| | |
| | | |
| | | import cn.hutool.core.collection.CollUtil; |
| | | import cn.hutool.core.util.ObjUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| | | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| | | 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.controller.admin.md.item.vo.MesMdItemSaveReqVO; |
| | | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| | |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; |
| | | import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; |
| | | import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdItemMapper; |
| | | import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.type.MesMdItemTypeListReqVO; |
| | | import cn.iocoder.yudao.module.mes.enums.md.MesMdItemTypeEnum; |
| | | |
| | | import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum; |
| | |
| | | * |
| | | * 支持 MES 和 MDM 物料数据双向同步 |
| | | * |
| | | * @author 芋道源码 |
| | | * @author 超级管理员 |
| | | */ |
| | | @Service |
| | | @Validated |
| | |
| | | updateItem(createReqVO); |
| | | return createReqVO.getId(); |
| | | } |
| | | // 存在逻辑删除记录(取消同步后重新同步):恢复该记录后走更新,避免主键冲突 |
| | | if (itemMapper.selectAnyById(createReqVO.getId()) != null) { |
| | | itemMapper.restoreById(createReqVO.getId()); |
| | | updateItem(createReqVO); |
| | | return createReqVO.getId(); |
| | | } |
| | | } |
| | | |
| | | // 插入 |
| | | MesMdItemDO item = BeanUtils.toBean(createReqVO, MesMdItemDO.class); |
| | | item.setStatus(CommonStatusEnum.DISABLE.getStatus()); // 默认禁用。信息完成后,再启用 |
| | | // 状态只能由基础数据(MDM)控制:MDM 同步时沿用其状态;MES 本地新增默认禁用 |
| | | item.setStatus(createReqVO.getMdmItemId() != null && createReqVO.getStatus() != null |
| | | ? createReqVO.getStatus() : CommonStatusEnum.DISABLE.getStatus()); |
| | | clearStockIfNotSafe(item); // 如果未启用安全库存,清零库存上下限 |
| | | itemMapper.insert(item); |
| | | |
| | |
| | | // 更新 |
| | | MesMdItemDO updateObj = BeanUtils.toBean(updateReqVO, MesMdItemDO.class); |
| | | clearStockIfNotSafe(updateObj); // 如果未启用安全库存,清零库存上下限 |
| | | // 状态只能由基础数据(MDM)控制,MES 本地更新不允许修改状态 |
| | | if (updateReqVO.getMdmItemId() == null) { |
| | | updateObj.setStatus(null); |
| | | } |
| | | itemMapper.updateById(updateObj); |
| | | |
| | | // 同步到 MDM(勾选 syncMdm 时) |
| | |
| | | private void validateItemSaveData(MesMdItemSaveReqVO reqVO) { |
| | | // 校验物料编码的唯一性 |
| | | validateItemCodeUnique(reqVO.getId(), reqVO.getCode()); |
| | | // 校验物料名称的唯一性 |
| | | validateItemNameUnique(reqVO.getId(), reqVO.getName()); |
| | | // 不再校验物料名称的唯一性:允许同名不同编码的物料(与 MDM 物料规则保持一致) |
| | | // 校验物料分类存在 |
| | | validateItemTypeExists(reqVO.getItemTypeId()); |
| | | // 校验计量单位存在 |
| | |
| | | } |
| | | if (ObjUtil.notEqual(item.getId(), id)) { |
| | | throw exception(MD_ITEM_CODE_DUPLICATE); |
| | | } |
| | | } |
| | | |
| | | private void validateItemNameUnique(Long id, String name) { |
| | | MesMdItemDO item = itemMapper.selectByName(name); |
| | | if (item == null) { |
| | | return; |
| | | } |
| | | if (ObjUtil.notEqual(item.getId(), id)) { |
| | | throw exception(MD_ITEM_NAME_DUPLICATE); |
| | | } |
| | | } |
| | | |
| | |
| | | return item; |
| | | } |
| | | |
| | | } |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public MesMdItemImportRespVO importItemList(List<MesMdItemImportExcelVO> importList, Boolean updateSupport) { |
| | | MesMdItemImportRespVO respVO = MesMdItemImportRespVO.empty(); |
| | | if (CollUtil.isEmpty(importList)) { |
| | | return respVO; |
| | | } |
| | | // 预加载计量单位、物料分类,按名称建索引,避免逐行查库 |
| | | Map<String, Long> unitMeasureMap = new HashMap<>(); |
| | | unitMeasureService.getUnitMeasureListByStatus(CommonStatusEnum.ENABLE.getStatus()) |
| | | .forEach(unit -> unitMeasureMap.put(unit.getName().trim(), unit.getId())); |
| | | Map<String, Long> itemTypeMap = new HashMap<>(); |
| | | itemTypeService.getItemTypeList(new MesMdItemTypeListReqVO()) |
| | | .forEach(type -> itemTypeMap.put(type.getName().trim(), type.getId())); |
| | | |
| | | int index = 0; |
| | | for (MesMdItemImportExcelVO row : importList) { |
| | | index++; |
| | | String key = StrUtil.isNotBlank(row.getCode()) ? row.getCode().trim() : "第 " + index + " 行"; |
| | | // 1. 基础校验 |
| | | if (StrUtil.isBlank(row.getCode())) { |
| | | respVO.getFailureCodes().put(key, "物料编码不能为空"); |
| | | continue; |
| | | } |
| | | if (StrUtil.isBlank(row.getName())) { |
| | | respVO.getFailureCodes().put(key, "物料名称不能为空"); |
| | | continue; |
| | | } |
| | | String code = row.getCode().trim(); |
| | | String unitName = StrUtil.trim(row.getUnitMeasureName()); |
| | | Long unitMeasureId = unitName == null ? null : unitMeasureMap.get(unitName); |
| | | if (unitMeasureId == null) { |
| | | respVO.getFailureCodes().put(key, "计量单位[" + unitName + "]不存在"); |
| | | continue; |
| | | } |
| | | String typeName = StrUtil.trim(row.getItemTypeName()); |
| | | Long itemTypeId = typeName == null ? null : itemTypeMap.get(typeName); |
| | | if (itemTypeId == null) { |
| | | respVO.getFailureCodes().put(key, "物料分类[" + typeName + "]不存在"); |
| | | continue; |
| | | } |
| | | |
| | | // 2. 组装保存对象(颜色一并写入) |
| | | MesMdItemSaveReqVO saveReqVO = new MesMdItemSaveReqVO(); |
| | | saveReqVO.setCode(code); |
| | | saveReqVO.setName(row.getName().trim()); |
| | | saveReqVO.setSpecification(StrUtil.trim(row.getSpecification())); |
| | | saveReqVO.setColor(StrUtil.trim(row.getColor())); |
| | | saveReqVO.setUnitMeasureId(unitMeasureId); |
| | | saveReqVO.setItemTypeId(itemTypeId); |
| | | saveReqVO.setSafeStockFlag(row.getSafeStockFlag()); |
| | | saveReqVO.setMinStock(row.getMinStock()); |
| | | saveReqVO.setMaxStock(row.getMaxStock()); |
| | | saveReqVO.setHighValue(row.getHighValue()); |
| | | saveReqVO.setBatchFlag(row.getBatchFlag()); |
| | | saveReqVO.setRemark(StrUtil.trim(row.getRemark())); |
| | | |
| | | // 3. 新增或更新,单行失败不影响整批 |
| | | MesMdItemDO existItem = itemMapper.selectByCode(code); |
| | | try { |
| | | if (existItem == null) { |
| | | createItem(saveReqVO); |
| | | respVO.getCreateCodes().add(code); |
| | | } else if (!Boolean.TRUE.equals(updateSupport)) { |
| | | respVO.getFailureCodes().put(key, "物料编码已存在(勾选「是否覆盖」可更新)"); |
| | | } else { |
| | | saveReqVO.setId(existItem.getId()); |
| | | saveReqVO.setMdmItemId(existItem.getMdmItemId()); |
| | | updateItem(saveReqVO); |
| | | respVO.getUpdateCodes().add(code); |
| | | } |
| | | } catch (Exception e) { |
| | | respVO.getFailureCodes().put(key, e.getMessage() == null ? "导入失败" : e.getMessage()); |
| | | } |
| | | } |
| | | return respVO; |
| | | } |
| | | |
| | | } |