ソースを参照

pms 同步SAP库存 添加未关联组织部门的 SAP工厂 库存地点

zhangcl 3 週間 前
コミット
1105a8a6d7

+ 6 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsapstock/vo/IotSapStockPageReqVO.java

@@ -21,12 +21,18 @@ public class IotSapStockPageReqVO extends PageParam {
     @Schema(description = "组织部门id", example = "10123")
     private Long deptId;
 
+    @Schema(description = "工厂(SAP) 专业公司 sap code")
+    private String factoryCode;
+
     @Schema(description = "工厂id (system_sap_org表id)", example = "10123")
     private Long factoryId;
 
     @Schema(description = "工厂(SAP) 专业公司")
     private String factory;
 
+    @Schema(description = "库存地点 sap code", example = "10123")
+    private String storageLocationCode;
+
     @Schema(description = "库存地点id", example = "10123")
     private Long storageLocationId;
 

+ 8 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsapstock/vo/IotSapStockRespVO.java

@@ -21,6 +21,10 @@ public class IotSapStockRespVO {
     @ExcelProperty("组织部门id")
     private Long deptId;
 
+    @Schema(description = "工厂(SAP) 专业公司 sap code")
+    @ExcelProperty("工厂(SAP) 专业公司 sap code")
+    private String factoryCode;
+
     @Schema(description = "工厂id (system_sap_org表id)", example = "10123")
     @ExcelProperty("工厂(SAP) 专业公司")
     private Long factoryId;
@@ -29,6 +33,10 @@ public class IotSapStockRespVO {
     @ExcelProperty("工厂(SAP) 专业公司 名称")
     private String factory;
 
+    @Schema(description = "库存地点 sap code", example = "10123")
+    @ExcelProperty("库存地点 sap code")
+    private String storageLocationCode;
+
     @Schema(description = "库存地点id", example = "10123")
     @ExcelProperty("库存地点id")
     private Long storageLocationId;

+ 6 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/iotsapstock/vo/IotSapStockSaveReqVO.java

@@ -16,12 +16,18 @@ public class IotSapStockSaveReqVO {
     @Schema(description = "组织部门id", example = "10123")
     private Long deptId;
 
+    @Schema(description = "工厂 sap code", example = "10123")
+    private String factoryCode;
+
     @Schema(description = "工厂id (system_sap_org表id)", example = "10123")
     private Long factoryId;
 
     @Schema(description = "工厂(SAP) 专业公司")
     private String factory;
 
+    @Schema(description = "库存地点 sap code", example = "10123")
+    private String storageLocationCode;
+
     @Schema(description = "库存地点id", example = "10123")
     private Long storageLocationId;
 

+ 8 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/iotsapstock/IotSapStockDO.java

@@ -33,6 +33,10 @@ public class IotSapStockDO extends BaseDO {
      * 组织部门id
      */
     private Long deptId;
+    /**
+     * 工厂(SAP) 专业公司 SAP code
+     */
+    private String factoryCode;
     /**
      * 工厂id (system_sap_org表id)
      */
@@ -41,6 +45,10 @@ public class IotSapStockDO extends BaseDO {
      * 工厂(SAP) 专业公司
      */
     private String factory;
+    /**
+     * 库存地点 - SAP code
+     */
+    private String storageLocationCode;
     /**
      * 库存地点id
      */

+ 148 - 11
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/service/IotSapServiceImpl.java

@@ -513,13 +513,13 @@ public class IotSapServiceImpl implements IotSapService {
         Map<String, Long> factoryIdPair = new HashMap<>();
         // key工厂code    value工厂名称
         Map<String, String> factoryNamePair = new HashMap<>();
-        // key库存地点code    value库存地点id
+        // key工厂code-库存地点code    value库存地点id
         Map<String, Long> storageLocationIdPair = new HashMap<>();
-        // key库存地点id    value库存地点code
+        // key库存地点id    value工厂code-库存地点code
         Map<Long, String> stockLocationCodeIdPair = new HashMap<>();
         // key库存地点code  value部门id
         Map<String, Long> locationCodeDeptIdPair = new HashMap<>();
-        // key库存地点code    value库存地点名称描述
+        // key工厂code-库存地点code    value库存地点名称描述
         Map<String, String> stockLocationNamePair = new HashMap<>();
         // 工厂集合
         factories.forEach(factory -> {
@@ -530,15 +530,13 @@ public class IotSapServiceImpl implements IotSapService {
         storageLocations.forEach(location -> {
             System.out.println("当前库存地点信息:" + location.getFactoryCode() + " - " + location.getStorageLocationCode());
             String uniqueKey = StrUtil.join("-", location.getFactoryCode(), location.getStorageLocationCode());
-            // stockLocationCodeIdPair.put(location.getId(), location.getStorageLocationCode());
             stockLocationCodeIdPair.put(location.getId(), uniqueKey);
-            // storageLocationIdPair.put(location.getStorageLocationCode(), location.getId());
             storageLocationIdPair.put(uniqueKey, location.getId());
-            // stockLocationNamePair.put(location.getStorageLocationCode(), location.getStorageLocationName());
             stockLocationNamePair.put(uniqueKey, location.getStorageLocationName());
         });
         // 筛选出pms系统中未维护的 库存地点 信息(工厂-库存地点编码)
         Set<String> notExistStorageLocations = new HashSet<>();
+        // 系统中未维护的 工厂 库存地点 也需要存储到数据库 但是 不设置 deptId
         sapStocks.forEach(stock -> {
             String uniqueKey = StrUtil.join("-", stock.getWERKS(), stock.getLGORT());
             if (!storageLocationIdPair.containsKey(uniqueKey)) {
@@ -566,7 +564,7 @@ public class IotSapServiceImpl implements IotSapService {
                 });
             }
         });
-        // 查询所有SAP库存集合A,以 ‘库存地点+物料编码’ 为唯一key 如果 sapStocks 中有物料不在A中 新增物料
+        // 查询所有SAP库存集合A,以 ‘库存地点id+物料编码’ 为唯一key 如果 sapStocks 中有物料不在A中 新增物料
         Set<String> existStockKeys = new HashSet<>();
         List<IotSapStockDO> existStocks = TenantUtils.execute(1L, () -> iotSapStockMapper.selectList());
         if (CollUtil.isNotEmpty(existStocks)) {
@@ -576,6 +574,19 @@ public class IotSapServiceImpl implements IotSapService {
                     .map(stk -> StrUtil.join("-", String.valueOf(stk.getStorageLocationId()), stk.getMaterialCode()))
                     .collect(Collectors.toSet());
         }
+        System.out.println(factoryCode + "当前库中已有sap库存数量:" + existStockKeys.size());
+
+        // todo 没有维护SAP工厂 库存地点的组织 已经存在的库存数据
+        Set<String> noFactoryExistStockKeys = new HashSet<>();
+        if (CollUtil.isNotEmpty(existStocks)) {
+            noFactoryExistStockKeys = existStocks.stream()
+                    // 过滤非空对象和非空code
+                    .filter(stk -> ObjUtil.isNotEmpty(stk) && StrUtil.isNotBlank(stk.getMaterialCode())
+                            && StrUtil.isNotBlank(stk.getFactoryCode()) && StrUtil.isNotBlank(stk.getStorageLocationCode()))
+                    .map(stk -> StrUtil.join("-", stk.getFactoryCode(), stk.getStorageLocationCode(), stk.getMaterialCode()))
+                    .collect(Collectors.toSet());
+        }
+
         // 将已经存在的库存数据 设置成 Map<String, IotSapStockDO> 的形式 便于后续更新
         // key库存地点id-物料编码       value库存对象   从此集合中筛选将要被更新的库存对象
         Map<String, IotSapStockDO> tobeUpdatedStockPair = new HashMap<>();
@@ -588,7 +599,19 @@ public class IotSapServiceImpl implements IotSapService {
                         (existing, replacement) -> existing // 处理键冲突: 保留先出现的元素
                 ));
 
-        System.out.println(factoryCode + "当前库中已有sap库存数量:" + existStockKeys.size());
+        // todo 没有配置SAP 工厂 库存地点 的组织库存更新
+        // 将已经存在的库存数据 设置成 Map<String, IotSapStockDO> 的形式 便于后续更新
+        // key工厂code-库存地点code-物料编码       value库存对象   从此集合中筛选将要被更新的库存对象
+        Map<String, IotSapStockDO> noFactoryTobeUpdatedStockPair = new HashMap<>();
+        noFactoryTobeUpdatedStockPair = existStocks.stream()
+                .filter(stk -> StrUtil.isNotBlank(stk.getMaterialCode()) && StrUtil.isNotBlank(stk.getFactoryCode())
+                        && StrUtil.isNotBlank(stk.getStorageLocationCode()))
+                .collect(Collectors.toMap(
+                        stk -> StrUtil.join("-", stk.getFactoryCode(), stk.getStorageLocationCode(), stk.getMaterialCode()),
+                        stk -> stk, // 值为对象本身
+                        (existing, replacement) -> existing // 处理键冲突: 保留先出现的元素
+                ));
+
         // 找出需要新增的库存(SAP物料编码去掉前导零后,不在现有物料集合中的记录)
         Set<String> finalExistStockKeys = existStockKeys;
         List<IotSapStockVO> newStocks = sapStocks.stream()
@@ -602,7 +625,22 @@ public class IotSapServiceImpl implements IotSapService {
                     return !finalExistStockKeys.contains(StrUtil.join("-", storageLocationId, processedCode));
                 })
                 .collect(Collectors.toList());
+
         System.out.println(factoryCode + "需要新增的sap库存数量:" + newStocks.size());
+
+        // todo 没有维护SAP工厂 库存地点的组织 新增的库存数据
+        // 找出需要新增的库存(SAP物料编码去掉前导零后,不在现有物料集合中的记录)
+        Set<String> noFactoryFinalExistStockKeys = noFactoryExistStockKeys;
+        List<IotSapStockVO> noFactoryNewStocks = sapStocks.stream()
+                .filter(stk -> StrUtil.isNotBlank(stk.getMATNR()) && StrUtil.isNotBlank(stk.getLGORT()) && StrUtil.isNotBlank(stk.getWERKS()))
+                .filter(stk -> {
+                    // 处理前导零:移除MATNR前的 00000000
+                    String processedCode = stk.getMATNR().replaceFirst("^0+", "");
+                    // 本地已经配置过库存地点 包含SAP库存接口返回的库存地点
+                    return !noFactoryFinalExistStockKeys.contains(StrUtil.join("-", stk.getWERKS(), stk.getLGORT(), processedCode));
+                })
+                .collect(Collectors.toList());
+
         // 新增SAP库存数据
         List<IotSapStockDO> tobeAddedStocks = new ArrayList<>();
         if (CollUtil.isNotEmpty(newStocks)) {
@@ -645,6 +683,51 @@ public class IotSapServiceImpl implements IotSapService {
                 }
             });
         }
+
+        // todo 新增 没有配置组织部门的 SAP库存数据
+        List<IotSapStockDO> noFactoryTobeAddedStocks = new ArrayList<>();
+        if (CollUtil.isNotEmpty(noFactoryNewStocks)) {
+            noFactoryNewStocks.forEach(stock -> {
+                // 只保存pms维护过库存地点的数据
+                String uniqueKey = StrUtil.join("-", stock.getWERKS(), stock.getLGORT());
+                IotSapStockDO sapStock = new IotSapStockDO();
+                // 部门统一设置为 科瑞石油技术
+                sapStock.setDeptId(156l);
+                // 工厂id
+                /* if (factoryIdPair.containsKey(stock.getWERKS())) {
+                    sapStock.setFactoryId(factoryIdPair.get(stock.getWERKS()));
+                } */
+                sapStock.setFactoryCode(stock.getWERKS());
+                // 工厂名称
+                if (factoryNamePair.containsKey(stock.getWERKS())) {
+                    sapStock.setFactory(factoryNamePair.get(stock.getWERKS()));
+                }
+                // 库存地点 code
+                sapStock.setStorageLocationCode(stock.getLGORT());
+                // 库存地点id
+                /* if (storageLocationIdPair.containsKey(uniqueKey)) {
+                    sapStock.setStorageLocationId(storageLocationIdPair.get(uniqueKey));
+                } */
+                // 库存地点名称
+                if (stockLocationNamePair.containsKey(uniqueKey)) {
+                    sapStock.setProjectDepartment(stockLocationNamePair.get(uniqueKey));
+                }
+                // 物料编码 需要去掉前缀 00000000
+                sapStock.setMaterialCode(stock.getMATNR().replaceFirst("^0+", ""));
+                // 物料描述
+                sapStock.setMaterialName(stock.getMAKTX());
+                // 库存数量
+                sapStock.setQuantity(stock.getLABST());
+                // 单价
+                sapStock.setUnitPrice(stock.getJIAGE());
+                // 基本单位
+                sapStock.setUnit(stock.getMEINS());
+                // 同步时间
+                sapStock.setSyncTime(LocalDateTime.now());
+                noFactoryTobeAddedStocks.add(sapStock);
+            });
+        }
+
         // 使用返回的SAP库存数据更新已有的 库存数据
         // pms中已有 SAP返回数据中也存在 则更新
         List<IotSapStockDO> actualUpdatedStocks = new ArrayList<>();
@@ -663,8 +746,27 @@ public class IotSapServiceImpl implements IotSapService {
             });
         }
         System.out.println(factoryCode + "需要更新的SAP库存数量:" + actualUpdatedStocks.size());
-        // pms中已有 但是 SAP返回数据不存在 如果设置了安全库存,则库存为0,若没有设置安全库存,则可以删除
 
+        // todo sap 工厂 库存地点 未关联组织部门
+        // 使用返回的SAP库存数据更新已有的 库存数据 pms中已有 SAP返回数据中也存在 则更新
+        List<IotSapStockDO> noFactoryActualUpdatedStocks = new ArrayList<>();
+        // key工厂code-库存地点code-物料编码      value库存对象
+        Map<String, IotSapStockVO> noFactoryExistStockPair = createNoFactoryExistStockMap(sapStocks, noFactoryExistStockKeys, storageLocationIdPair);
+        if (CollUtil.isNotEmpty(noFactoryExistStockPair)) {
+            Map<String, IotSapStockDO> finalTobeUpdatedStockPair = noFactoryTobeUpdatedStockPair;
+            noFactoryExistStockPair.forEach((k, v) -> {
+                if (finalTobeUpdatedStockPair.containsKey(k)) {
+                    IotSapStockDO sapStock = finalTobeUpdatedStockPair.get(k);
+                    sapStock.setUnitPrice(v.getJIAGE());    // 更新库存价格
+                    sapStock.setQuantity(v.getLABST());     // 更新库存数量
+                    sapStock.setUnit(v.getMEINS());         // 更新基本单位
+                    noFactoryActualUpdatedStocks.add(sapStock);
+                }
+            });
+        }
+        System.out.println(factoryCode + "SAP工厂库存地点未关联组织部门-需要更新的SAP库存数量:" + noFactoryActualUpdatedStocks.size());
+
+        // pms中已有 但是 SAP返回数据不存在 如果设置了安全库存,则库存为0,若没有设置安全库存,则可以删除
 
         // 遍历明细数据 新增 修改 SAP库存数据
         /* List<IotSapStockDO> tobeSapStocks = new ArrayList<>();
@@ -705,14 +807,22 @@ public class IotSapServiceImpl implements IotSapService {
                 tobeSapStocks.add(sapStock);
             }
         }); */
-        // 本地库存 初始化 批量插入本地库存 记录
+        // 本地库存 初始化 批量插入SAP 库存 工厂 库存地点 已经关联了组织架构部门
         if (CollUtil.isNotEmpty(tobeAddedStocks)) {
             TenantUtils.execute(1L, () -> iotSapStockMapper.insertBatch(tobeAddedStocks));
         }
+        // 本地库存 初始化 批量插入本地库存 记录 工厂 库存地点 未关联了组织架构部门
+        if (CollUtil.isNotEmpty(noFactoryTobeAddedStocks)) {
+            TenantUtils.execute(1L, () -> iotSapStockMapper.insertBatch(noFactoryTobeAddedStocks));
+        }
         // pms中存在而且SAP接口也返回的库存数据:更新
         if (CollUtil.isNotEmpty(actualUpdatedStocks)) {
             TenantUtils.execute(1L, () -> iotSapStockMapper.updateBatch(actualUpdatedStocks));
         }
+        // pms中存在而且SAP接口也返回的库存数据:更新 工厂 库存地点 未关联了组织架构部门
+        if (CollUtil.isNotEmpty(noFactoryActualUpdatedStocks)) {
+            TenantUtils.execute(1L, () -> iotSapStockMapper.updateBatch(noFactoryActualUpdatedStocks));
+        }
     }
 
     /**
@@ -772,7 +882,7 @@ public class IotSapServiceImpl implements IotSapService {
     private Map<String, IotSapStockVO> createExistStockMap(List<IotSapStockVO> sapStocks, Set<String> existStockKeys, Map<String, Long> storageLocationIdPair) {
         return sapStocks.stream()
                 .filter(sapStock -> StrUtil.isNotBlank(sapStock.getMATNR()) &&
-                        ObjUtil.isNotEmpty(sapStock.getLGORT()) &&
+                        StrUtil.isNotBlank(sapStock.getLGORT()) &&
                         storageLocationIdPair.containsKey(StrUtil.join("-", sapStock.getWERKS(), sapStock.getLGORT())))
                 .map(sapStock -> {
                     // 处理前导零:移除MATNR前的 00000000
@@ -788,4 +898,31 @@ public class IotSapServiceImpl implements IotSapService {
                         (existing, replacement) -> existing // 如果有重复的key,保留第一个值
                 ));
     }
+
+    /**
+     * 处理本地未维护的工厂 库存地点 同步过来的物料
+     * sap库存 更新 创建 唯一key(工厂code+库存地点code-物料编码) 到 sap库存对象 的映射
+     * pms中已有的库存  SAP库存接口也返回了 需要更新
+     * @param sapStocks SAP库存列表
+     * @param existStockKeys 数据库中已存在的 sap库存 集合
+     * @param storageLocationIdPair key库存地点code    value库存地点id
+     * @return 物料编码到描述的映射
+     */
+    private Map<String, IotSapStockVO> createNoFactoryExistStockMap(List<IotSapStockVO> sapStocks,
+                                                                    Set<String> existStockKeys, Map<String, Long> storageLocationIdPair) {
+        return sapStocks.stream()
+                .filter(sapStock -> StrUtil.isNotBlank(sapStock.getMATNR()) && StrUtil.isNotBlank(sapStock.getLGORT()))
+                .map(sapStock -> {
+                    // 处理前导零:移除MATNR前的 00000000
+                    String processedCode = sapStock.getMATNR().replaceFirst("^0+", "");
+                    // 本地已经配置过库存地点 包含SAP库存接口返回的库存地点
+                    return new AbstractMap.SimpleEntry<>(StrUtil.join("-", sapStock.getWERKS(), sapStock.getLGORT(), processedCode), sapStock);
+                })
+                .filter(entry -> existStockKeys.contains(entry.getKey()))
+                .collect(Collectors.toMap(
+                        Map.Entry::getKey,
+                        Map.Entry::getValue,
+                        (existing, replacement) -> existing // 如果有重复的key,保留第一个值
+                ));
+    }
 }