云
3 天以前 87733eb3623593da247c051593d64b8ff9e1d3a4
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesDetailServiceImpl.java
@@ -6,6 +6,10 @@
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesDetailDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesDetailMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.productsales.MesWmProductSalesMapper;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum;
import org.springframework.transaction.annotation.Transactional;
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
@@ -40,9 +44,26 @@
    private MesWmMaterialStockService materialStockService;
    @Resource
    private MesWmWarehouseAreaService warehouseAreaService;
    @Resource
    private MesWmMaterialStockBagMapper stockBagMapper;
    @Resource
    private MesWmProductSalesMapper productSalesMapper;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createProductSalesDetail(MesWmProductSalesDetailSaveReqVO createReqVO) {
        lockPickingOrder(createReqVO.getSalesId());
        if (createReqVO.getRemark() != null && createReqVO.getRemark().matches("移动端无袋码拣货 #[a-f0-9-]{36}")) {
            var existing = productSalesDetailMapper.selectListBySalesId(createReqVO.getSalesId()).stream()
                    .filter(d -> createReqVO.getRemark().equals(d.getRemark())).findFirst().orElse(null);
            if (existing != null) {
                if (ObjUtil.notEqual(existing.getLineId(), createReqVO.getLineId())
                        || ObjUtil.notEqual(existing.getMaterialStockId(), createReqVO.getMaterialStockId())
                        || existing.getQuantity().compareTo(createReqVO.getQuantity()) != 0)
                    throw new IllegalArgumentException("拣货请求标识已用于其他明细");
                return existing.getId();
            }
        }
        // 校验数据
        validateProductSalesDetailSaveData(createReqVO);
@@ -53,9 +74,13 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProductSalesDetail(MesWmProductSalesDetailSaveReqVO updateReqVO) {
        // 校验存在
        MesWmProductSalesDetailDO existing = validateProductSalesDetailExists(updateReqVO.getId());
        lockPickingOrder(existing.getSalesId());
        if (existing.getShipmentId() != null) throw new IllegalArgumentException("已分配发货记录的明细不能修改");
        if (ObjUtil.notEqual(existing.getSalesId(), updateReqVO.getSalesId())) throw exception(WM_PRODUCT_SALES_DETAIL_LINE_NOT_MATCH);
        if (existing.getBagCodeId() != null) throw new IllegalArgumentException("扫码袋码明细不能手工修改数量或库存,请删除后重新扫码选择");
        // 校验数据
        validateProductSalesDetailSaveData(updateReqVO);
@@ -66,9 +91,12 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteProductSalesDetail(Long id) {
        // 校验存在
        validateProductSalesDetailExists(id);
        MesWmProductSalesDetailDO detail = validateProductSalesDetailExists(id);
        lockPickingOrder(detail.getSalesId());
        if (detail.getShipmentId() != null) throw new IllegalArgumentException("已分配发货记录的明细不能删除");
        // 删除
        productSalesDetailMapper.deleteById(id);
    }
@@ -106,7 +134,19 @@
        return detail;
    }
    private void lockPickingOrder(Long salesId) {
        var sales = productSalesMapper.selectByIdForUpdate(salesId);
        if (sales == null) throw exception(WM_PRODUCT_SALES_NOT_EXISTS);
        if (!MesWmProductSalesStatusEnum.APPROVING.getStatus().equals(sales.getStatus())) {
            throw exception(WM_PRODUCT_SALES_CANNOT_PICK);
        }
    }
    private void validateProductSalesDetailSaveData(MesWmProductSalesDetailSaveReqVO reqVO) {
        if (reqVO.getQuantity() == null || reqVO.getQuantity().signum() <= 0) throw new IllegalArgumentException("拣货数量必须大于零");
        if (reqVO.getMaterialStockId() != null && stockBagMapper.selectOneActiveByMaterialStockId(reqVO.getMaterialStockId()) != null) {
            throw new IllegalArgumentException("该库存存在袋码明细,请选择实际拣出的袋码");
        }
        // 校验父数据(行)存在
        MesWmProductSalesLineDO line = productSalesLineService.getProductSalesLine(reqVO.getLineId());
        if (line == null) {
@@ -115,11 +155,19 @@
        if (ObjUtil.notEqual(line.getSalesId(), reqVO.getSalesId())) {
            throw exception(WM_PRODUCT_SALES_DETAIL_LINE_NOT_MATCH);
        }
        var picked = productSalesDetailMapper.selectListByLineId(line.getId()).stream()
                .filter(d -> !java.util.Objects.equals(d.getId(), reqVO.getId()))
                .map(MesWmProductSalesDetailDO::getQuantity).reduce(java.math.BigDecimal.ZERO, java.math.BigDecimal::add);
        if (line.getQuantity() == null || picked.add(reqVO.getQuantity()).compareTo(line.getQuantity()) > 0)
            throw new IllegalArgumentException("累计拣货数量不能超过出库单行计划数量");
        // 校验物料存在
        mdmItemService.validateItemExistsAndEnable(reqVO.getItemId());
        if (ObjUtil.notEqual(line.getItemId(), reqVO.getItemId())) {
            throw exception(WM_PRODUCT_SALES_DETAIL_ITEM_MISMATCH);
        }
        if (line.getBatchCode() != null && !line.getBatchCode().isBlank()
                && !java.util.Objects.equals(line.getBatchCode(), reqVO.getBatchCode()))
            throw new IllegalArgumentException("所选库存批次与出库单行批次不一致");
        // 校验库位存在
        warehouseAreaService.validateWarehouseAreaExists(
                reqVO.getWarehouseId(), reqVO.getLocationId(), reqVO.getAreaId());