| | |
| | | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; |
| | | import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemImportExcelVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemImportRespVO; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemPageReqVO; |
| | |
| | | import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; |
| | | import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService; |
| | | import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService; |
| | | import cn.iocoder.yudao.module.mdm.api.item.MdmItemSyncApi; |
| | | import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemSyncReqDTO; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | /** |
| | | * MES 物料产品 Service 实现类 |
| | | * |
| | | * 改造说明:MES 物料主数据来源于 MDM |
| | | * - getItem/getItemList/validateItemExists 调用 MDM API |
| | | * - MES 特有配置(批次配置、BOM、SOP、SIP)保留在 MES 模块管理 |
| | | * 支持 MES 和 MDM 物料数据双向同步 |
| | | * |
| | | * @author 芋道源码 |
| | | */ |
| | |
| | | |
| | | @Resource |
| | | private MesMdItemMapper itemMapper; |
| | | |
| | | @Resource |
| | | private MdmItemApi mdmItemApi; |
| | | |
| | | @Resource |
| | | private MesMdItemTypeService itemTypeService; |
| | |
| | | @Resource |
| | | private MesMdAutoCodeRecordService autoCodeRecordService; |
| | | |
| | | @Resource |
| | | private MdmItemSyncApi mdmItemSyncApi; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createItem(MesMdItemSaveReqVO createReqVO) { |
| | | // 校验数据 |
| | | validateItemSaveData(createReqVO); |
| | |
| | | // 自动生成条码 |
| | | barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.ITEM.getValue(), |
| | | item.getId(), item.getCode(), item.getName()); |
| | | |
| | | // 同步到 MDM(勾选 syncMdm 时) |
| | | if (Boolean.TRUE.equals(createReqVO.getSyncMdm())) { |
| | | syncItemToMdm(item, createReqVO); |
| | | } |
| | | |
| | | return item.getId(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateItem(MesMdItemSaveReqVO updateReqVO) { |
| | | // 校验存在 |
| | | validateItemExists(updateReqVO.getId()); |
| | |
| | | MesMdItemDO updateObj = BeanUtils.toBean(updateReqVO, MesMdItemDO.class); |
| | | clearStockIfNotSafe(updateObj); // 如果未启用安全库存,清零库存上下限 |
| | | itemMapper.updateById(updateObj); |
| | | |
| | | // 同步到 MDM(勾选 syncMdm 时) |
| | | if (Boolean.TRUE.equals(updateReqVO.getSyncMdm())) { |
| | | MesMdItemDO item = itemMapper.selectById(updateReqVO.getId()); |
| | | syncItemToMdm(item, updateReqVO); |
| | | } |
| | | } |
| | | |
| | | private void validateItemSaveData(MesMdItemSaveReqVO reqVO) { |
| | |
| | | |
| | | @Override |
| | | public MesMdItemDO validateItemExists(Long id) { |
| | | MdmItemRespDTO item = mdmItemApi.validateItemExists(id).getCheckedData(); |
| | | return BeanUtils.toBean(item, MesMdItemDO.class); |
| | | MesMdItemDO item = itemMapper.selectById(id); |
| | | if (item == null) { |
| | | throw exception(MD_ITEM_NOT_EXISTS); |
| | | } |
| | | return item; |
| | | } |
| | | |
| | | @Override |
| | | public MesMdItemDO validateItemExistsAndEnable(Long id) { |
| | | MdmItemRespDTO item = mdmItemApi.validateItemExistsAndEnable(id).getCheckedData(); |
| | | return BeanUtils.toBean(item, MesMdItemDO.class); |
| | | MesMdItemDO item = validateItemExists(id); |
| | | if (ObjUtil.notEqual(CommonStatusEnum.ENABLE.getStatus(), item.getStatus())) { |
| | | throw exception(MD_ITEM_IS_DISABLE); |
| | | } |
| | | return item; |
| | | } |
| | | |
| | | private void validateItemCodeUnique(Long id, String code) { |
| | |
| | | |
| | | @Override |
| | | public MesMdItemDO getItem(Long id) { |
| | | // 从 MDM 获取物料主数据 |
| | | MdmItemRespDTO item = mdmItemApi.getItem(id).getCheckedData(); |
| | | return BeanUtils.toBean(item, MesMdItemDO.class); |
| | | return itemMapper.selectById(id); |
| | | } |
| | | |
| | | @Override |
| | | public MesMdItemDO getItemByCode(String code) { |
| | | return itemMapper.selectByCode(code); |
| | | } |
| | | |
| | | @Override |
| | | public PageResult<MesMdItemDO> getItemPage(MesMdItemPageReqVO pageReqVO) { |
| | | // 调用 MDM API 分页查询(MES 物料对应 MDM 物料类型=物料) |
| | | cn.iocoder.yudao.framework.common.pojo.PageResult<MdmItemRespDTO> mdmPageResult = |
| | | mdmItemApi.getItemPage(1, pageReqVO.getStatus(), pageReqVO.getPageNo(), pageReqVO.getPageSize()).getCheckedData(); |
| | | List<MesMdItemDO> itemList = BeanUtils.toBean(mdmPageResult.getList(), MesMdItemDO.class); |
| | | return new PageResult<>(itemList, mdmPageResult.getTotal()); |
| | | // 查找时,如果查找某个分类编号,则包含它的子分类 |
| | | Set<Long> itemTypeIds = null; |
| | | if (pageReqVO.getItemTypeId() != null) { |
| | | itemTypeIds = new HashSet<>(); |
| | | itemTypeIds.add(pageReqVO.getItemTypeId()); |
| | | List<MesMdItemTypeDO> children = itemTypeService.getItemTypeChildrenList(pageReqVO.getItemTypeId()); |
| | | itemTypeIds.addAll(convertSet(children, MesMdItemTypeDO::getId)); |
| | | } |
| | | // 分页查询 |
| | | return itemMapper.selectPage(pageReqVO, itemTypeIds); |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (CollUtil.isEmpty(ids)) { |
| | | return Collections.emptyList(); |
| | | } |
| | | List<MdmItemRespDTO> itemList = mdmItemApi.getItemList(ids).getCheckedData(); |
| | | return BeanUtils.toBean(itemList, MesMdItemDO.class); |
| | | return itemMapper.selectByIds(ids); |
| | | } |
| | | |
| | | @Override |
| | | public Long getItemCountByItemTypeId(Long itemTypeId) { |
| | | // MES 分类需要映射到 MDM 分类 |
| | | return mdmItemApi.getItemCountByCategoryId(itemTypeId).getCheckedData(); |
| | | return itemMapper.selectCountByItemTypeId(itemTypeId); |
| | | } |
| | | |
| | | @Override |
| | | public Long getItemCountByUnitMeasureId(Long unitMeasureId) { |
| | | return mdmItemApi.getItemCountByUnitMeasureId(unitMeasureId).getCheckedData(); |
| | | return itemMapper.selectCountByUnitMeasureId(unitMeasureId); |
| | | } |
| | | |
| | | @Override |
| | |
| | | return respVO; |
| | | } |
| | | |
| | | } |
| | | /** |
| | | * 同步物料到 MDM |
| | | * |
| | | * @param item MES 物料数据 |
| | | * @param saveReqVO 保存请求(包含批次配置) |
| | | */ |
| | | private void syncItemToMdm(MesMdItemDO item, MesMdItemSaveReqVO saveReqVO) { |
| | | // 1. 获取物料类型对应的 itemType |
| | | Long itemType = null; |
| | | if (item.getItemTypeId() != null) { |
| | | MesMdItemTypeDO itemTypeDO = itemTypeService.getItemType(item.getItemTypeId()); |
| | | if (itemTypeDO != null) { |
| | | // MES: ITEM=物料, PRODUCT=产品 -> MDM: 1=原料, 2=半成品, 3=成品, 4=辅料 |
| | | // itemType = convertMesItemTypeToMdm(itemTypeDO.getItemOrProduct(), itemTypeDO.getName()); |
| | | itemType = itemTypeDO.getId(); |
| | | } |
| | | } |
| | | |
| | | // 2. 获取计量单位编码 |
| | | String unitCode = null; |
| | | Long unitMeasureId = null; |
| | | if (item.getUnitMeasureId() != null) { |
| | | MesMdUnitMeasureDO unitMeasure = unitMeasureService.getUnitMeasure(item.getUnitMeasureId()); |
| | | if (unitMeasure != null) { |
| | | unitCode = unitMeasure.getCode(); |
| | | } |
| | | unitMeasureId = item.getUnitMeasureId(); |
| | | } |
| | | |
| | | // 3. 获取批次配置 |
| | | MesMdItemBatchConfigDO batchConfig = itemBatchConfigService.getItemBatchConfigByItemId(item.getId()); |
| | | |
| | | // 4. 组装同步 DTO |
| | | MdmItemSyncReqDTO syncReqDTO = new MdmItemSyncReqDTO(); |
| | | syncReqDTO.setCode(item.getCode()); |
| | | syncReqDTO.setName(item.getName()); |
| | | syncReqDTO.setSpecification(item.getSpecification()); |
| | | syncReqDTO.setItemType(itemType); |
| | | syncReqDTO.setUnitMeasureId(unitMeasureId); |
| | | syncReqDTO.setCategoryId(item.getItemTypeId()); |
| | | syncReqDTO.setStatus(item.getStatus()); |
| | | syncReqDTO.setMinStock(item.getMinStock()); |
| | | syncReqDTO.setMaxStock(item.getMaxStock()); |
| | | syncReqDTO.setIsBatchManaged(item.getBatchFlag()); |
| | | syncReqDTO.setIsHighValue(item.getHighValue()); |
| | | syncReqDTO.setRemark(item.getRemark()); |
| | | |
| | | // 5. 同步批次配置 |
| | | if (batchConfig != null) { |
| | | syncReqDTO.setProduceDateFlag(batchConfig.getProduceDateFlag()); |
| | | syncReqDTO.setExpireDateFlag(batchConfig.getExpireDateFlag()); |
| | | syncReqDTO.setReceiptDateFlag(batchConfig.getReceiptDateFlag()); |
| | | syncReqDTO.setVendorFlag(batchConfig.getVendorFlag()); |
| | | syncReqDTO.setPurchaseOrderCodeFlag(batchConfig.getPurchaseOrderCodeFlag()); |
| | | syncReqDTO.setLotNumberFlag(batchConfig.getLotNumberFlag()); |
| | | syncReqDTO.setQualityStatusFlag(batchConfig.getQualityStatusFlag()); |
| | | } |
| | | |
| | | // 6. 调用 MDM 同步 API |
| | | mdmItemSyncApi.syncItemToMdm(syncReqDTO); |
| | | } |
| | | |
| | | /** |
| | | * 将 MES 物料类型转换为 MDM 物料类型 |
| | | * MES: ITEM(物料)/PRODUCT(产品) |
| | | * MDM: 1原料, 2半成品, 3成品, 4辅料 |
| | | */ |
| | | private Integer convertMesItemTypeToMdm(String itemOrProduct, String typeName) { |
| | | if (itemOrProduct == null) { |
| | | return null; |
| | | } |
| | | // 根据名称匹配 |
| | | if (typeName != null) { |
| | | if (typeName.contains("原料")) { |
| | | return 1; |
| | | } else if (typeName.contains("半成品")) { |
| | | return 2; |
| | | } else if (typeName.contains("成品")) { |
| | | return 3; |
| | | } else if (typeName.contains("辅料")) { |
| | | return 4; |
| | | } |
| | | } |
| | | // 根据 ITEM/PRODUCT 兜底 |
| | | if ("PRODUCT".equals(itemOrProduct)) { |
| | | return 3; // 产品 -> 成品 |
| | | } |
| | | return 1; // 默认原料 |
| | | } |
| | | |
| | | } |