liyong
2026-07-10 80ddf4c9c0bcb0f6c31524e0d9f5599c8001e904
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java
@@ -18,16 +18,21 @@
import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum;
import cn.iocoder.yudao.module.erp.service.finance.ErpAccountService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.product.mapping.ErpMdmMappingService;
import cn.iocoder.yudao.module.erp.service.stock.ErpStockRecordService;
import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO;
import cn.iocoder.yudao.module.wms.api.dto.WmsSalesOutboundReqDTO;
import cn.iocoder.yudao.module.wms.api.stock.WmsStockApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -46,6 +51,7 @@
 */
@Service
@Validated
@Slf4j
public class ErpSaleOutServiceImpl implements ErpSaleOutService {
    @Resource
@@ -65,6 +71,12 @@
    private ErpAccountService accountService;
    @Resource
    private ErpStockRecordService stockRecordService;
    @Resource
    private WmsStockApi wmsStockApi;
    @Resource
    private ErpMdmMappingService mdmMappingService;
    @Resource
    private AdminUserApi adminUserApi;
@@ -193,6 +205,67 @@
                    saleOutItem.getProductId(), saleOutItem.getWarehouseId(), count,
                    bizType, saleOutItem.getOutId(), saleOutItem.getId(), saleOut.getNo()));
        });
        // 4. 同步 WMS 库存(MES 库存)
        if (approve) {
            syncToWmsSalesOutbound(saleOut, saleOutItems);
        }
    }
    /**
     * 同步销售出库到 WMS 库存
     */
    private void syncToWmsSalesOutbound(ErpSaleOutDO saleOut, List<ErpSaleOutItemDO> saleOutItems) {
        if (CollUtil.isEmpty(saleOutItems)) {
            return;
        }
        log.info("[syncToWmsSalesOutbound] 开始同步销售出库到WMS,saleOutId={}", saleOut.getId());
        // 构建出库请求
        WmsSalesOutboundReqDTO reqDTO = new WmsSalesOutboundReqDTO()
                .setBizId(saleOut.getId())
                .setBizCode(saleOut.getNo())
                .setOutboundTime(LocalDateTime.now());
        // 转换明细项
        List<WmsSalesOutboundReqDTO.Item> items = convertList(saleOutItems, item -> {
            // ERP 产品 ID -> MDM 物料 ID
            Long mdmItemId = mdmMappingService.getMdmItemId(item.getProductId());
            // ERP 仓库 ID -> MES 仓库 ID
            Long mesWarehouseId = mdmMappingService.getMesWarehouseId(item.getWarehouseId());
            if (mdmItemId == null) {
                log.warn("[syncToWmsSalesOutbound] 未找到MDM物料映射,erpProductId={}", item.getProductId());
                return null;
            }
            if (mesWarehouseId == null) {
                log.warn("[syncToWmsSalesOutbound] 未找到MES仓库映射,erpWarehouseId={}", item.getWarehouseId());
                return null;
            }
            return new WmsSalesOutboundReqDTO.Item()
                    .setItemId(mdmItemId)
                    .setWarehouseId(mesWarehouseId)
                    .setQuantity(item.getCount())
                    .setBizLineId(item.getId());
        });
        // 过滤掉映射失败的项
        items = items.stream().filter(java.util.Objects::nonNull).toList();
        if (CollUtil.isEmpty(items)) {
            log.warn("[syncToWmsSalesOutbound] 无有效的出库明细,跳过WMS同步");
            return;
        }
        reqDTO.setItems(items);
        try {
            Long transactionId = wmsStockApi.salesOutbound(reqDTO);
            log.info("[syncToWmsSalesOutbound] 同步成功,transactionId={}", transactionId);
        } catch (Exception e) {
            log.error("[syncToWmsSalesOutbound] 同步失败", e);
        }
    }
    @Override