| | |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.iocoder.yudao.framework.common.core.KeyValue; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWmReturnSalesLinePageReqVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.wm.returnsales.vo.line.MesWmReturnSalesLineSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productsales.MesWmProductSalesLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesLineDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnsales.MesWmReturnSalesDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnsales.MesWmReturnSalesLineMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmQualityStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.enums.wm.MesWmReturnSalesStatusEnum; |
| | | import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.productsales.MesWmProductSalesLineService; |
| | | import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; |
| | | import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.Collection; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Objects; |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.MD_ITEM_BATCH_REQUIRED; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_SALES_LINE_NOT_EXISTS; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; |
| | | |
| | | /** |
| | | * MES 销售退货单行 Service 实现类 |
| | |
| | | @Lazy |
| | | private MesWmReturnSalesService returnSalesService; |
| | | @Resource |
| | | private MesMdmItemService mdmItemService; |
| | | private MdmItemApi mdmItemApi; |
| | | @Resource |
| | | private MesWmBatchService batchService; |
| | | @Resource |
| | | @Lazy |
| | | private MesWmReturnSalesDetailService returnSalesDetailService; |
| | | @Resource |
| | | @Lazy |
| | | private MesWmProductSalesLineService productSalesLineService; |
| | | |
| | | @Override |
| | | public Long createReturnSalesLine(MesWmReturnSalesLineSaveReqVO createReqVO) { |
| | |
| | | |
| | | /** |
| | | * 校验保存时的关联数据 |
| | | * |
| | | * <p>退货单关联了销售出库单时,物料、批次一律取自出库行,并校验可退数量; |
| | | * 未关联出库单(如售后模块创建)时,保持原有物料/批次校验逻辑。 |
| | | */ |
| | | private void validateLineSaveData(MesWmReturnSalesLineSaveReqVO reqVO) { |
| | | // 校验退货单存在 + 草稿状态 |
| | | returnSalesService.validateReturnSalesExistsAndPrepare(reqVO.getReturnId()); |
| | | MesWmReturnSalesDO returnSales = returnSalesService.validateReturnSalesExistsAndPrepare(reqVO.getReturnId()); |
| | | if (returnSales.getProductSalesId() != null) { |
| | | validateOutboundLine(reqVO, returnSales); |
| | | return; |
| | | } |
| | | // 校验物料存在 + 批次管理 |
| | | validateItemBatchManagement(reqVO.getReturnId(), reqVO.getItemId(), reqVO.getBatchId()); |
| | | } |
| | | |
| | | /** |
| | | * 校验出库行归属与可退数量,并从出库行回填物料、批次 |
| | | */ |
| | | private void validateOutboundLine(MesWmReturnSalesLineSaveReqVO reqVO, MesWmReturnSalesDO returnSales) { |
| | | if (reqVO.getProductSalesLineId() == null) { |
| | | throw exception(WM_RETURN_SALES_LINE_PRODUCT_SALES_REQUIRED); |
| | | } |
| | | MesWmProductSalesLineDO outboundLine = |
| | | productSalesLineService.validateProductSalesLineExists(reqVO.getProductSalesLineId()); |
| | | if (ObjUtil.notEqual(outboundLine.getSalesId(), returnSales.getProductSalesId())) { |
| | | throw exception(WM_RETURN_SALES_LINE_PRODUCT_SALES_NOT_MATCH); |
| | | } |
| | | // 物料、批次必须与出库行一致 |
| | | reqVO.setItemId(outboundLine.getItemId()); |
| | | reqVO.setBatchId(outboundLine.getBatchId()); |
| | | reqVO.setBatchCode(outboundLine.getBatchCode()); |
| | | |
| | | // 可退数量 = 出库数量 - 其它退货单已退数量(排除当前退货单) |
| | | BigDecimal returned = getReturnedQuantityMap( |
| | | Collections.singletonList(outboundLine.getId()), returnSales.getId()) |
| | | .getOrDefault(outboundLine.getId(), BigDecimal.ZERO); |
| | | BigDecimal returnable = outboundLine.getQuantity().subtract(returned); |
| | | if (reqVO.getQuantity().compareTo(returnable) > 0) { |
| | | throw exception(WM_RETURN_SALES_LINE_QUANTITY_EXCEED); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | |
| | | @Override |
| | | public Map<Long, BigDecimal> getReturnedQuantityMap(Collection<Long> productSalesLineIds, Long excludeReturnId) { |
| | | if (CollUtil.isEmpty(productSalesLineIds)) { |
| | | return Collections.emptyMap(); |
| | | } |
| | | List<KeyValue<Long, BigDecimal>> list = returnSalesLineMapper.selectReturnedQuantityList( |
| | | productSalesLineIds, MesWmReturnSalesStatusEnum.CANCELED.getStatus(), excludeReturnId); |
| | | return CollectionUtils.convertMap(list, KeyValue::getKey, KeyValue::getValue); |
| | | } |
| | | |
| | | @Override |
| | | public void updateQualityStatusByReturnId(Long returnId, Integer qualityStatus) { |
| | | List<MesWmReturnSalesLineDO> lines = returnSalesLineMapper.selectListByReturnId(returnId); |
| | | for (MesWmReturnSalesLineDO line : lines) { |
| | |
| | | * @param batchId 批次ID |
| | | */ |
| | | private void validateItemBatchManagement(Long returnId, Long itemId, Long batchId) { |
| | | MesMdmItemDO item = mdmItemService.validateItemExistsAndEnable(itemId); |
| | | MdmItemRespDTO item = mdmItemApi.validateItemExistsAndEnable(itemId).getCheckedData(); |
| | | // 如果物料启用了批次管理,则必须选择批次 |
| | | if (Boolean.TRUE.equals(item.getIsBatchManaged()) && batchId == null) { |
| | | throw exception(MD_ITEM_BATCH_REQUIRED); |
| | |
| | | // 1.C.1 新增一行不合格品 |
| | | MesWmReturnSalesLineDO unqualifiedLine = new MesWmReturnSalesLineDO() |
| | | .setReturnId(sourceLine.getReturnId()) |
| | | .setProductSalesLineId(sourceLine.getProductSalesLineId()) |
| | | .setItemId(sourceLine.getItemId()) |
| | | .setQuantity(unqualifiedQuantity) |
| | | .setBatchId(sourceLine.getBatchId()) |
| | | .setBatchCode(sourceLine.getBatchCode()) |
| | | .setRqcId(sourceLine.getRqcId()) |
| | | .setRqcCheckFlag(sourceLine.getRqcCheckFlag()) |
| | | .setQualityStatus(MesWmQualityStatusEnum.FAIL.getStatus()) |