| | |
| | | import com.ruoyi.common.exception.ServiceException; |
| | | import com.ruoyi.common.utils.bean.BeanUtils; |
| | | import com.ruoyi.procurementrecord.utils.StockUtils; |
| | | import com.ruoyi.production.bean.dto.ProductStructureDto; |
| | | import com.ruoyi.production.bean.dto.ProductionProductMainDto; |
| | | import com.ruoyi.production.enums.ProductOrderStatusEnum; |
| | | import com.ruoyi.production.mapper.*; |
| | |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedHashSet; |
| | |
| | | @AllArgsConstructor |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public class ProductionProductMainServiceImpl extends ServiceImpl<ProductionProductMainMapper, ProductionProductMain> implements ProductionProductMainService { |
| | | |
| | | /** |
| | | * ç产æ¥å·¥å¤§ç±»ï¼åªåºåå°æç´/大æç´/è´æ¯ï¼ä¸ååºåé¶ä»¶ã |
| | | * key为å
¥åºè§èå¼ï¼value为产ååç§°å¹é
å«åï¼ç°åºæ°æ®è´æ¯åä½âè´å¸âï¼ã |
| | | */ |
| | | private static final Map<String, List<String>> MAJOR_CATEGORY_PATTERNS = new LinkedHashMap<>() {{ |
| | | put("å°æç´", List.of("å°æç´")); |
| | | put("大æç´", List.of("大æç´")); |
| | | put("è´æ¯", List.of("è´æ¯", "è´å¸")); |
| | | }}; |
| | | |
| | | private final ProductionProductMainMapper productionProductMainMapper; |
| | | private final SysUserMapper userMapper; |
| | |
| | | private final ProductionAccountMapper productionAccountMapper; |
| | | private final ProductionOperationTaskMapper productionOperationTaskMapper; |
| | | private final ProductionOrderMapper productionOrderMapper; |
| | | private final ProductionOrderBomMapper productionOrderBomMapper; |
| | | private final ProductionBomStructureMapper productionBomStructureMapper; |
| | | private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper; |
| | | private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper; |
| | | private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper; |
| | |
| | | throw new ServiceException("产åè§æ ¼ä¸åå¨"); |
| | | } |
| | | |
| | | // æ¥å·¥å®ææ¶å¯¹è®¡æ°çé¶ä»¶ååºåï¼åæ ¼/轻微è¿å·¥/严éè¿å·¥/æ¥åºåç±»æ°éã |
| | | BigDecimal qualifiedQty = defaultDecimal(dto.getQuantity()); |
| | | BigDecimal reworkMinorQty = defaultDecimal(dto.getReworkMinorQty()); |
| | | BigDecimal reworkMajorQty = defaultDecimal(dto.getReworkMajorQty()); |
| | | BigDecimal scrapQtyInput = defaultDecimal(dto.getScrapQty()); |
| | | if (qualifiedQty.compareTo(BigDecimal.ZERO) < 0 |
| | | || reworkMinorQty.compareTo(BigDecimal.ZERO) < 0 |
| | | || reworkMajorQty.compareTo(BigDecimal.ZERO) < 0 |
| | | || scrapQtyInput.compareTo(BigDecimal.ZERO) < 0) { |
| | | throw new ServiceException("æ¥å·¥æ°éä¸è½ä¸ºè´æ°"); |
| | | } |
| | | if (qualifiedQty.add(reworkMinorQty).add(reworkMajorQty).add(scrapQtyInput).compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw new ServiceException("请æåæ ¼/轻微è¿å·¥/严éè¿å·¥/æ¥åºå类填åé¶ä»¶æ°é"); |
| | | } |
| | | |
| | | ProductionProductMain productionProductMain = new ProductionProductMain(); |
| | | productionProductMain.setProductNo(generateProductNo()); |
| | | productionProductMain.setMajorCategory(resolveMajorCategory(productModel)); |
| | | productionProductMain.setUserId(user == null ? dto.getUserId() : user.getUserId()); |
| | | productionProductMain.setUserName(user == null ? dto.getUserName() : user.getNickName()); |
| | | productionProductMain.setProductionOperationTaskId(taskId); |
| | | productionProductMain.setStatus(0); |
| | | productionProductMain.setReportType(dto.getReportType() == null ? 0 : dto.getReportType()); |
| | | productionProductMain.setReportType(dto.getReportType() != null |
| | | ? dto.getReportType() |
| | | : deriveReportType(qualifiedQty, reworkMinorQty, reworkMajorQty, scrapQtyInput)); |
| | | productionProductMain.setAuditStatus(dto.getAuditStatus() == null ? 0 : dto.getAuditStatus()); |
| | | productionProductMain.setAuditRemark(dto.getAuditRemark()); |
| | | productionProductMain.setWorkHour(dto.getWorkHour()); |
| | |
| | | syncOperationParamInputValue(dto, routingOperation.getId(), productionProductMain.getId()); |
| | | createReportApprovalInstance(productionProductMain); |
| | | |
| | | List<ProductStructureDto> productStructureDtos = resolveInputStructures( |
| | | productionOrder.getId(), routingOperation, productModel.getId()); |
| | | // å¦ææ²¡æbomåèç¹äºï¼é£ä¹æå
¥å°±æ¯ä»æ¬èº« |
| | | if (productStructureDtos.isEmpty()) { |
| | | ProductStructureDto fallbackInput = new ProductStructureDto(); |
| | | fallbackInput.setProductModelId(productModel.getId()); |
| | | fallbackInput.setUnitQuantity(BigDecimal.ONE); |
| | | productStructureDtos.add(fallbackInput); |
| | | } |
| | | for (ProductStructureDto item : productStructureDtos) { |
| | | // å½åå®ç°æå·¥åºæåç´æ¥ä½ä¸ºæå
¥ï¼åç»è¥æ¥å
¥é¢æè®°å½å¯å¨è¿éæ¿æ¢æ¥æºã |
| | | ProductionProductInput productionProductInput = new ProductionProductInput(); |
| | | productionProductInput.setProductionProductMainId(productionProductMain.getId()); |
| | | productionProductInput.setProductModelId(item.getProductModelId()); |
| | | productionProductInput.setInputQuantity(item.getUnitQuantity().multiply(defaultDecimal(dto.getQuantity()))); |
| | | productionProductInput.setQuantity(productionProductInput.getInputQuantity()); |
| | | productionProductInputMapper.insert(productionProductInput); |
| | | } |
| | | // 鿱忴ï¼ç产æ¥å·¥ä¸åæé¶ä»¶ï¼BOMç»æï¼æåæå
¥ï¼æå
¥å³æ¬æ¬¡æ¥å·¥çäº§åæ¬èº«ï¼æå¤§ç±»ç»è®¡ã |
| | | ProductionProductInput productionProductInput = new ProductionProductInput(); |
| | | productionProductInput.setProductionProductMainId(productionProductMain.getId()); |
| | | productionProductInput.setProductModelId(productModel.getId()); |
| | | productionProductInput.setInputQuantity(qualifiedQty); |
| | | productionProductInput.setQuantity(qualifiedQty); |
| | | productionProductInputMapper.insert(productionProductInput); |
| | | |
| | | ProductionProductOutput productionProductOutput = new ProductionProductOutput(); |
| | | productionProductOutput.setProductionProductMainId(productionProductMain.getId()); |
| | | productionProductOutput.setProductModelId(productModel.getId()); |
| | | productionProductOutput.setQuantity(defaultDecimal(dto.getQuantity())); |
| | | productionProductOutput.setScrapQty(defaultDecimal(dto.getScrapQty())); |
| | | productionProductOutput.setReworkMinorQty(reworkMinorQty); |
| | | productionProductOutput.setReworkMajorQty(reworkMajorQty); |
| | | productionProductOutputMapper.insert(productionProductOutput); |
| | | BigDecimal reportQty = defaultDecimal(productionProductOutput.getQuantity()); |
| | | BigDecimal scrapQty = defaultDecimal(productionProductOutput.getScrapQty()); |
| | |
| | | productionProductMain.getId(), |
| | | qualifiedBatchNo); |
| | | } |
| | | // åºååºçè¿å·¥é¶ä»¶çæä¸åæ ¼åå¾
å¤çåï¼è¿å
¥ä¸åæ ¼å管ççæ¥å·¥å¤çéç¯ã |
| | | createReworkUnqualifiedRecords(productionProductMain, productModel, reworkMinorQty, reworkMajorQty); |
| | | return true; |
| | | } |
| | | |
| | | private Integer deriveReportType(BigDecimal qualifiedQty, BigDecimal reworkMinorQty, |
| | | BigDecimal reworkMajorQty, BigDecimal scrapQty) { |
| | | if (qualifiedQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | return 0; |
| | | } |
| | | if (reworkMinorQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | return 1; |
| | | } |
| | | if (reworkMajorQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | return 2; |
| | | } |
| | | if (scrapQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | return 3; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | private void createReworkUnqualifiedRecords(ProductionProductMain productionProductMain, |
| | | ProductModel productModel, |
| | | BigDecimal reworkMinorQty, |
| | | BigDecimal reworkMajorQty) { |
| | | if (reworkMinorQty.compareTo(BigDecimal.ZERO) <= 0 && reworkMajorQty.compareTo(BigDecimal.ZERO) <= 0) { |
| | | return; |
| | | } |
| | | Product product = productMapper.selectById(productModel.getProductId()); |
| | | if (product == null) { |
| | | throw new ServiceException("产åä¸åå¨ï¼æ æ³çææ¥å·¥è¿å·¥å¾
å¤çå"); |
| | | } |
| | | if (reworkMinorQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | insertReworkUnqualified(productionProductMain, product, productModel, reworkMinorQty, 0); |
| | | } |
| | | if (reworkMajorQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | insertReworkUnqualified(productionProductMain, product, productModel, reworkMajorQty, 1); |
| | | } |
| | | } |
| | | |
| | | private void insertReworkUnqualified(ProductionProductMain productionProductMain, |
| | | Product product, |
| | | ProductModel productModel, |
| | | BigDecimal quantity, |
| | | int dealType) { |
| | | QualityUnqualified qualityUnqualified = new QualityUnqualified(); |
| | | qualityUnqualified.setInspectType(1); |
| | | qualityUnqualified.setInspectState(0); |
| | | qualityUnqualified.setCheckTime(new Date()); |
| | | qualityUnqualified.setCheckName(productionProductMain.getUserName()); |
| | | qualityUnqualified.setProductId(product.getId()); |
| | | qualityUnqualified.setProductName(product.getProductName()); |
| | | qualityUnqualified.setModel(productModel.getModel()); |
| | | qualityUnqualified.setUnit(productModel.getUnit()); |
| | | qualityUnqualified.setQuantity(quantity); |
| | | qualityUnqualified.setProductModelId(productModel.getId()); |
| | | qualityUnqualified.setProductMainId(productionProductMain.getId()); |
| | | qualityUnqualified.setDefectivePhenomena("ç产æ¥å·¥ã" + productionProductMain.getProductNo() |
| | | + "ã计æ°åºå-" + (dealType == 0 ? "轻微è¿å·¥" : "严éè¿å·¥")); |
| | | qualityUnqualified.setDealType(dealType); |
| | | qualityUnqualified.setDealResult("æ¥å·¥"); |
| | | qualityUnqualifiedMapper.insert(qualityUnqualified); |
| | | } |
| | | |
| | | private void createReportApprovalInstance(ProductionProductMain productionProductMain) { |
| | |
| | | BigDecimal schedulingNum = task == null ? BigDecimal.ZERO : defaultDecimal(task.getPlanQuantity()); |
| | | BigDecimal finishedNum = output == null ? BigDecimal.ZERO : defaultDecimal(output.getQuantity()); |
| | | BigDecimal scrapQty = output == null ? BigDecimal.ZERO : defaultDecimal(output.getScrapQty()); |
| | | BigDecimal reworkMinorNum = output == null ? BigDecimal.ZERO : defaultDecimal(output.getReworkMinorQty()); |
| | | BigDecimal reworkMajorNum = output == null ? BigDecimal.ZERO : defaultDecimal(output.getReworkMajorQty()); |
| | | BigDecimal pendingNum = schedulingNum.subtract(finishedNum); |
| | | if (pendingNum.compareTo(BigDecimal.ZERO) < 0) { |
| | | pendingNum = BigDecimal.ZERO; |
| | |
| | | fields.add(buildReportField("workOrderNo", "å·¥åç¼å·", "text", resolveWorkOrderNo(productionProductMain.getProductionOperationTaskId()))); |
| | | fields.add(buildReportField("schedulingNum", "æäº§æ°é", "number", schedulingNum)); |
| | | fields.add(buildReportField("pendingNum", "å¾
ç产æ°é", "number", pendingNum)); |
| | | fields.add(buildReportField("finishedNum", "çäº§åæ ¼æ°é", "number", finishedNum)); |
| | | fields.add(buildReportField("finishedNum", "åæ ¼æ°é", "number", finishedNum)); |
| | | fields.add(buildReportField("reworkMinorQty", "轻微è¿å·¥æ°é", "number", reworkMinorNum)); |
| | | fields.add(buildReportField("reworkMajorQty", "严éè¿å·¥æ°é", "number", reworkMajorNum)); |
| | | fields.add(buildReportField("scrapQty", "æ¥åºæ°é", "number", scrapQty)); |
| | | fields.add(buildReportField("reportType", "æ¥å·¥ç»æ", "select", resolveReportTypeLabel(productionProductMain.getReportType()))); |
| | | fields.add(buildReportField("workHour", "å·¥æ¶", "number", productionProductMain.getWorkHour())); |
| | |
| | | formPayload.put("pendingNum", pendingNum); |
| | | formPayload.put("finishedNum", finishedNum); |
| | | formPayload.put("scrapQty", scrapQty); |
| | | formPayload.put("reworkMinorQty", reworkMinorNum); |
| | | formPayload.put("reworkMajorQty", reworkMajorNum); |
| | | formPayload.put("reportType", resolveReportTypeLabel(productionProductMain.getReportType())); |
| | | formPayload.put("workHour", productionProductMain.getWorkHour()); |
| | | formPayload.put("auditStatus", resolveAuditStatusLabel(productionProductMain.getAuditStatus())); |
| | |
| | | return target; |
| | | } |
| | | |
| | | private List<ProductStructureDto> resolveInputStructures(Long productionOrderId, |
| | | ProductionOrderRoutingOperation routingOperation, |
| | | Long outputProductModelId) { |
| | | if (productionOrderId == null || routingOperation == null || routingOperation.getTechnologyOperationId() == null) { |
| | | return new ArrayList<>(); |
| | | /** |
| | | * éæ±ï¼ç产æ¥å·¥åªåºå产å大类ï¼å°æç´/大æç´/è´æ¯ï¼ï¼ä¸ååºåé¶ä»¶ã |
| | | * ä»äº§åºäº§åèªèº«åç§°å¼å§æ²¿äº§åæ åä¸åå
³é®åå¹é
ï¼å½ä¸å³å对åºè§èå¤§ç±»ï¼æªå½ä¸è¿å nullã |
| | | * äº§åæ é¡¶å±ä¸ºâæå/åæå/åæâçåºååç±»ï¼ä¸è½ç´æ¥å½ä½å¤§ç±»ï¼å æ¤å¿
é¡»èªåºåä¸å第ä¸ä¸ªå½ä¸çå±çº§ã |
| | | */ |
| | | private String resolveMajorCategory(ProductModel productModel) { |
| | | if (productModel == null || productModel.getProductId() == null) { |
| | | return null; |
| | | } |
| | | ProductionOrderBom orderBom = productionOrderBomMapper.selectOne( |
| | | Wrappers.<ProductionOrderBom>lambdaQuery() |
| | | .eq(ProductionOrderBom::getProductionOrderId, productionOrderId) |
| | | .orderByDesc(ProductionOrderBom::getId) |
| | | .last("limit 1")); |
| | | if (orderBom == null || orderBom.getId() == null) { |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | List<ProductionBomStructure> bomNodeList = productionBomStructureMapper.selectList( |
| | | Wrappers.<ProductionBomStructure>lambdaQuery() |
| | | .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId()) |
| | | .orderByAsc(ProductionBomStructure::getId)); |
| | | if (bomNodeList.isEmpty()) { |
| | | return new ArrayList<>(); |
| | | } |
| | | |
| | | Map<Long, ProductionBomStructure> nodeMap = bomNodeList.stream() |
| | | .filter(item -> item != null && item.getId() != null) |
| | | .collect(Collectors.toMap(ProductionBomStructure::getId, item -> item, (left, right) -> left)); |
| | | Long currentOutputModelId = routingOperation.getProductModelId() != null |
| | | ? routingOperation.getProductModelId() |
| | | : outputProductModelId; |
| | | |
| | | Map<Long, BigDecimal> unitQtyByProductModel = new LinkedHashMap<>(); |
| | | for (ProductionBomStructure node : bomNodeList) { |
| | | if (node == null || node.getParentId() == null || node.getProductModelId() == null) { |
| | | continue; |
| | | Product product = productMapper.selectById(productModel.getProductId()); |
| | | Set<Long> visited = new LinkedHashSet<>(); |
| | | while (product != null && visited.add(product.getId())) { |
| | | String category = matchMajorCategory(product.getProductName()); |
| | | if (category != null) { |
| | | return category; |
| | | } |
| | | if (!Objects.equals(node.getTechnologyOperationId(), routingOperation.getTechnologyOperationId())) { |
| | | continue; |
| | | if (product.getParentId() == null || product.getParentId() == 0L) { |
| | | break; |
| | | } |
| | | ProductionBomStructure parent = nodeMap.get(node.getParentId()); |
| | | if (parent == null || !Objects.equals(parent.getProductModelId(), currentOutputModelId)) { |
| | | continue; |
| | | } |
| | | unitQtyByProductModel.merge(node.getProductModelId(), defaultDecimal(node.getUnitQuantity()), BigDecimal::add); |
| | | product = productMapper.selectById(product.getParentId()); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | List<ProductStructureDto> result = new ArrayList<>(); |
| | | for (Map.Entry<Long, BigDecimal> entry : unitQtyByProductModel.entrySet()) { |
| | | if (entry.getValue().compareTo(BigDecimal.ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | ProductStructureDto item = new ProductStructureDto(); |
| | | item.setProductModelId(entry.getKey()); |
| | | item.setUnitQuantity(entry.getValue()); |
| | | result.add(item); |
| | | static String matchMajorCategory(String productName) { |
| | | if (productName == null || productName.isEmpty()) { |
| | | return null; |
| | | } |
| | | return result; |
| | | // ç´ç/ç´å¥çé
ä»¶åç§°å¯è½å¸¦âè´å¸âçåæ ·ï¼å¦ SAè´å¸å¥ï¼ï¼æé¤åé¿å
误å½å¤§ç±»ã |
| | | if (productName.contains("ç´ç") || productName.contains("ç´å¥") || productName.contains("å¼ç")) { |
| | | return null; |
| | | } |
| | | for (Map.Entry<String, List<String>> entry : MAJOR_CATEGORY_PATTERNS.entrySet()) { |
| | | for (String alias : entry.getValue()) { |
| | | if (productName.contains(alias)) { |
| | | return entry.getKey(); |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private Boolean removeProductMainByProductionTask(ProductionProductMain productionProductMain) { |
| | |
| | | if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState() == 1) { |
| | | throw new ServiceException("è¯¥æ¡æ¥å·¥å·²ç»ä¸åæ ¼å¤çäºï¼ä¸å
许å é¤"); |
| | | } |
| | | } |
| | | // æ¥å·¥è®¡æ°åºåç´æ¥äº§ççè¿å·¥å¾
å¤çåï¼å·²å¤ççä¸å
许å 餿¥å·¥ï¼æªå¤çç鿥工ä¸å¹¶å é¤ã |
| | | List<QualityUnqualified> reworkUnqualifieds = qualityUnqualifiedMapper.selectList( |
| | | Wrappers.<QualityUnqualified>lambdaQuery() |
| | | .eq(QualityUnqualified::getProductMainId, productionProductMain.getId())); |
| | | if (reworkUnqualifieds.stream().anyMatch(q -> Integer.valueOf(1).equals(q.getInspectState()))) { |
| | | throw new ServiceException("è¯¥æ¡æ¥å·¥çè¿å·¥é¶ä»¶å·²åä¸åæ ¼å¤çï¼ä¸å
许å é¤"); |
| | | } |
| | | ProductionProductOutput productionProductOutput = productionProductOutputMapper.selectList( |
| | | Wrappers.<ProductionProductOutput>lambdaQuery() |
| | |
| | | } |
| | | } |
| | | |
| | | qualityUnqualifiedMapper.delete(new LambdaQueryWrapper<QualityUnqualified>() |
| | | .eq(QualityUnqualified::getProductMainId, productionProductMain.getId())); |
| | | qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>() |
| | | .eq(QualityInspect::getProductMainId, productionProductMain.getId())).forEach(q -> { |
| | | qualityInspectParamMapper.delete(new LambdaQueryWrapper<QualityInspectParam>() |