| | |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesLineMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; |
| | | import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeQcStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmSalesNoticeStatusEnum; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO; |
| | | import cn.iocoder.yudao.module.mes.service.qc.oqc.MesQcOqcService; |
| | | import cn.iocoder.yudao.module.erp.api.sale.ErpSaleOrderApi; |
| | | import cn.iocoder.yudao.module.erp.api.sale.enums.ErpSaleOrderOutStatusEnum; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.context.annotation.Lazy; |
| | |
| | | |
| | | @Resource |
| | | private MesTraceIntegrityService integrityService; |
| | | |
| | | @Resource |
| | | private ErpSaleOrderApi saleOrderApi; |
| | | |
| | | @Override |
| | | public Long createProductSales(MesWmProductSalesSaveReqVO createReqVO) { |
| | |
| | | if (pallet != null && pallet.getBatchId() == null) { |
| | | throw exception(PRO_PALLET_NOT_BIND_BATCH); |
| | | } |
| | | // 种子质检按袋码粒度流转后,出库只允许已质检合格的袋码/托盘 |
| | | if (pallet != null) { |
| | | List<MesProBagCodeDO> palletBags = bagCodeService.getBagCodeListByPalletId(pallet.getId()); |
| | | if (palletBags.stream().anyMatch(b -> !MesProBagCodeQcStatusEnum.QUALIFIED.getStatus().equals(b.getQcStatus()))) { |
| | | throw exception(WM_PRODUCT_SALES_SCAN_PALLET_NOT_ALL_QUALIFIED); |
| | | } |
| | | } else if (!MesProBagCodeQcStatusEnum.QUALIFIED.getStatus().equals(bag.getQcStatus())) { |
| | | throw exception(WM_PRODUCT_SALES_SCAN_BAG_NOT_QUALIFIED); |
| | | } |
| | | Long codeId = pallet != null ? pallet.getId() : bag.getId(); |
| | | MesWmProductSalesDetailDO existed = pallet != null |
| | | ? productSalesDetailMapper.selectBySalesIdAndPalletCodeId(reqVO.getSalesId(), codeId) |
| | |
| | | if (quantity == null) { |
| | | quantity = line.getQuantity(); |
| | | } |
| | | List<MesWmMaterialStockDO> stocks = materialStockService.getMaterialStockListByItemAndBatch(batch.getItemId(), wmBatch.getId()); |
| | | // 只从合格库记录中选库存(同批次暂存库记录不可出库) |
| | | List<MesWmMaterialStockDO> stocks = materialStockService.getQualifiedMaterialStockListByItemAndBatch(batch.getItemId(), wmBatch.getId()); |
| | | BigDecimal outboundQuantity = quantity; |
| | | MesWmMaterialStockDO stock = stocks.stream().filter(item -> item.getQuantity().compareTo(outboundQuantity) >= 0).findFirst().orElse(null); |
| | | if (stock == null) { |
| | |
| | | // 执行拣货(待拣货 → 待填写运单) |
| | | productSalesMapper.updateById(new MesWmProductSalesDO() |
| | | .setId(id).setStatus(MesWmProductSalesStatusEnum.SHIPPING.getStatus())); |
| | | |
| | | // 回写 ERP 销售订单出库状态为"部分出库"(表示已拣货/占用) |
| | | if (sales.getSaleOrderId() != null) { |
| | | saleOrderApi.updateOrderOutStatusTo(sales.getSaleOrderId(), |
| | | ErpSaleOrderOutStatusEnum.PART_OUT.getStatus()); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | updateSalesNoticeOutCount(sales); |
| | | } |
| | | |
| | | // 6. 回写 ERP 销售订单的出库数量和状态 |
| | | updateErpSaleOrderOutCount(sales); |
| | | |
| | | // 7. 回写袋码/托盘出库去向(供窜货稽查定位经销商地区),并生成出库完整性摘要 |
| | | // 6. 回写袋码/托盘出库去向(供窜货稽查定位经销商地区),并生成出库完整性摘要 |
| | | List<MesWmProductSalesDetailDO> outDetails = productSalesDetailService.getProductSalesDetailListBySalesId(id); |
| | | for (MesWmProductSalesDetailDO detail : outDetails) { |
| | | if (detail.getBagCodeId() != null) { |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 回写 ERP 销售订单的出库数量和状态 |
| | | */ |
| | | private void updateErpSaleOrderOutCount(MesWmProductSalesDO sales) { |
| | | // 获取出库单行 |
| | | List<MesWmProductSalesLineDO> lines = productSalesLineService.getProductSalesLineListBySalesId(sales.getId()); |
| | | if (CollUtil.isEmpty(lines)) { |
| | | return; |
| | | } |
| | | // 用于存储销售订单 ID,避免重复更新 |
| | | Long saleOrderId = null; |
| | | // 遍历行,按 saleOrderItemId 更新出库数量 |
| | | for (MesWmProductSalesLineDO line : lines) { |
| | | if (line.getSaleOrderItemId() != null && line.getQuantity() != null) { |
| | | saleOrderApi.updateOrderItemOutCount(line.getSaleOrderItemId(), line.getQuantity()); |
| | | // 获取销售订单 ID(从第一个有效的明细项获取) |
| | | if (saleOrderId == null) { |
| | | cn.iocoder.yudao.module.erp.api.sale.dto.ErpSaleOrderItemRespDTO itemDTO = |
| | | saleOrderApi.getSaleOrderItem(line.getSaleOrderItemId()).getCheckedData(); |
| | | if (itemDTO != null && itemDTO.getOrderId() != null) { |
| | | saleOrderId = itemDTO.getOrderId(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | // 更新销售订单的出库状态 |
| | | if (saleOrderId != null) { |
| | | saleOrderApi.updateOrderOutStatus(saleOrderId); |
| | | } |
| | | } |
| | | |
| | | private void createTransactionList(MesWmProductSalesDO sales) { |
| | | List<MesWmProductSalesDetailDO> details = productSalesDetailService.getProductSalesDetailListBySalesId(sales.getId()); |
| | | wmTransactionService.createTransactionList(convertList(details, detail -> new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.OUT.getType()).setItemId(detail.getItemId()) |
| | | .setQuantity(detail.getQuantity().negate()) // 出库数量为负数 |
| | | .setBatchId(detail.getBatchId()).setBatchCode(detail.getBatchCode()) |
| | | .setBagCodeId(detail.getBagCodeId()) // 袋码型明细出库时置袋码已出库;托盘型明细不逐袋处理 |
| | | .setWarehouseId(detail.getWarehouseId()).setLocationId(detail.getLocationId()).setAreaId(detail.getAreaId()) |
| | | .setBizType(MesBizTypeConstants.WM_PRODUCT_SALES).setBizId(sales.getId()) |
| | | .setBizCode(sales.getCode()).setBizLineId(detail.getLineId()) |