| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.feedback.MesProFeedbackDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderProcessDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDetailDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productproduce.MesWmProductProduceLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productproduce.MesWmProductProduceMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.feedback.MesProFeedbackMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductProduceStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; |
| | | import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderProcessService; |
| | | import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProductService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.productreceipt.MesWmProductReceiptService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService; |
| | |
| | | |
| | | @Resource |
| | | private MesWmProductProduceMapper productProduceMapper; |
| | | @Resource |
| | | private MesProFeedbackMapper feedbackMapper; |
| | | |
| | | @Resource |
| | | private MesWmProductProduceLineService productProduceLineService; |
| | |
| | | private MesProWorkOrderService workOrderService; |
| | | @Resource |
| | | private MesProWorkOrderProcessService workOrderProcessService; |
| | | @Resource |
| | | private MesProRouteProductService routeProductService; |
| | | @Resource |
| | | private MesWmProductReceiptService productReceiptService; |
| | | @Resource |
| | |
| | | } |
| | | |
| | | // 2. 创建库存事务 |
| | | createTransactionList(id, lines); |
| | | createTransactionList(produce, lines); |
| | | |
| | | // 3. 更新入库单状态 |
| | | productProduceMapper.updateById(new MesWmProductProduceDO() |
| | |
| | | } |
| | | } |
| | | |
| | | private void createTransactionList(Long produceId, List<MesWmProductProduceLineDO> lines) { |
| | | private void createTransactionList(MesWmProductProduceDO produce, List<MesWmProductProduceLineDO> lines) { |
| | | MesProFeedbackDO feedback = produce.getFeedbackId() != null |
| | | ? feedbackMapper.selectById(produce.getFeedbackId()) : null; |
| | | String bizCode = feedback != null && cn.hutool.core.util.StrUtil.isNotBlank(feedback.getCode()) |
| | | ? feedback.getCode() : "PRODUCE-" + produce.getId(); |
| | | for (MesWmProductProduceLineDO line : lines) { |
| | | // 1. 校验每行明细数量之和等于行数量 |
| | | List<MesWmProductProduceDetailDO> details = productProduceDetailService.getProductProduceDetailListByLineId( |
| | |
| | | .setQuantity(detail.getQuantity()) |
| | | .setBatchId(detail.getBatchId()).setBatchCode(detail.getBatchCode()) |
| | | .setWarehouseId(detail.getWarehouseId()).setLocationId(detail.getLocationId()).setAreaId(detail.getAreaId()) |
| | | .setBizType(MesBizTypeConstants.WM_PRODUCT_PRODUCE).setBizId(produceId) |
| | | .setBizCode("").setBizLineId(line.getId())); |
| | | .setBizType(MesBizTypeConstants.WM_PRODUCT_PRODUCE).setBizId(produce.getId()) |
| | | .setBizCode(bizCode).setBizLineId(line.getId())); |
| | | } |
| | | } |
| | | } |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MesWmProductProduceDO generateProductProduce(MesProFeedbackDO feedback, boolean checkFlag, |
| | | MesProFeedbackApproveReqVO approveReqVO) { |
| | | // 一个报工只能生成一张生产产出单;审批接口重试时直接返回既有单据 |
| | | MesWmProductProduceDO existingProduce = productProduceMapper.selectByFeedbackId(feedback.getId()); |
| | | if (existingProduce != null) { |
| | | return existingProduce; |
| | | } |
| | | // 0. 查询关联的工单(用于获取 clientId 等信息) |
| | | MesProWorkOrderDO workOrder = workOrderService.getWorkOrder(feedback.getWorkOrderId()); |
| | | |
| | |
| | | Long batchId = batch != null ? batch.getId() : null; |
| | | String batchCode = batch != null ? batch.getCode() : null; |
| | | |
| | | // 1.5 获取虚拟线边库 |
| | | MesWmWarehouseDO virtualWarehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE); |
| | | MesWmWarehouseLocationDO virtualLocation = locationService.getWarehouseLocationByCode(MesWmWarehouseLocationDO.WIP_VIRTUAL_LOCATION); |
| | | MesWmWarehouseAreaDO virtualArea = areaService.getWarehouseAreaByCode(MesWmWarehouseAreaDO.WIP_VIRTUAL_AREA); |
| | | // 1.5 优先使用工艺路线产品绑定的报工仓库;历史数据未配置时回退虚拟线边库。 |
| | | WarehouseTarget outputTarget = resolveOutputTarget(feedback.getItemId()); |
| | | |
| | | // 3. 根据是否需要检验分支处理 |
| | | if (checkFlag) { |
| | |
| | | productProduceLineService.createProductProduceLine(unqualifiedLine); |
| | | MesWmProductProduceDetailDO unqualifiedDetail = buildProduceDetail(produce, feedback, batchId, batchCode, |
| | | unqualifiedLine.getId(), unqualifiedQty, |
| | | virtualWarehouse.getId(), virtualLocation.getId(), virtualArea.getId()); |
| | | outputTarget.warehouseId(), outputTarget.locationId(), outputTarget.areaId()); |
| | | productProduceDetailService.createProductProduceDetail(unqualifiedDetail); |
| | | } |
| | | // 3.2.2 合格品行 + 明细 |
| | |
| | | productProduceLineService.createProductProduceLine(qualifiedLine); |
| | | MesWmProductProduceDetailDO qualifiedDetail = buildProduceDetail(produce, feedback, batchId, batchCode, |
| | | qualifiedLine.getId(), qualifiedQty, |
| | | virtualWarehouse.getId(), virtualLocation.getId(), virtualArea.getId()); |
| | | outputTarget.warehouseId(), outputTarget.locationId(), outputTarget.areaId()); |
| | | productProduceDetailService.createProductProduceDetail(qualifiedDetail); |
| | | } |
| | | } |
| | |
| | | if (produce == null) { |
| | | throw exception(WM_PRODUCT_PRODUCE_NOT_EXISTS); |
| | | } |
| | | // 1.2 获取虚拟线边库 |
| | | MesWmWarehouseDO virtualWarehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE); |
| | | MesWmWarehouseLocationDO virtualLocation = locationService.getWarehouseLocationByCode(MesWmWarehouseLocationDO.WIP_VIRTUAL_LOCATION); |
| | | MesWmWarehouseAreaDO virtualArea = areaService.getWarehouseAreaByCode(MesWmWarehouseAreaDO.WIP_VIRTUAL_AREA); |
| | | |
| | | // 2. 通过 sourceLineId 直接定位待检验行 |
| | | MesWmProductProduceLineDO pendingLine = productProduceLineService.validateProductProduceLineExists(sourceLineId); |
| | | WarehouseTarget outputTarget = resolveOutputTarget(pendingLine.getItemId()); |
| | | |
| | | // 3A. 情况一:存在不合格品数量,需要拆分行 |
| | | if (unqualifiedQty != null && unqualifiedQty.compareTo(BigDecimal.ZERO) > 0) { |
| | |
| | | .produceId(produce.getId()).lineId(unqualifiedLine.getId()) |
| | | .itemId(pendingLine.getItemId()).quantity(unqualifiedQty) |
| | | .batchId(pendingLine.getBatchId()).batchCode(pendingLine.getBatchCode()) |
| | | .warehouseId(virtualWarehouse.getId()).locationId(virtualLocation.getId()).areaId(virtualArea.getId()) |
| | | .warehouseId(outputTarget.warehouseId()).locationId(outputTarget.locationId()).areaId(outputTarget.areaId()) |
| | | .build()); |
| | | // 3A.2 合格品:复用原待检行,更新数量和状态 + 明细 |
| | | pendingLine.setQuantity(ObjectUtil.defaultIfNull(qualifiedQty, BigDecimal.ZERO)); |
| | |
| | | .produceId(produce.getId()).lineId(pendingLine.getId()) |
| | | .itemId(pendingLine.getItemId()).quantity(qualifiedQty) |
| | | .batchId(pendingLine.getBatchId()).batchCode(pendingLine.getBatchCode()) |
| | | .warehouseId(virtualWarehouse.getId()).locationId(virtualLocation.getId()).areaId(virtualArea.getId()) |
| | | .warehouseId(outputTarget.warehouseId()).locationId(outputTarget.locationId()).areaId(outputTarget.areaId()) |
| | | .build()); |
| | | } |
| | | } else { |
| | |
| | | .produceId(produce.getId()).lineId(pendingLine.getId()) |
| | | .itemId(pendingLine.getItemId()).quantity(pendingLine.getQuantity()) |
| | | .batchId(pendingLine.getBatchId()).batchCode(pendingLine.getBatchCode()) |
| | | .warehouseId(virtualWarehouse.getId()).locationId(virtualLocation.getId()).areaId(virtualArea.getId()) |
| | | .warehouseId(outputTarget.warehouseId()).locationId(outputTarget.locationId()).areaId(outputTarget.areaId()) |
| | | .build()); |
| | | } |
| | | |
| | |
| | | finishProductProduce(produce.getId()); |
| | | } |
| | | |
| | | private WarehouseTarget resolveOutputTarget(Long itemId) { |
| | | MesProRouteProductDO routeProduct = itemId != null |
| | | ? routeProductService.getRouteProductByItemId(itemId) : null; |
| | | if (routeProduct != null && routeProduct.getWarehouseId() != null |
| | | && routeProduct.getLocationId() != null && routeProduct.getAreaId() != null) { |
| | | areaService.validateWarehouseAreaExists(routeProduct.getWarehouseId(), |
| | | routeProduct.getLocationId(), routeProduct.getAreaId()); |
| | | return new WarehouseTarget(routeProduct.getWarehouseId(), routeProduct.getLocationId(), routeProduct.getAreaId()); |
| | | } |
| | | MesWmWarehouseDO warehouse = warehouseService.getWarehouseByCode(MesWmWarehouseDO.WIP_VIRTUAL_WAREHOUSE); |
| | | MesWmWarehouseLocationDO location = locationService.getWarehouseLocationByCode( |
| | | MesWmWarehouseLocationDO.WIP_VIRTUAL_LOCATION); |
| | | MesWmWarehouseAreaDO area = areaService.getWarehouseAreaByCode(MesWmWarehouseAreaDO.WIP_VIRTUAL_AREA); |
| | | return new WarehouseTarget(warehouse.getId(), location.getId(), area.getId()); |
| | | } |
| | | |
| | | private record WarehouseTarget(Long warehouseId, Long locationId, Long areaId) { |
| | | } |
| | | |
| | | } |