| | |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| | | 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.framework.mybatis.core.mapper.BaseMapperX; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemImportExcelVO; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemImportReqVO; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemImportRespVO; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemPageReqVO; |
| | | import cn.iocoder.yudao.module.mdm.controller.admin.item.vo.MdmItemSaveReqVO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.brand.MdmBrandDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.category.MdmItemCategoryDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemBatchConfigDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.item.MdmItemDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.dataobject.unit.MdmUnitMeasureDO; |
| | | import cn.iocoder.yudao.module.mdm.dal.mysql.brand.MdmBrandMapper; |
| | | import cn.iocoder.yudao.module.mdm.dal.mysql.category.MdmItemCategoryMapper; |
| | | import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemBatchConfigMapper; |
| | | import cn.iocoder.yudao.module.mdm.dal.mysql.item.MdmItemMapper; |
| | | import cn.iocoder.yudao.module.mdm.dal.mysql.unit.MdmUnitMeasureMapper; |
| | | import cn.iocoder.yudao.module.mdm.service.brand.MdmBrandService; |
| | | import cn.iocoder.yudao.module.mdm.service.category.MdmItemCategoryService; |
| | | import cn.iocoder.yudao.module.mdm.service.unit.MdmUnitMeasureService; |
| | | import cn.iocoder.yudao.module.mes.api.item.MesMdItemApi; |
| | | import cn.iocoder.yudao.module.mes.api.item.MesMdItemTypeApi; |
| | | import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemSyncReqDTO; |
| | | import cn.iocoder.yudao.module.mes.api.item.dto.MesMdItemTypeRespDTO; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import jakarta.annotation.Resource; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.context.annotation.Lazy; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| | | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; |
| | | import static cn.iocoder.yudao.module.mdm.enums.ErrorCodeConstants.*; |
| | | |
| | | /** |
| | | * MDM 物料主数据 Service 实现类 |
| | | * |
| | | * @author 芋道源码 |
| | | * @author 超级管理员 |
| | | */ |
| | | @Service |
| | | @Validated |
| | |
| | | private MdmBrandService brandService; |
| | | |
| | | @Resource |
| | | private MdmItemCategoryMapper itemCategoryMapper; |
| | | @Resource |
| | | private MdmUnitMeasureMapper unitMeasureMapper; |
| | | @Resource |
| | | private MdmBrandMapper brandMapper; |
| | | |
| | | @Resource |
| | | @Lazy |
| | | private MesMdItemApi mesMdItemApi; |
| | | @Resource |
| | | private MdmItemBatchConfigMapper itemBatchConfigMapper; |
| | | |
| | | @Resource |
| | | private MesMdItemTypeApi mesMdItemTypeApi; |
| | | |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | // 保存批次配置(如果有) |
| | | saveBatchConfig(item.getId(), createReqVO); |
| | | |
| | | // 同步到 MES(勾选 syncMes 时) |
| | | createReqVO.setId(item.getId()); |
| | | // 勾选同步时,同步到 MES |
| | | if (Boolean.TRUE.equals(createReqVO.getSyncMes())) { |
| | | createReqVO.setId(item.getId()); |
| | | syncItemToMes(createReqVO); |
| | | } |
| | | return item.getId(); |
| | |
| | | // 保存批次配置(如果有) |
| | | saveBatchConfig(updateReqVO.getId(), updateReqVO); |
| | | |
| | | // 同步到 MES(勾选 syncMes 时) |
| | | // 根据同步开关决定:打开则同步到 MES,关闭则取消同步(从 MES 删除) |
| | | if (Boolean.TRUE.equals(updateReqVO.getSyncMes())) { |
| | | syncItemToMes(updateReqVO); |
| | | } else { |
| | | mesMdItemApi.deleteItem(updateReqVO.getId()); |
| | | } |
| | | } |
| | | |
| | |
| | | // 解析分类 id -> code(使用 MDM 本地分类服务) |
| | | String itemTypeCode = null; |
| | | if (reqVO.getCategoryId() != null) { |
| | | CommonResult<MesMdItemTypeRespDTO> itemType = mesMdItemTypeApi.getItemType(reqVO.getCategoryId()); |
| | | itemTypeCode = itemType.getData().getCode(); |
| | | MdmItemCategoryDO category = itemCategoryService.getItemCategory(reqVO.getCategoryId()); |
| | | if (category == null) { |
| | | throw exception(MDM_ITEM_CATEGORY_NOT_EXISTS); |
| | | } |
| | | itemTypeCode = category.getCode(); |
| | | } |
| | | // 组装同步 DTO |
| | | MesMdItemSyncReqDTO syncReqDTO = new MesMdItemSyncReqDTO(); |
| | |
| | | syncReqDTO.setMaxStock(reqVO.getMaxStock()); |
| | | syncReqDTO.setHighValue(reqVO.getIsHighValue()); |
| | | syncReqDTO.setBatchFlag(reqVO.getIsBatchManaged()); |
| | | syncReqDTO.setStatus(reqVO.getStatus()); |
| | | syncReqDTO.setRemark(reqVO.getRemark()); |
| | | // 批次配置字段 |
| | | syncReqDTO.setProduceDateFlag(reqVO.getProduceDateFlag()); |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateItemStatus(Long id, Integer status) { |
| | | // 校验存在 |
| | | validateItemExists(id); |
| | | // 更新状态 |
| | | itemMapper.updateById(new MdmItemDO().setId(id).setStatus(status)); |
| | | // 同步状态到 MES |
| | | mesMdItemApi.updateItemStatus(id, status); |
| | | } |
| | | |
| | | @Override |
| | |
| | | validateItemNoReference(id); |
| | | // 软删除当前记录 |
| | | itemMapper.deleteById(id); |
| | | // 同步删除到 MES |
| | | mesMdItemApi.deleteItem(id); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateItemSync(Long id, Boolean sync) { |
| | | // 校验存在 |
| | | MdmItemDO item = validateItemExists(id); |
| | | if (Boolean.TRUE.equals(sync)) { |
| | | // 同步到 MES:从 DB 读取完整物料数据组装后走 syncItemToMes |
| | | MdmItemSaveReqVO reqVO = BeanUtils.toBean(item, MdmItemSaveReqVO.class); |
| | | // DO 字段名为 highValue,与 VO 的 isHighValue 不自动匹配,手动补齐 |
| | | reqVO.setIsHighValue(item.getHighValue()); |
| | | // 补齐批次属性配置 |
| | | MdmItemBatchConfigDO config = itemBatchConfigMapper.selectOne( |
| | | MdmItemBatchConfigDO::getItemId, id); |
| | | if (config != null) { |
| | | reqVO.setProduceDateFlag(config.getProduceDateFlag()); |
| | | reqVO.setExpireDateFlag(config.getExpireDateFlag()); |
| | | reqVO.setReceiptDateFlag(config.getReceiptDateFlag()); |
| | | reqVO.setVendorFlag(config.getVendorFlag()); |
| | | reqVO.setPurchaseOrderCodeFlag(config.getPurchaseOrderCodeFlag()); |
| | | reqVO.setLotNumberFlag(config.getLotNumberFlag()); |
| | | reqVO.setQualityStatusFlag(config.getQualityStatusFlag()); |
| | | } |
| | | syncItemToMes(reqVO); |
| | | } else { |
| | | // 取消同步:从 MES 删除该物料(MES 无此物料时内部为空操作) |
| | | mesMdItemApi.deleteItem(id); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | // 逐个删除(复用单条删除逻辑,保持校验) |
| | | ids.forEach(this::deleteItem); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MdmItemImportRespVO importItemList(List<MdmItemImportExcelVO> importItems, |
| | | MdmItemImportReqVO importReqVO) { |
| | | // 1. 校验非空(以物料编码作为导入主键) |
| | | importItems = filterList(importItems, item -> StrUtil.isNotBlank(item.getCode())); |
| | | if (CollUtil.isEmpty(importItems)) { |
| | | throw exception(MDM_ITEM_IMPORT_LIST_IS_EMPTY); |
| | | } |
| | | |
| | | // 2. 逐条处理 |
| | | MdmItemImportRespVO respVO = MdmItemImportRespVO.builder() |
| | | .createItemCodes(new ArrayList<>()) |
| | | .updateItemCodes(new ArrayList<>()) |
| | | .failureItemCodes(new LinkedHashMap<>()) |
| | | .build(); |
| | | importItems.forEach(importItem -> { |
| | | try { |
| | | // 2.1 解析外键:分类 / 主单位 / 辅单位 / 品牌(按名称解析) |
| | | Long categoryId = resolveCategoryId(importItem.getCategoryName()); |
| | | Long unitMeasureId = resolveUnitMeasureId(importItem.getUnitMeasureName()); |
| | | Long unitMeasureId2 = resolveUnitMeasureId(importItem.getUnitMeasureName2()); |
| | | Long unitMeasureId3 = resolveUnitMeasureId(importItem.getUnitMeasureName3()); |
| | | Long brandId = resolveBrandId(importItem.getBrandName()); |
| | | // 2.2 判断是否存在(按编码唯一) |
| | | MdmItemDO existItem = itemMapper.selectByCode(importItem.getCode()); |
| | | if (existItem == null) { |
| | | // 2.2.1 新增 |
| | | MdmItemDO item = BeanUtils.toBean(importItem, MdmItemDO.class) |
| | | .setCategoryId(categoryId) |
| | | .setUnitMeasureId(unitMeasureId) |
| | | .setUnitMeasureId2(unitMeasureId2) |
| | | .setUnitMeasureId3(unitMeasureId3) |
| | | .setBrandId(brandId); |
| | | if (item.getStatus() == null) { |
| | | item.setStatus(CommonStatusEnum.ENABLE.getStatus()); |
| | | } |
| | | itemMapper.insert(item); |
| | | respVO.getCreateItemCodes().add(importItem.getCode()); |
| | | return; |
| | | } |
| | | // 2.2.2 已存在,判断是否允许更新 |
| | | if (!importReqVO.getUpdateSupport()) { |
| | | respVO.getFailureItemCodes().put(importItem.getCode(), |
| | | StrUtil.format(MDM_ITEM_CODE_EXISTS.getMsg(), importItem.getCode())); |
| | | return; |
| | | } |
| | | MdmItemDO updateItem = BeanUtils.toBean(importItem, MdmItemDO.class) |
| | | .setId(existItem.getId()) |
| | | .setCategoryId(categoryId) |
| | | .setUnitMeasureId(unitMeasureId) |
| | | .setUnitMeasureId2(unitMeasureId2) |
| | | .setUnitMeasureId3(unitMeasureId3) |
| | | .setBrandId(brandId); |
| | | itemMapper.updateById(updateItem); |
| | | respVO.getUpdateItemCodes().add(importItem.getCode()); |
| | | } catch (ServiceException ex) { |
| | | respVO.getFailureItemCodes().put(importItem.getCode(), ex.getMessage()); |
| | | } |
| | | }); |
| | | return respVO; |
| | | } |
| | | |
| | | /** |
| | | * 按名称解析物料分类编号 |
| | | */ |
| | | private Long resolveCategoryId(String categoryName) { |
| | | if (StrUtil.isBlank(categoryName)) { |
| | | return null; |
| | | } |
| | | MdmItemCategoryDO category = itemCategoryMapper.selectByName(categoryName); |
| | | if (category == null) { |
| | | throw exception(MDM_ITEM_IMPORT_CATEGORY_NOT_EXISTS, categoryName); |
| | | } |
| | | return category.getId(); |
| | | } |
| | | |
| | | /** |
| | | * 按名称解析计量单位编号 |
| | | */ |
| | | private Long resolveUnitMeasureId(String unitMeasureName) { |
| | | if (StrUtil.isBlank(unitMeasureName)) { |
| | | return null; |
| | | } |
| | | MdmUnitMeasureDO unitMeasure = unitMeasureMapper.selectByName(unitMeasureName); |
| | | if (unitMeasure == null) { |
| | | throw exception(MDM_ITEM_IMPORT_UNIT_NOT_EXISTS, unitMeasureName); |
| | | } |
| | | return unitMeasure.getId(); |
| | | } |
| | | |
| | | /** |
| | | * 按名称解析品牌编号 |
| | | */ |
| | | private Long resolveBrandId(String brandName) { |
| | | if (StrUtil.isBlank(brandName)) { |
| | | return null; |
| | | } |
| | | MdmBrandDO brand = brandMapper.selectByName(brandName); |
| | | if (brand == null) { |
| | | throw exception(MDM_ITEM_IMPORT_BRAND_NOT_EXISTS, brandName); |
| | | } |
| | | return brand.getId(); |
| | | } |
| | | |
| | | @Override |
| | |
| | | return itemMapper.selectByCode(code); |
| | | } |
| | | |
| | | @Override |
| | | public List<MdmItemDO> getItemSimpleList() { |
| | | return itemMapper.selectList(MdmItemDO::getStatus, |
| | | cn.iocoder.yudao.framework.common.enums.CommonStatusEnum.ENABLE.getStatus()); |
| | | } |
| | | |
| | | /** |
| | | * 保存批次配置(到 MDM 本地表) |
| | | */ |
| | |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |