package cn.iocoder.yudao.module.mes.service.wm.returnvendor;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
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.erp.api.purchase.ErpPurchaseOrderApi;
|
import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderItemRespDTO;
|
import cn.iocoder.yudao.module.erp.api.purchase.dto.ErpPurchaseOrderRespDTO;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.returnvendor.vo.line.MesWmReturnVendorLinePageReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.wm.returnvendor.vo.line.MesWmReturnVendorLineSaveReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnvendor.MesWmReturnVendorLineDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.returnvendor.MesWmReturnVendorDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.wm.returnvendor.MesWmReturnVendorLineMapper;
|
import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService;
|
import cn.iocoder.yudao.module.mes.service.wm.batch.MesWmBatchService;
|
import jakarta.annotation.Resource;
|
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.util.List;
|
import java.util.Set;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_VENDOR_ITEM_NOT_IN_PURCHASE_ORDER;
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_RETURN_VENDOR_LINE_NOT_EXISTS;
|
|
/**
|
* MES 供应商退货单行 Service 实现类
|
*/
|
@Service
|
@Validated
|
public class MesWmReturnVendorLineServiceImpl implements MesWmReturnVendorLineService {
|
|
@Resource
|
private MesWmReturnVendorLineMapper returnVendorLineMapper;
|
|
@Resource
|
@Lazy
|
private MesWmReturnVendorService returnVendorService;
|
@Resource
|
@Lazy
|
private MesWmReturnVendorDetailService returnVendorDetailService;
|
@Resource
|
private MesMdmItemService mdmItemService;
|
@Resource
|
private MesWmBatchService batchService;
|
@Resource
|
private ErpPurchaseOrderApi purchaseOrderApi;
|
|
@Override
|
public Long createReturnVendorLine(MesWmReturnVendorLineSaveReqVO createReqVO) {
|
// 校验数据
|
MesWmReturnVendorDO returnVendor = validateReturnVendorLineSaveData(createReqVO);
|
// 退货单若已关联采购订单,物料必须属于该采购订单,禁止跨订单随意选料
|
validateReturnVendorItemInPurchaseOrder(returnVendor, createReqVO.getItemId(), null);
|
|
// 插入
|
MesWmReturnVendorLineDO line = BeanUtils.toBean(createReqVO, MesWmReturnVendorLineDO.class);
|
returnVendorLineMapper.insert(line);
|
return line.getId();
|
}
|
|
@Override
|
public void updateReturnVendorLine(MesWmReturnVendorLineSaveReqVO updateReqVO) {
|
// 校验存在
|
MesWmReturnVendorLineDO oldLine = validateReturnVendorLineExists(updateReqVO.getId());
|
// 固定父单 ID,防止通过接口篡改
|
updateReqVO.setReturnId(oldLine.getReturnId());
|
// 校验数据
|
MesWmReturnVendorDO returnVendor = validateReturnVendorLineSaveData(updateReqVO);
|
// 关联采购订单时,不允许把行物料改成订单外的物料;仅改数量等操作不受影响
|
validateReturnVendorItemInPurchaseOrder(returnVendor, updateReqVO.getItemId(), oldLine.getItemId());
|
|
// 更新
|
MesWmReturnVendorLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnVendorLineDO.class);
|
returnVendorLineMapper.updateById(updateObj);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteReturnVendorLine(Long id) {
|
// 1.1 校验存在
|
MesWmReturnVendorLineDO line = validateReturnVendorLineExists(id);
|
// 1.2 校验父数据为草稿状态
|
returnVendorService.validateReturnVendorExistsAndPrepare(line.getReturnId());
|
|
// 2.1 级联删除该行下的明细
|
returnVendorDetailService.deleteReturnVendorDetailByLineId(id);
|
// 2.2 删除行
|
returnVendorLineMapper.deleteById(id);
|
}
|
|
@Override
|
public MesWmReturnVendorLineDO getReturnVendorLine(Long id) {
|
return returnVendorLineMapper.selectById(id);
|
}
|
|
@Override
|
public PageResult<MesWmReturnVendorLineDO> getReturnVendorLinePage(MesWmReturnVendorLinePageReqVO pageReqVO) {
|
return returnVendorLineMapper.selectPage(pageReqVO);
|
}
|
|
@Override
|
public List<MesWmReturnVendorLineDO> getReturnVendorLineListByReturnId(Long returnId) {
|
return returnVendorLineMapper.selectListByReturnId(returnId);
|
}
|
|
@Override
|
public void deleteReturnVendorLineByReturnId(Long returnId) {
|
returnVendorLineMapper.deleteByReturnId(returnId);
|
}
|
|
@Override
|
public MesWmReturnVendorLineDO validateReturnVendorLineExists(Long id) {
|
MesWmReturnVendorLineDO line = returnVendorLineMapper.selectById(id);
|
if (line == null) {
|
throw exception(WM_RETURN_VENDOR_LINE_NOT_EXISTS);
|
}
|
return line;
|
}
|
|
private MesWmReturnVendorDO validateReturnVendorLineSaveData(MesWmReturnVendorLineSaveReqVO reqVO) {
|
// 校验父数据存在且为草稿状态
|
MesWmReturnVendorDO returnVendor = returnVendorService.validateReturnVendorExistsAndPrepare(reqVO.getReturnId());
|
// 校验物料存在
|
mdmItemService.validateItemExistsAndEnable(reqVO.getItemId());
|
// 校验批次存在且属于当前物料和供应商
|
if (reqVO.getBatchId() != null) {
|
batchService.validateBatchExists(reqVO.getBatchId(), reqVO.getItemId(), null, returnVendor.getVendorId());
|
}
|
return returnVendor;
|
}
|
|
/**
|
* 校验退货行物料属于所关联采购订单(退货单已关联采购订单时)。
|
*
|
* 采购退货的物料应取自关联采购订单,此处为后端兜底,防止通过接口跨订单随意选料。
|
* 物料与带入逻辑保持一致:以采购订单明细的产品 ID 作为物料集合。
|
*
|
* @param oldItemId 修改前物料 ID;为空表示新增。物料未变化时(仅改数量等)不重复校验
|
*/
|
private void validateReturnVendorItemInPurchaseOrder(MesWmReturnVendorDO returnVendor, Long itemId, Long oldItemId) {
|
Long purchaseOrderId = returnVendor.getPurchaseOrderId();
|
if (purchaseOrderId == null) {
|
return;
|
}
|
// 编辑行时物料未变(只改数量/批次等),无需校验
|
if (ObjUtil.equal(itemId, oldItemId)) {
|
return;
|
}
|
List<ErpPurchaseOrderItemRespDTO> poItems = purchaseOrderApi
|
.getPurchaseOrderItemList(purchaseOrderId).getCheckedData();
|
if (CollUtil.isEmpty(poItems)) {
|
// 订单无明细时由"带入物料"流程统一给出提示,此处不拦截
|
return;
|
}
|
Set<Long> poProductIds = CollectionUtils.convertSet(poItems, ErpPurchaseOrderItemRespDTO::getProductId);
|
if (poProductIds.contains(itemId)) {
|
return;
|
}
|
throw new ServiceException(WM_RETURN_VENDOR_ITEM_NOT_IN_PURCHASE_ORDER.getCode(),
|
String.format("退货单[%s]已关联采购订单[%s],退货物料%s不在该采购订单明细中。"
|
+ "退货只能针对该采购订单的物料,请选择订单内的物料并仅调整退货数量;"
|
+ "如需退回订单外物料,请先解除当前采购订单关联。",
|
returnVendor.getCode(), resolvePurchaseOrderNo(purchaseOrderId), resolveItemDesc(itemId)));
|
}
|
|
/**
|
* 解析采购订单号,解析失败时回退为可读 ID
|
*/
|
private String resolvePurchaseOrderNo(Long purchaseOrderId) {
|
ErpPurchaseOrderRespDTO purchaseOrder = purchaseOrderApi.getPurchaseOrder(purchaseOrderId).getCheckedData();
|
if (purchaseOrder != null && StrUtil.isNotBlank(purchaseOrder.getNo())) {
|
return purchaseOrder.getNo();
|
}
|
return "ID=" + purchaseOrderId;
|
}
|
|
/**
|
* 解析物料可读描述(编码+名称),解析失败时回退为可读 ID
|
*/
|
private String resolveItemDesc(Long itemId) {
|
MesMdmItemDO item = mdmItemService.getItem(itemId);
|
if (item == null) {
|
return "ID=" + itemId;
|
}
|
String name = StrUtil.nullToDefault(item.getName(), "");
|
return (StrUtil.isNotBlank(item.getCode()) ? "[" + item.getCode() + "]" : "[ID=" + itemId + "]") + name;
|
}
|
|
}
|