From f4c288c55d08c04cd026508b358beebfcdce5fc2 Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期五, 22 五月 2026 09:29:09 +0800
Subject: [PATCH] feat(product): 添加产品型号向下复制功能并优化生产报工重量计算 - 在ProductController中新增downCopy接口实现产品型号批量复制功能 - 将ProductionProductMainDto中的bomInputQty字段重命名为inputWeight - 在ProductionProductMainServiceImpl中添加JSON解析逻辑支持从otherData中提取投入重量 - 新增resolveInputWeight、findParameterValue、findFieldValue等工具方法处理复杂参数解析 - 为ProductModelDto添加targetProductId字段用于指定复制目标 - 修复销售台账按调度员ID和姓名分组的SQL查询问题 - 优化库存服务中剩余数量计算的空值处理逻辑 - 完善生产投料数量为空时的默认值处理机制
---
src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 204 insertions(+), 4 deletions(-)
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java
index 2554b5e..b91ba31 100644
--- a/src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.pojo.Product;
@@ -15,13 +16,12 @@
import com.ruoyi.production.dto.BomImportDto;
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductStructureDto;
-import com.ruoyi.production.mapper.ProductBomMapper;
-import com.ruoyi.production.pojo.ProductBom;
-import com.ruoyi.production.pojo.ProductProcess;
-import com.ruoyi.production.pojo.ProductStructure;
+import com.ruoyi.production.mapper.*;
+import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProductBomService;
import com.ruoyi.production.service.ProductProcessService;
import com.ruoyi.production.service.ProductStructureService;
+import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -59,6 +59,18 @@
@Autowired
private ProductProcessService productProcessService;
+ @Autowired
+ private ProductStructureMapper productStructureMapper;
+
+ @Autowired
+ private ProductOrderMapper productOrderMapper;
+
+ @Autowired
+ private ProductProcessRouteMapper productProcessRouteMapper;
+
+ @Autowired
+ private ProcessRouteMapper processRouteMapper;
+
@Override
public IPage<ProductBomDto> listPage(Page page, ProductBomDto productBomDto) {
return productBomMapper.listPage(page, productBomDto);
@@ -99,6 +111,194 @@
@Override
@Transactional(rollbackFor = Exception.class)
+ public AjaxResult update(ProductBom productBom) {
+ // 鏌ヨ鍑轰骇鍝佹ā鍨嬩俊鎭�
+ if (productBom.getProductModelId() == null) {
+ throw new ServiceException("璇烽�夋嫨浜у搧妯″瀷");
+ }
+
+ ProductBom oldBom = productBomMapper.selectById(productBom.getId());
+ // 濡傛灉瑙勬牸鏀瑰彉锛屽叧鑱旂殑鐢熶骇璁㈠崟濡傛灉璁㈠崟瀹屾垚鏁伴噺>0锛屽垯涓嶈鏀筨om锛涘惁鍒欏垹闄や箣鍓嶅叧鑱旂殑浜у搧缁撴瀯, 淇敼鍏宠仈璁㈠崟鐨勪骇鍝佷俊鎭�
+ if (!oldBom.getProductModelId().equals(productBom.getProductModelId())) {
+ ProductModel productModel = productModelService.getById(productBom.getProductModelId());
+ if (productModel == null) {
+ throw new ServiceException("閫夋嫨鐨勪骇鍝佹ā鍨嬩笉瀛樺湪");
+ }
+
+ // 鍏宠仈鐨勭敓浜ц鍗曞鏋滆鍗曞畬鎴愭暟閲�>0锛屽垯涓嶈鏀筨om
+ // 鍏堟煡璇笌璇OM鍏宠仈鐨勫伐鑹鸿矾绾�
+ List<ProductProcessRoute> productProcessRoutes = productProcessRouteMapper.selectList(new LambdaQueryWrapper<ProductProcessRoute>()
+ .eq(ProductProcessRoute::getBomId, oldBom.getId()));
+
+ // 妫�鏌ユ槸鍚︽湁鍏宠仈鐨勫伐鑹鸿矾绾�
+ if (!productProcessRoutes.isEmpty()) {
+ // 鎻愬彇宸ヨ壓璺嚎鍏宠仈鐨勭敓浜ц鍗旾D
+ List<Long> orderIds = productProcessRoutes.stream()
+ .map(ProductProcessRoute::getProductOrderId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ // 鏌ヨ鍏宠仈鐨勭敓浜ц鍗�
+ if (!orderIds.isEmpty()) {
+ List<ProductOrder> productOrders = productOrderMapper.selectList(new LambdaQueryWrapper<ProductOrder>()
+ .in(ProductOrder::getId, orderIds));
+
+ // 妫�鏌ヨ鍗曞畬鎴愭暟閲�
+ for (ProductOrder order : productOrders) {
+ if (order.getCompleteQuantity() != null && order.getCompleteQuantity().compareTo(BigDecimal.ZERO) > 0) {
+ throw new ServiceException("璇OM宸插叧鑱旂敓浜ц鍗曚笖鏈夊畬鎴愭暟閲忥紝鏃犳硶淇敼");
+ } else {
+ // 淇敼鍏宠仈璁㈠崟鐨勪骇鍝佷俊鎭�
+ order.setProductModelId(productBom.getProductModelId());
+ productOrderMapper.updateById(order);
+ }
+ }
+ }
+
+ // 淇敼鍏宠仈浜у搧宸ヨ壓璺嚎鐨勪骇鍝佷俊鎭�
+ for (ProductProcessRoute route : productProcessRoutes) {
+ route.setProductModelId(productBom.getProductModelId());
+ productProcessRouteMapper.updateById(route);
+ }
+
+ // 鏌ヨ鍏宠仈鐨勫伐鑹鸿矾绾�
+ List<ProcessRoute> processRoutes = processRouteMapper.selectList(new LambdaQueryWrapper<ProcessRoute>()
+ .eq(ProcessRoute::getBomId, oldBom.getId()));
+ if (!processRoutes.isEmpty()) {
+ // 淇敼鍏宠仈宸ヨ壓璺嚎鐨勪骇鍝佷俊鎭�
+ for (ProcessRoute route : processRoutes) {
+ route.setProductModelId(productBom.getProductModelId());
+ processRouteMapper.updateById(route);
+ }
+ }
+ }
+
+ // 鍒犻櫎涔嬪墠鍏宠仈鐨勪骇鍝佺粨鏋�
+ productStructureMapper.delete(new LambdaQueryWrapper<ProductStructure>().eq(ProductStructure::getBomId, productBom.getId()));
+
+ // 鍏宠仈鏂扮殑浜у搧缁撴瀯
+ ProductStructure productStructure = new ProductStructure();
+ productStructure.setProductModelId(productBom.getProductModelId());
+ productStructure.setUnit(productModel.getUnit());
+ productStructure.setUnitQuantity(BigDecimal.valueOf(1));
+ productStructure.setBomId(productBom.getId());
+ productStructureService.save(productStructure);
+ }
+ productBomMapper.updateById(productBom);
+ return AjaxResult.success();
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public AjaxResult copy(ProductBomDto productBom) {
+ Long copyId = productBom.getCopyId();
+ if (copyId == null) {
+ throw new ServiceException("澶嶅埗婧怋OM ID涓嶈兘涓虹┖");
+ }
+ ProductBom sourceBom = productBomMapper.selectById(copyId);
+ if (sourceBom == null) {
+ throw new ServiceException("澶嶅埗婧怋OM涓嶅瓨鍦�");
+ }
+
+
+ ProductBom newBom = getProductBom(productBom, sourceBom);
+ productBomMapper.insert(newBom);
+ newBom.setBomNo("BM." + String.format("%05d", newBom.getId()));
+ productBomMapper.updateById(newBom);
+
+
+
+ ProductModel productModel = productModelService.getById(newBom.getProductModelId());
+ if (productModel == null) {
+ throw new ServiceException("閫夋嫨鐨勪骇鍝佹ā鍨嬩笉瀛樺湪");
+ }
+
+ ProductStructure newRoot = getProductStructure(newBom, productModel);
+ productStructureService.save(newRoot);
+ List<ProductStructure> sourceStructures = productStructureMapper.selectList(
+ Wrappers.<ProductStructure>lambdaQuery()
+ .eq(ProductStructure::getBomId, copyId.intValue()));
+ if (sourceStructures == null || sourceStructures.isEmpty()) {
+ return AjaxResult.success();
+ }
+
+ ProductStructure oldRoot = sourceStructures.stream()
+ .filter(s -> s.getParentId() == null)
+ .findFirst().orElse(new ProductStructure());
+
+ List<ProductStructure> children = sourceStructures
+ .stream()
+ .filter(s -> !s.getId().equals(oldRoot.getId()))
+ .collect(Collectors.toList());
+
+ Map<Long, Long> oldNewIdMap = new HashMap<>();
+
+ oldNewIdMap.put(oldRoot.getId(), newRoot.getId());
+
+ List<ProductStructure> insertList = children
+ .stream()
+ .map(item -> getProductStructures(item, newBom))
+ .collect(Collectors.toList());
+
+ productStructureService.saveBatch(insertList);
+
+ for (int i = 0; i < children.size(); i++) {
+ oldNewIdMap.put(
+ children.get(i).getId(),
+ insertList.get(i).getId()
+ );
+ }
+
+ List<ProductStructure> updateList = new ArrayList<>();
+ for (int i = 0; i < children.size(); i++) {
+ ProductStructure source = children.get(i);
+ ProductStructure inserted = insertList.get(i);
+ Long newParentId = oldNewIdMap.get(source.getParentId());
+ if (newParentId != null) {
+ inserted.setParentId(newParentId);
+ updateList.add(inserted);
+ }
+ }
+ if (!updateList.isEmpty()) {
+ productStructureService.updateBatchById(updateList);
+ }
+
+ return AjaxResult.success();
+ }
+
+ @NotNull
+ private static ProductStructure getProductStructures(ProductStructure item, ProductBom newBom) {
+ ProductStructure copy = new ProductStructure();
+ copy.setProductModelId(item.getProductModelId());
+ copy.setProcessId(item.getProcessId());
+ copy.setUnitQuantity(item.getUnitQuantity());
+ copy.setDemandedQuantity(item.getDemandedQuantity());
+ copy.setUnit(item.getUnit());
+ copy.setBomId(newBom.getId());
+ return copy;
+ }
+
+ @NotNull
+ private static ProductStructure getProductStructure(ProductBom newBom, ProductModel productModel) {
+ ProductStructure newRoot = new ProductStructure();
+ newRoot.setProductModelId(newBom.getProductModelId());
+ newRoot.setUnitQuantity(BigDecimal.valueOf(1));
+ newRoot.setUnit(productModel.getUnit());
+ newRoot.setBomId(newBom.getId());
+ return newRoot;
+ }
+
+ @NotNull
+ private static ProductBom getProductBom(ProductBomDto productBom, ProductBom sourceBom) {
+ ProductBom newBom = new ProductBom();
+ newBom.setProductModelId(productBom.getProductModelId() != null ? productBom.getProductModelId() : sourceBom.getProductModelId());
+ newBom.setRemark(productBom.getRemark());
+ newBom.setVersion(productBom.getVersion() != null ? productBom.getVersion() : sourceBom.getVersion());
+ return newBom;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
public AjaxResult uploadBom(MultipartFile file) {
ExcelUtil<BomImportDto> util = new ExcelUtil<>(BomImportDto.class);
List<BomImportDto> list;
--
Gitblit v1.9.3