package cn.iocoder.yudao.module.mes.service.wm.returnsales; 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.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.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.*; /** * MES 销售退货单行 Service 实现类 * * @author 超级管理员 */ @Service @Validated public class MesWmReturnSalesLineServiceImpl implements MesWmReturnSalesLineService { @Resource private MesWmReturnSalesLineMapper returnSalesLineMapper; @Resource @Lazy private MesWmReturnSalesService returnSalesService; @Resource private MdmItemApi mdmItemApi; @Resource private MesWmBatchService batchService; @Resource @Lazy private MesWmReturnSalesDetailService returnSalesDetailService; @Resource @Lazy private MesWmProductSalesLineService productSalesLineService; @Override public Long createReturnSalesLine(MesWmReturnSalesLineSaveReqVO createReqVO) { validateLineSaveData(createReqVO); // 插入 MesWmReturnSalesLineDO line = BeanUtils.toBean(createReqVO, MesWmReturnSalesLineDO.class); // 质量状态自动赋值 line.setQualityStatus(calculateQualityStatus(line.getRqcCheckFlag())); returnSalesLineMapper.insert(line); return line.getId(); } @Override public void updateReturnSalesLine(MesWmReturnSalesLineSaveReqVO updateReqVO) { // 校验存在 MesWmReturnSalesLineDO oldLine = validateReturnSalesLineExists(updateReqVO.getId()); // 固定父单 ID,防止通过接口篡改 updateReqVO.setReturnId(oldLine.getReturnId()); validateLineSaveData(updateReqVO); // 更新 MesWmReturnSalesLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnSalesLineDO.class); // 质量状态自动赋值 updateObj.setQualityStatus(calculateQualityStatus(updateObj.getRqcCheckFlag())); returnSalesLineMapper.updateById(updateObj); } /** * 校验保存时的关联数据 * *
退货单关联了销售出库单时,物料、批次一律取自出库行,并校验可退数量;
* 未关联出库单(如售后模块创建)时,保持原有物料/批次校验逻辑。
*/
private void validateLineSaveData(MesWmReturnSalesLineSaveReqVO reqVO) {
// 校验退货单存在 + 草稿状态
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
public void deleteReturnSalesLine(Long id) {
// 校验存在
MesWmReturnSalesLineDO line = validateReturnSalesLineExists(id);
// 校验主单为草稿状态才允许删除行
returnSalesService.validateReturnSalesExistsAndPrepare(line.getReturnId());
// 级联删除该行的明细
returnSalesDetailService.deleteReturnSalesDetailByLineId(id);
// 删除行
returnSalesLineMapper.deleteById(id);
}
@Override
public MesWmReturnSalesLineDO getReturnSalesLine(Long id) {
return returnSalesLineMapper.selectById(id);
}
@Override
public PageResult