| | |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.product.MesProRouteProductSaveReqVO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.pro.route.MesProRouteProductMapper; |
| | | import cn.iocoder.yudao.module.mes.enums.md.MesMdItemTypeEnum; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; |
| | | import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; |
| | | import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; |
| | | import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; |
| | | import cn.iocoder.yudao.module.mdm.enums.MdmItemTypeEnum; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.util.List; |
| | | import java.util.HashSet; |
| | | import java.util.Set; |
| | | 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 芋道源码 |
| | | * @author 超级管理员 |
| | | */ |
| | | @Service |
| | | @Validated |
| | |
| | | @Resource |
| | | @Lazy |
| | | private MesProRouteProductBomService routeProductBomService; |
| | | @Resource |
| | | private MesMdItemService itemService; |
| | | @Resource |
| | | private MesMdItemTypeService itemTypeService; |
| | | @Resource |
| | | private MesWmWarehouseAreaService warehouseAreaService; |
| | | @Resource |
| | | private MdmItemApi mdmItemApi; |
| | | |
| | | @Override |
| | | public Long createRouteProduct(MesProRouteProductSaveReqVO createReqVO) { |
| | | // 1.0 已启用的工艺路线,不允许操作 |
| | | routeService.validateRouteNotEnable(createReqVO.getRouteId()); |
| | | // 1.1 校验产品唯一性(一个产品只能关联一条工艺路线) |
| | | // 1.1 校验产品存在、启用且类型正确 |
| | | validateProductItem(createReqVO.getItemId()); |
| | | // 1.2 校验产品唯一性(一个产品只能关联一条工艺路线) |
| | | validateItemUnique(null, createReqVO.getItemId()); |
| | | warehouseAreaService.validateWarehouseAreaExists(createReqVO.getWarehouseId(), |
| | | createReqVO.getLocationId(), createReqVO.getAreaId()); |
| | | |
| | | // 2. 插入 |
| | | MesProRouteProductDO routeProduct = BeanUtils.toBean(createReqVO, MesProRouteProductDO.class); |
| | |
| | | // 1.0 已启用的工艺路线,不允许操作 |
| | | routeService.validateRouteNotEnable(updateReqVO.getRouteId()); |
| | | // 1.1 校验存在 |
| | | validateRouteProductExists(updateReqVO.getId()); |
| | | // 1.2 校验产品唯一性 |
| | | MesProRouteProductDO existing = routeProductMapper.selectById(updateReqVO.getId()); |
| | | validateRouteProductExists(existing); |
| | | // 历史路线产品可能采用旧分类;只修改仓位等配置时不重新拦截原有物料。 |
| | | if (ObjUtil.notEqual(existing.getItemId(), updateReqVO.getItemId())) { |
| | | validateProductItem(updateReqVO.getItemId()); |
| | | } |
| | | // 1.3 校验产品唯一性 |
| | | validateItemUnique(updateReqVO.getId(), updateReqVO.getItemId()); |
| | | warehouseAreaService.validateWarehouseAreaExists(updateReqVO.getWarehouseId(), |
| | | updateReqVO.getLocationId(), updateReqVO.getAreaId()); |
| | | |
| | | // 2. 更新 |
| | | MesProRouteProductDO updateObj = BeanUtils.toBean(updateReqVO, MesProRouteProductDO.class); |
| | |
| | | } |
| | | } |
| | | |
| | | private void validateProductItem(Long itemId) { |
| | | MesMdItemDO item = itemService.validateItemExistsAndEnable(itemId); |
| | | Long typeId = item.getItemTypeId(); |
| | | Set<Long> visited = new HashSet<>(); |
| | | while (typeId != null && !MesMdItemTypeDO.PARENT_ID_ROOT.equals(typeId) && visited.add(typeId)) { |
| | | MesMdItemTypeDO itemType = itemTypeService.getItemType(typeId); |
| | | if (itemType == null) { |
| | | break; |
| | | } |
| | | // 兼容旧分类:可能未设置 PRODUCT 标识,也未采用 FG/SF 编码。 |
| | | if (MesMdItemTypeEnum.isProduct(itemType.getItemOrProduct()) |
| | | || "FG".equalsIgnoreCase(itemType.getCode()) |
| | | || "SF".equalsIgnoreCase(itemType.getCode()) |
| | | || isProductCategoryName(itemType.getName())) { |
| | | return; |
| | | } |
| | | typeId = itemType.getParentId(); |
| | | } |
| | | // MES 兼容分类可能仍标记为 ITEM;以 MDM 物料主数据的成品/半成品类型兜底。 |
| | | CommonResult<MdmItemRespDTO> mdmResult = mdmItemApi.getItemByCode(item.getCode()); |
| | | if (mdmResult != null && mdmResult.isSuccess() && mdmResult.getData() != null) { |
| | | MdmItemRespDTO mdmItem = mdmResult.getData(); |
| | | Integer mdmType = mdmItem.getItemType(); |
| | | // 历史同步曾将分类 ID 写入 itemType;与 categoryId 相同的值不能当作类型枚举。 |
| | | if (!Objects.equals(mdmItem.getCategoryId(), mdmType == null ? null : mdmType.longValue()) |
| | | && (MdmItemTypeEnum.PRODUCT.getType().equals(mdmType) |
| | | || MdmItemTypeEnum.SEMI_FINISHED.getType().equals(mdmType))) { |
| | | return; |
| | | } |
| | | } |
| | | throw exception(PRO_ROUTE_PRODUCT_ITEM_TYPE_INVALID, item.getName()); |
| | | } |
| | | |
| | | private boolean isProductCategoryName(String name) { |
| | | return name != null && (name.contains("半成品") || name.contains("产成品") |
| | | || (name.contains("成品") && !name.contains("非成品"))); |
| | | } |
| | | |
| | | private void validateItemUnique(Long id, Long itemId) { |
| | | MesProRouteProductDO existing = routeProductMapper.selectByItemId(itemId); |
| | | if (existing == null) { |