| | |
| | | |
| | | private void createTransactionList(Long produceId, List<MesWmProductProduceLineDO> lines) { |
| | | for (MesWmProductProduceLineDO line : lines) { |
| | | if (MesWmQualityStatusEnum.FAIL.getStatus().equals(line.getQualityStatus())) { |
| | | // 不合格产出保留记录,交由不合格品处理,不生成合格库存流水。 |
| | | continue; |
| | | } |
| | | if (!MesWmQualityStatusEnum.PASS.getStatus().equals(line.getQualityStatus())) { |
| | | throw exception(WM_PRODUCT_PRODUCE_QUALITY_PENDING); |
| | | } |
| | | // 1. 校验每行明细数量之和等于行数量 |
| | | List<MesWmProductProduceDetailDO> details = productProduceDetailService.getProductProduceDetailListByLineId( |
| | | line.getId()); |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MesWmProductProduceDO generateProductProduce(MesProFeedbackDO feedback, boolean checkFlag, |
| | | MesProFeedbackApproveReqVO approveReqVO) { |
| | | if (!checkFlag) throw exception(WM_PRODUCT_PRODUCE_QUALITY_PENDING); |
| | | // 0. 查询关联的工单(用于获取 clientId 等信息) |
| | | MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(feedback.getWorkOrderId()); |
| | | |
| | |
| | | // 2. 获取或生成批次(审批请求中的批次属性优先) |
| | | MesWmBatchGenerateReqVO batchReqVO = new MesWmBatchGenerateReqVO() |
| | | .setItemId(feedback.getItemId()) |
| | | .setReelNo(workOrder != null ? workOrder.getReelNo() : null) |
| | | .setProduceDate(LocalDate.now().atStartOfDay()) // 截断到当天零点,确保同一天的报工生成相同批次号 |
| | | .setExpireDate(feedback.getExpireDate()) |
| | | .setWorkOrderId(feedback.getWorkOrderId()) |
| | |
| | | Long batchId = batch != null ? batch.getId() : null; |
| | | String batchCode = batch != null ? batch.getCode() : null; |
| | | |
| | | WarehouseTarget outputTarget = resolveOutputTarget(feedback.getWorkOrderId(), feedback.getProcessId(), feedback.getItemId()); |
| | | |
| | | // 3. 根据是否需要检验分支处理 |
| | | if (checkFlag) { |
| | | // 3.1 需要检验:创建一条行(质量状态=待检验),不生成明细 |
| | | MesWmProductProduceLineDO line = buildProduceLine(produce, feedback, batchId, batchCode, |
| | | feedback.getFeedbackQuantity(), MesWmQualityStatusEnum.PENDING.getStatus()); |
| | | productProduceLineService.createProductProduceLine(line); |
| | | // 注意:checkFlag=true 时不生成明细行,等 IPQC 检验完成后由 splitPendingAndFinishProduce 按质量结果拆行+生成明细 |
| | | } else { |
| | | // 3.2 无需检验:按合格品/不合格品各生成一行 + 明细 |
| | | BigDecimal qualifiedQty = ObjectUtil.defaultIfNull(feedback.getQualifiedQuantity(), BigDecimal.ZERO); |
| | | BigDecimal unqualifiedQty = ObjectUtil.defaultIfNull(feedback.getUnqualifiedQuantity(), BigDecimal.ZERO); |
| | | // 3.2.0 兜底:合格/不良数量都未填写时(报工只填报工数量),默认整单为合格品 |
| | | if (qualifiedQty.compareTo(BigDecimal.ZERO) <= 0 && unqualifiedQty.compareTo(BigDecimal.ZERO) <= 0) { |
| | | qualifiedQty = feedback.getFeedbackQuantity(); |
| | | } |
| | | // 3.2.1 不合格品行 + 明细 |
| | | if (unqualifiedQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | MesWmProductProduceLineDO unqualifiedLine = buildProduceLine(produce, feedback, batchId, batchCode, |
| | | unqualifiedQty, MesWmQualityStatusEnum.FAIL.getStatus()); |
| | | productProduceLineService.createProductProduceLine(unqualifiedLine); |
| | | MesWmProductProduceDetailDO unqualifiedDetail = buildProduceDetail(produce, feedback, batchId, batchCode, |
| | | unqualifiedLine.getId(), unqualifiedQty, |
| | | outputTarget.warehouseId(), outputTarget.locationId(), outputTarget.areaId()); |
| | | productProduceDetailService.createProductProduceDetail(unqualifiedDetail); |
| | | } |
| | | // 3.2.2 合格品行 + 明细 |
| | | if (qualifiedQty.compareTo(BigDecimal.ZERO) > 0) { |
| | | MesWmProductProduceLineDO qualifiedLine = buildProduceLine(produce, feedback, batchId, batchCode, |
| | | qualifiedQty, MesWmQualityStatusEnum.PASS.getStatus()); |
| | | productProduceLineService.createProductProduceLine(qualifiedLine); |
| | | MesWmProductProduceDetailDO qualifiedDetail = buildProduceDetail(produce, feedback, batchId, batchCode, |
| | | qualifiedLine.getId(), qualifiedQty, |
| | | outputTarget.warehouseId(), outputTarget.locationId(), outputTarget.areaId()); |
| | | productProduceDetailService.createProductProduceDetail(qualifiedDetail); |
| | | } |
| | | } |
| | | // 新报工产出统一待检,历史不检验即入库分支已移除。 |
| | | MesWmProductProduceLineDO line = buildProduceLine(produce, feedback, batchId, batchCode, |
| | | feedback.getFeedbackQuantity(), MesWmQualityStatusEnum.PENDING.getStatus(), |
| | | workOrder != null ? workOrder.getReelNo() : null); |
| | | productProduceLineService.createProductProduceLine(line); |
| | | return produce; |
| | | } |
| | | |
| | | private MesWmProductProduceLineDO buildProduceLine(MesWmProductProduceDO produce, MesProFeedbackDO feedback, |
| | | Long batchId, String batchCode, |
| | | BigDecimal quantity, Integer qualityStatus) { |
| | | BigDecimal quantity, Integer qualityStatus, String reelNo) { |
| | | return MesWmProductProduceLineDO.builder() |
| | | .produceId(produce.getId()).feedbackId(feedback.getId()) |
| | | .itemId(feedback.getItemId()).quantity(quantity) |
| | | .batchId(batchId).batchCode(batchCode) |
| | | .batchId(batchId).batchCode(batchCode).reelNo(reelNo) |
| | | .expireDate(feedback.getExpireDate()).lotNumber(feedback.getLotNumber()) |
| | | .qualityStatus(qualityStatus) |
| | | .build(); |
| | | } |
| | | |
| | | private MesWmProductProduceDetailDO buildProduceDetail(MesWmProductProduceDO produce, MesProFeedbackDO feedback, |
| | | Long batchId, String batchCode, |
| | | Long lineId, BigDecimal quantity, |
| | | Long warehouseId, Long locationId, Long areaId) { |
| | | return MesWmProductProduceDetailDO.builder() |
| | | .produceId(produce.getId()).lineId(lineId) |
| | | .itemId(feedback.getItemId()).quantity(quantity) |
| | | .batchId(batchId).batchCode(batchCode) |
| | | .warehouseId(warehouseId).locationId(locationId).areaId(areaId) |
| | | .build(); |
| | | } |
| | | |
| | |
| | | } |
| | | // 2. 通过 sourceLineId 直接定位待检验行 |
| | | MesWmProductProduceLineDO pendingLine = productProduceLineService.validateProductProduceLineExists(sourceLineId); |
| | | if (!ObjUtil.equal(pendingLine.getProduceId(), produce.getId()) |
| | | || !ObjUtil.equal(pendingLine.getFeedbackId(), feedbackId) |
| | | || !ObjUtil.equal(pendingLine.getQualityStatus(), MesWmQualityStatusEnum.PENDING.getStatus()) |
| | | || qualifiedQty == null || unqualifiedQty == null || pendingLine.getQuantity() == null |
| | | || qualifiedQty.signum() < 0 || unqualifiedQty.signum() < 0 |
| | | || qualifiedQty.add(unqualifiedQty).compareTo(pendingLine.getQuantity()) != 0) { |
| | | throw exception(WM_PRODUCT_PRODUCE_INSPECTION_INVALID); |
| | | } |
| | | WarehouseTarget outputTarget = resolveOutputTarget(produce.getWorkOrderId(), produce.getProcessId(), pendingLine.getItemId()); |
| | | |
| | | // 3A. 情况一:存在不合格品数量,需要拆分行 |
| | |
| | | .produceId(produce.getId()).feedbackId(feedbackId) |
| | | .itemId(pendingLine.getItemId()).quantity(unqualifiedQty) |
| | | .batchId(pendingLine.getBatchId()).batchCode(pendingLine.getBatchCode()) |
| | | .expireDate(pendingLine.getExpireDate()).lotNumber(pendingLine.getLotNumber()) |
| | | .expireDate(pendingLine.getExpireDate()).lotNumber(pendingLine.getLotNumber()).reelNo(pendingLine.getReelNo()) |
| | | .qualityStatus(MesWmQualityStatusEnum.FAIL.getStatus()) |
| | | .build(); |
| | | productProduceLineService.createProductProduceLine(unqualifiedLine); |
| | | productProduceDetailService.createProductProduceDetail(MesWmProductProduceDetailDO.builder() |
| | | .produceId(produce.getId()).lineId(unqualifiedLine.getId()) |
| | | .itemId(pendingLine.getItemId()).quantity(unqualifiedQty) |
| | | .batchId(pendingLine.getBatchId()).batchCode(pendingLine.getBatchCode()) |
| | | .batchId(pendingLine.getBatchId()).batchCode(pendingLine.getBatchCode()).reelNo(pendingLine.getReelNo()) |
| | | .warehouseId(outputTarget.warehouseId()).locationId(outputTarget.locationId()).areaId(outputTarget.areaId()) |
| | | .build()); |
| | | // 3A.2 合格品:复用原待检行,更新数量和状态 + 明细 |
| | |
| | | productProduceDetailService.createProductProduceDetail(MesWmProductProduceDetailDO.builder() |
| | | .produceId(produce.getId()).lineId(pendingLine.getId()) |
| | | .itemId(pendingLine.getItemId()).quantity(qualifiedQty) |
| | | .batchId(pendingLine.getBatchId()).batchCode(pendingLine.getBatchCode()) |
| | | .batchId(pendingLine.getBatchId()).batchCode(pendingLine.getBatchCode()).reelNo(pendingLine.getReelNo()) |
| | | .warehouseId(outputTarget.warehouseId()).locationId(outputTarget.locationId()).areaId(outputTarget.areaId()) |
| | | .build()); |
| | | } |
| | |
| | | productProduceDetailService.createProductProduceDetail(MesWmProductProduceDetailDO.builder() |
| | | .produceId(produce.getId()).lineId(pendingLine.getId()) |
| | | .itemId(pendingLine.getItemId()).quantity(pendingLine.getQuantity()) |
| | | .batchId(pendingLine.getBatchId()).batchCode(pendingLine.getBatchCode()) |
| | | .batchId(pendingLine.getBatchId()).batchCode(pendingLine.getBatchCode()).reelNo(pendingLine.getReelNo()) |
| | | .warehouseId(outputTarget.warehouseId()).locationId(outputTarget.locationId()).areaId(outputTarget.areaId()) |
| | | .build()); |
| | | } |