| | |
| | | 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.md.item.MesMdItemService; |
| | | 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.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; |
| | | |
| | | /** |
| | |
| | | @Lazy |
| | | private MesWmReturnVendorDetailService returnVendorDetailService; |
| | | @Resource |
| | | private MesMdItemService itemService; |
| | | private MesMdmItemService mdmItemService; |
| | | @Resource |
| | | private MesWmBatchService batchService; |
| | | @Resource |
| | | private ErpPurchaseOrderApi purchaseOrderApi; |
| | | |
| | | @Override |
| | | public Long createReturnVendorLine(MesWmReturnVendorLineSaveReqVO createReqVO) { |
| | | // 校验数据 |
| | | validateReturnVendorLineSaveData(createReqVO); |
| | | MesWmReturnVendorDO returnVendor = validateReturnVendorLineSaveData(createReqVO); |
| | | // 退货单若已关联采购订单,物料必须属于该采购订单,禁止跨订单随意选料 |
| | | validateReturnVendorItemInPurchaseOrder(returnVendor, createReqVO.getItemId(), null); |
| | | |
| | | // 插入 |
| | | MesWmReturnVendorLineDO line = BeanUtils.toBean(createReqVO, MesWmReturnVendorLineDO.class); |
| | |
| | | // 固定父单 ID,防止通过接口篡改 |
| | | updateReqVO.setReturnId(oldLine.getReturnId()); |
| | | // 校验数据 |
| | | validateReturnVendorLineSaveData(updateReqVO); |
| | | MesWmReturnVendorDO returnVendor = validateReturnVendorLineSaveData(updateReqVO); |
| | | // 关联采购订单时,不允许把行物料改成订单外的物料;仅改数量等操作不受影响 |
| | | validateReturnVendorItemInPurchaseOrder(returnVendor, updateReqVO.getItemId(), oldLine.getItemId()); |
| | | |
| | | // 更新 |
| | | MesWmReturnVendorLineDO updateObj = BeanUtils.toBean(updateReqVO, MesWmReturnVendorLineDO.class); |
| | |
| | | return line; |
| | | } |
| | | |
| | | private void validateReturnVendorLineSaveData(MesWmReturnVendorLineSaveReqVO reqVO) { |
| | | private MesWmReturnVendorDO validateReturnVendorLineSaveData(MesWmReturnVendorLineSaveReqVO reqVO) { |
| | | // 校验父数据存在且为草稿状态 |
| | | MesWmReturnVendorDO returnVendor = returnVendorService.validateReturnVendorExistsAndPrepare(reqVO.getReturnId()); |
| | | // 校验物料存在 |
| | | itemService.validateItemExistsAndEnable(reqVO.getItemId()); |
| | | 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; |
| | | } |
| | | |
| | | } |