瀏覽代碼

Merge remote-tracking branch 'origin/master'

lipenghui 2 月之前
父節點
當前提交
9be6a0b01c

+ 112 - 74
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/job/sap/SyncSapPickingListJob.java

@@ -2,20 +2,33 @@ package cn.iocoder.yudao.module.pms.job.sap;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.LocalDateTimeUtil;
 import cn.hutool.core.util.ObjUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.dict.core.DictFrameworkUtils;
 import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
 import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotsappickinglist.IotSapPickingListMapper;
 import cn.iocoder.yudao.module.pms.sap.SapConnector;
+import cn.iocoder.yudao.module.pms.sap.service.IotSapService;
+import cn.iocoder.yudao.module.pms.sap.vo.IotSapPickingListHeadVO;
+import cn.iocoder.yudao.module.pms.sap.vo.IotSapPickingListItemVO;
 import cn.iocoder.yudao.module.system.api.saporg.SapOrgApi;
 import cn.iocoder.yudao.module.system.api.saporg.dto.SapOrgRespDTO;
 import com.sap.conn.jco.*;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.stereotype.Component;
 
+import javax.annotation.Resource;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 import java.util.stream.Collectors;
 
+import static cn.iocoder.yudao.module.pms.framework.config.MultiThreadConfiguration.PMS_THREAD_POOL_TASK_EXECUTOR;
+
 @Component
 @Slf4j
 public class SyncSapPickingListJob implements JobHandler {
@@ -23,90 +36,115 @@ public class SyncSapPickingListJob implements JobHandler {
     private SapConnector sapConnector;
     @Autowired
     private SapOrgApi sapOrgApi;
+    @Autowired
+    private IotSapPickingListMapper sapPickingListMapper;
+    @Resource(name = PMS_THREAD_POOL_TASK_EXECUTOR)
+    private ThreadPoolTaskExecutor pmsThreadPoolTaskExecutor;
+    @Autowired
+    private IotSapService iotSapService;
 
     @Override
     @TenantJob
     public String execute(String param) throws Exception {
+        // 查询所有工厂 根据工厂 多线程处理 领料单
         List<String> factoryCodes = factoryCodes();
         if (CollUtil.isEmpty(factoryCodes)) {
             return "No SAP Factory";
         }
-        try {
-            JCoDestination destination = sapConnector.getDestination();
-            JCoFunction function = destination.getRepository().getFunction("ZPMS_006");
-            if (ObjUtil.isEmpty(function)) {
-                return "No SAP Function";
-            }
-            // 设置输入参数
-            JCoParameterList input = function.getImportParameterList();
-            input.setValue("I_WERKS", "6011");
-            // 暂时只设置同步 2025年后的 领料单 2025年之前的领料单 手动入库
-            input.setValue("I_DATUM_F", "20250101"); // 开始日期
-            // input.setValue("I_DATUM_T", "20251231"); // 结束日期
-
-            // 执行 RFC 调用
-            function.execute(destination);
+        // 查询 SAP同步领料单 开始时间 结束时间 数据字典
+        String startTime = DictFrameworkUtils.parseDictDataValue("iot_sap_pickinglist_synctime_range", "开始时间");
+        String endTime = DictFrameworkUtils.parseDictDataValue("iot_sap_pickinglist_synctime_range", "结束时间");
+        if (StrUtil.isEmpty(startTime) || StrUtil.isEmpty(endTime)) {
+            return "No startTime or endTime";
+        }
+        factoryCodes.forEach(factory -> {
+            CountDownLatch latch = new CountDownLatch(factoryCodes.size());;
+            pmsThreadPoolTaskExecutor.execute(() -> {
+                try {
+                    JCoDestination destination = sapConnector.getDestination();
+                    JCoFunction function = destination.getRepository().getFunction("ZPMS_006");
+                    if (ObjUtil.isNotEmpty(function)) {
+                        // 设置输入参数
+                        JCoParameterList input = function.getImportParameterList();
+                        input.setValue("I_WERKS", factory);
+                        // 暂时只设置同步 2025年后的 领料单 2025年之前的领料单 手动入库
+                        input.setValue("I_DATUM_F", startTime); // 开始日期 必填
+                        input.setValue("I_DATUM_T", endTime);   // 结束日期 必填
+                        // 执行 RFC 调用
+                        function.execute(destination);
+                        // 获取输出参数
+                        JCoParameterList output = function.getTableParameterList();
+                        JCoTable headTable = function.getTableParameterList().getTable("T_HEAD");
+                        System.out.println(factory + "当前工厂对应的领料单HEAD数量:" + headTable.getNumRows());
+                        List<IotSapPickingListHeadVO> pickingListHeads = new ArrayList<>();
+                        if (headTable != null && headTable.getNumRows() > 0) {
+                            for (int i = 0; i < headTable.getNumRows(); i++) {
+                                headTable.setRow(i);
+                                IotSapPickingListHeadVO pickingListHead = new IotSapPickingListHeadVO();
+                                pickingListHead.setWERKS(headTable.getString("WERKS"));
+                                pickingListHead.setTXTMD(headTable.getString("TXTMD"));
+                                pickingListHead.setZLTNO(headTable.getString("ZLTNO"));
+                                pickingListHead.setZLLLX(headTable.getString("ZLLLX"));
+                                pickingListHead.setDATUM(LocalDateTimeUtil.of(headTable.getDate("DATUM")));
+                                pickingListHead.setPSPID(headTable.getString("PSPID"));
+                                pickingListHead.setPOSID(headTable.getString("POSID"));
+                                pickingListHead.setPOST1(headTable.getString("POST1"));
+                                pickingListHead.setZSSXMB(headTable.getString("ZSSXMB"));
+                                pickingListHead.setLGOBE(headTable.getString("LGOBE"));
+                                pickingListHead.setKOSTL(headTable.getString("KOSTL"));
+                                pickingListHead.setLTEXT(headTable.getString("LTEXT"));
+                                pickingListHeads.add(pickingListHead);
+                            }
+                        }
+                        // 清空函数继续下次请求
+                        JCoTable itemTable = function.getTableParameterList().getTable("T_ITEM");
+                        System.out.println(factory + "当前工厂对应的领料单ITEM数量:" + headTable.getNumRows());
+                        List<IotSapPickingListItemVO> pickingListItems = new ArrayList<>();
+                        if (itemTable != null && itemTable.getNumRows() > 0) {
+                            for (int i = 0; i < itemTable.getNumRows(); i++) {
+                                itemTable.setRow(i);
+                                IotSapPickingListItemVO pickingListItem = new IotSapPickingListItemVO();
+                                pickingListItem.setWERKS(itemTable.getString("WERKS"));
+                                pickingListItem.setZLTNO(itemTable.getString("ZLTNO"));
+                                pickingListItem.setMATNR(itemTable.getString("MATNR"));
+                                pickingListItem.setMAKTX(itemTable.getString("MAKTX"));
+                                pickingListItem.setMENGE(itemTable.getBigDecimal("MENGE"));
+                                pickingListItem.setMEINS(itemTable.getString("MEINS"));
+                                pickingListItem.setSOBKZ(itemTable.getString("SOBKZ"));
+                                pickingListItem.setGRUND(itemTable.getString("GRUND"));
+                                pickingListItem.setGRTXT(itemTable.getString("GRTXT"));
+                                pickingListItem.setLGORT(itemTable.getString("LGORT"));
+                                pickingListItem.setLGOBE(itemTable.getString("LGOBE"));
+                                pickingListItem.setCHARG(itemTable.getString("CHARG"));
 
-            // 获取输出参数
-            JCoParameterList output = function.getTableParameterList();
-            JCoTable headTable = function.getTableParameterList().getTable("T_HEAD");
-            // JCoParameterList output = function.getExportParameterList();
-            if (CollUtil.isNotEmpty(output)) {
-                output.forEach(material -> {
-                    // System.out.println(material.getName());
-                });
-            }
-            if (headTable != null && headTable.getNumRows() > 0) {
-                for (int i = 0; i < headTable.getNumRows(); i++) {
-                    headTable.setRow(i);
-                    System.out.println(String.format("行号 %d: 工厂=%s, 名称 1=%s, 领料/退料编号=%s, ZLLLX=%s, " +
-                                    "日期=%tT, 项目定义=%s, WBS 元素=%s, 描述=%s, 所属项目部=%s, 描述=%s, 成本中心=%s, 描述=%s\n",
-                            i,
-                            headTable.getString("WERKS"),
-                            headTable.getString("TXTMD"),
-                            headTable.getString("ZLTNO"),
-                            headTable.getString("ZLLLX"),
-                            headTable.getDate("DATUM"),
-                            headTable.getString("PSPID"),
-                            headTable.getString("POSID"),
-                            headTable.getString("POST1"),
-                            headTable.getString("ZSSXMB"),
-                            headTable.getString("LGOBE"),
-                            headTable.getString("KOSTL"),
-                            headTable.getString("LTEXT")
-                    ));
-                }
-            }
-            // 清空函数继续下次请求
-            JCoTable itemTable = function.getTableParameterList().getTable("T_ITEM");
-            if (itemTable != null && itemTable.getNumRows() > 0) {
-                for (int i = 0; i < itemTable.getNumRows(); i++) {
-                    itemTable.setRow(i);
-                    System.out.println(String.format("行号 %d: 物料=%s, 描述=%s, 数量=%f, " +
-                                    "基本单位=%s, 特殊库存=%s, 移动原因=%s, 原因=%s, 库存地点=%s, 描述=%s, 库存仓位=%s, 批次=%s, 转入工厂=%s, BEIZHU=%s\n",
-                            i,
-                            itemTable.getInt("ZNUMC"),
-                            itemTable.getString("MATNR"),
-                            itemTable.getString("MAKTX"),
-                            itemTable.getDouble("MENGE"),
-                            itemTable.getString("MEINS"),
-                            itemTable.getString("SOBKZ"),
-                            itemTable.getInt("GRUND"),
-                            itemTable.getString("GRTXT"),
-                            itemTable.getString("LGORT"),
-                            itemTable.getString("LGOBE"),
-                            itemTable.getString("LGPBE"),
-                            itemTable.getString("CHARG"),
-                            itemTable.getString("WERKS_ZR"),
-                            itemTable.getString("BEIZHU")
-                    ));
+                                pickingListItem.setWERKS_ZR(itemTable.getString("WERKS_ZR"));
+                                pickingListItem.setBEIZHU(itemTable.getString("BEIZHU"));
+                                pickingListItem.setMBLNR(itemTable.getString("MBLNR"));
+                                pickingListItem.setMJAHR(itemTable.getString("MJAHR"));
+                                pickingListItem.setZEILE(itemTable.getString("ZEILE"));
+                                pickingListItem.setDMBTR(itemTable.getBigDecimal("DMBTR"));
+                                pickingListItem.setWAERS(itemTable.getString("WAERS"));
+                                pickingListItem.setLBKUM(itemTable.getBigDecimal("LBKUM"));
+                                pickingListItem.setSALK3(itemTable.getBigDecimal("SALK3"));
+                                pickingListItem.setVPRSV(itemTable.getString("VPRSV"));
+                                pickingListItem.setVERPR(itemTable.getBigDecimal("VERPR"));
+                                pickingListItems.add(pickingListItem);
+                            }
+                        }
+                        // 处理头部表信息 和 明细表数据
+                        if (CollUtil.isNotEmpty(pickingListHeads) && CollUtil.isNotEmpty(pickingListItems)) {
+                            iotSapService.processPickingLists(factory, pickingListHeads, pickingListItems);
+                        }
+                    }
+                } catch (JCoException e) {
+                    // 记录调用接口异常日志
+                    throw new RuntimeException(e);
+                } finally {
+                    latch.countDown();
                 }
-            }
-
-            return "Material Info: " + output.getString("T_HEAD");
-        } catch (JCoException e) {
-            return "Error calling SAP Picking List: " + e.getMessage();
-        }
+            });
+        });
+        return "Picking List Info: T_HEAD T_ITEM";
     }
 
     /**

+ 121 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/job/sap/SyncSapStockJob.java

@@ -0,0 +1,121 @@
+package cn.iocoder.yudao.module.pms.job.sap;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjUtil;
+import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
+import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotsappickinglist.IotSapPickingListMapper;
+import cn.iocoder.yudao.module.pms.sap.SapConnector;
+import cn.iocoder.yudao.module.pms.sap.service.IotSapService;
+import cn.iocoder.yudao.module.pms.sap.vo.IotSapStockVO;
+import cn.iocoder.yudao.module.system.api.saporg.SapOrgApi;
+import cn.iocoder.yudao.module.system.api.saporg.dto.SapOrgRespDTO;
+import com.sap.conn.jco.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.module.pms.framework.config.MultiThreadConfiguration.PMS_THREAD_POOL_TASK_EXECUTOR;
+
+/**
+ * 同步 SAP 库存 定时任务
+ */
+@Component
+@Slf4j
+public class SyncSapStockJob implements JobHandler {
+    @Autowired
+    private SapConnector sapConnector;
+    @Autowired
+    private SapOrgApi sapOrgApi;
+    @Autowired
+    private IotSapPickingListMapper sapPickingListMapper;
+    @Resource(name = PMS_THREAD_POOL_TASK_EXECUTOR)
+    private ThreadPoolTaskExecutor pmsThreadPoolTaskExecutor;
+    @Autowired
+    private IotSapService iotSapService;
+
+    @Override
+    @TenantJob
+    public String execute(String param) throws Exception {
+        // 查询所有工厂 根据工厂 多线程处理 SAP 库存
+        List<String> factoryCodes = factoryCodes();
+        if (CollUtil.isEmpty(factoryCodes)) {
+            return "No SAP Factory";
+        }
+        factoryCodes.forEach(factory -> {
+            CountDownLatch latch = new CountDownLatch(factoryCodes.size());;
+            pmsThreadPoolTaskExecutor.execute(() -> {
+                try {
+                    JCoDestination destination = sapConnector.getDestination();
+                    JCoFunction function = destination.getRepository().getFunction("ZPMS_002");
+                    if (ObjUtil.isNotEmpty(function)) {
+                        // 设置输入参数
+                        JCoParameterList input = function.getImportParameterList();
+                        input.setValue("IV_MATNR", "");    // 物料编号
+                        input.setValue("IV_WERKS", factory);    // 工厂
+                        input.setValue("IV_LGORT", "");    // 库存地点
+                        // 执行 RFC 调用
+                        function.execute(destination);
+                        // 获取输出参数
+                        JCoParameterList output = function.getTableParameterList();
+                        JCoTable etStockTable = function.getTableParameterList().getTable("ET_STOCK");
+                        System.out.println(factory + "当前工厂对应的SAP库存数量:" + etStockTable.getNumRows());
+                        List<IotSapStockVO> sapStocks = new ArrayList<>();
+                        if (etStockTable != null && etStockTable.getNumRows() > 0) {
+                            for (int i = 0; i < etStockTable.getNumRows(); i++) {
+                                etStockTable.setRow(i);
+                                IotSapStockVO sapStock = new IotSapStockVO();
+                                sapStock.setWERKS(etStockTable.getString("WERKS"));
+                                sapStock.setMATNR(etStockTable.getString("MATNR"));
+                                sapStock.setMAKTX(etStockTable.getString("MAKTX"));
+                                sapStock.setLABST(etStockTable.getBigDecimal("LABST"));
+                                sapStock.setLGORT(etStockTable.getString("LGORT"));
+                                sapStock.setCHARG(etStockTable.getString("CHARG"));
+                                sapStock.setSOBKZ(etStockTable.getString("SOBKZ"));
+                                sapStock.setPSPNR(etStockTable.getString("PSPNR"));
+                                sapStock.setPOSID(etStockTable.getString("POSID"));
+                                sapStock.setMEINS(etStockTable.getString("MEINS"));
+                                sapStock.setINSME(etStockTable.getString("INSME"));
+                                sapStock.setSPEME(etStockTable.getString("SPEME"));
+                                sapStock.setJIAGE(etStockTable.getBigDecimal("JIAGE"));
+                                sapStocks.add(sapStock);
+                            }
+                        }
+                        // 处理头部表信息 和 明细表数据
+                        if (CollUtil.isNotEmpty(sapStocks)) {
+                            iotSapService.processSapStock(factory, sapStocks);
+                        }
+                    }
+                } catch (JCoException e) {
+                    // 记录调用接口异常日志
+                    throw new RuntimeException(e);
+                } finally {
+                    latch.countDown();
+                }
+            });
+        });
+        return "SAP Stock Info: ET_STOCK";
+    }
+
+    /**
+     * 查询所有SAP工厂
+     */
+    private List<String> factoryCodes(){
+        List<SapOrgRespDTO> sapOrgs = sapOrgApi.getSapOrgByType(1);
+        if (CollUtil.isEmpty(sapOrgs)) {
+            return CollectionUtil.newArrayList();
+        }
+        List<String> factoryCodes = sapOrgs.stream()
+                .map(SapOrgRespDTO::getFactoryCode)
+                .collect(Collectors.toList());
+        return CollUtil.isEmpty(factoryCodes) ? CollUtil.empty(String.class) : factoryCodes;
+    }
+}

+ 19 - 8
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/SapController.java

@@ -58,11 +58,22 @@ public class SapController {
             if (etStockTable != null && etStockTable.getNumRows() > 0) {
                 for (int i = 0; i < etStockTable.getNumRows(); i++) {
                     etStockTable.setRow(i);
-                    System.out.println(String.format("行号 %d: 工厂=%s, 物料=%s, 数量=%s\n",
+                    System.out.println(String.format("行号 %d: 工厂=%s, 物料编码=%s, 物料描述=%s, 库存数量 非限制=%s, 库存地点编码=%s, 批次=%s \n" +
+                                    "特殊库存=%s, WBS 要素=%s, WBS 元素=%s, 基本单位=%s, 质量检验=%s, 已冻结=%s, 库存价格=%s",
                             i,
-                            etStockTable.getString("WERKS"),
-                            etStockTable.getString("MATNR"),
-                            etStockTable.getString("LABST")
+                            etStockTable.getString("WERKS"),    // 工厂
+                            etStockTable.getString("MATNR"),    // 物料编码
+                            etStockTable.getString("MAKTX"),    // 物料描述
+                            etStockTable.getBigDecimal("LABST"),    // 库存数量 非限制
+                            etStockTable.getString("LGORT"),    // 库存地点编码
+                            etStockTable.getString("CHARG"),    // 批次
+                            etStockTable.getString("SOBKZ"),    // 特殊库存
+                            etStockTable.getString("PSPNR"),    // WBS 要素
+                            etStockTable.getString("POSID"),    // WBS 元素
+                            etStockTable.getString("MEINS"),    // 基本单位
+                            etStockTable.getString("INSME"),    // 质量检验
+                            etStockTable.getString("SPEME"),    // 已冻结
+                            etStockTable.getBigDecimal("JIAGE")     // 库存价格
                     ));
                 }
             }
@@ -93,8 +104,8 @@ public class SapController {
             JCoParameterList input = function.getImportParameterList();
             input.setValue("I_WERKS", "6011");
             // 暂时只设置同步 2025年后的 领料单 2025年之前的领料单 手动入库
-            // input.setValue("I_DATUM_F", "20250101"); // 开始日期
-            // input.setValue("I_DATUM_T", "20251231"); // 结束日期
+            input.setValue("I_DATUM_F", "2025-07-01"); // 开始日期
+            input.setValue("I_DATUM_T", "2025-08-31"); // 结束日期
 
             // 执行 RFC 调用
             function.execute(destination);
@@ -134,7 +145,7 @@ public class SapController {
             if (itemTable != null && itemTable.getNumRows() > 0) {
                 for (int i = 0; i < itemTable.getNumRows(); i++) {
                     itemTable.setRow(i);
-                    System.out.println(String.format("行号 %d: 工厂编号=%s, 领料/退料编号=%s, 物料编码=%s, 物料描述=%s, " +
+                    /* System.out.println(String.format("行号 %d: 工厂编号=%s, 领料/退料编号=%s, 物料编码=%s, 物料描述=%s, " +
                                     "物料数量=%s, 基本单位=%s, 特殊库存=%s, 移动原因=%s, 原因=%s, 库存地点编码=%s, 库存地点描述=%s, 库存仓位=%s, 批次=%s, 转入工厂=%s\n" +
                                     "备注=%s, 物料凭证编号=%s, 物料凭证年度=%s, 行项目号=%s, 本位币金额(单价)=%s, 货币码=%s, 交易后库存数量 - 以输入单位计=%s, 本位币库存总价值=%s, 价格控制标识=%s, 移动平均价或标准价=%s\n",
                             i,
@@ -163,7 +174,7 @@ public class SapController {
                             itemTable.getBigDecimal("SALK3"),   // 本位币库存总价值
                             itemTable.getString("VPRSV"),       // 价格控制标识
                             itemTable.getBigDecimal("VERPR")    // 移动平均价或标准价
-                    ));
+                    )); */
                 }
             }
 

+ 18 - 4
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/service/IotSapService.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.pms.sap.service;
 
-import cn.iocoder.yudao.module.pms.sap.vo.IotSapMaterialVO;
-import cn.iocoder.yudao.module.pms.sap.vo.IotSapMerchantVO;
+import cn.iocoder.yudao.module.pms.sap.vo.*;
 
 import java.util.List;
 
@@ -16,7 +15,7 @@ public interface IotSapService {
      * @param
      * @return
      */
-    void processMaterials(List<IotSapMaterialVO>  sapMaterials);
+    void processMaterials(List<IotSapMaterialVO> sapMaterials);
 
     /**
      * 处理SAP接口返回的 客商 主数据
@@ -24,6 +23,21 @@ public interface IotSapService {
      * @param
      * @return
      */
-    void processMerchants(List<IotSapMerchantVO>  sapMerchants);
+    void processMerchants(List<IotSapMerchantVO> sapMerchants);
 
+    /**
+     * 处理SAP接口返回的 领料单 主数据
+     *
+     * @param
+     * @return
+     */
+    void processPickingLists(String factory, List<IotSapPickingListHeadVO> pickingListHeads, List<IotSapPickingListItemVO> pickingListItems);
+
+    /**
+     * 处理SAP接口返回的 SAP 库存 主数据
+     *
+     * @param
+     * @return
+     */
+    void processSapStock(String factory, List<IotSapStockVO> sapStocks);
 }

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

@@ -5,13 +5,22 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotlockstock.IotLockStockDO;
 import cn.iocoder.yudao.module.pms.dal.dataobject.iotmaterial.IotMaterialDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotsappickinglist.IotSapPickingListDO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.iotsapstock.IotSapStockDO;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotlockstock.IotLockStockMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotmaterial.IotMaterialMapper;
 import cn.iocoder.yudao.module.pms.dal.mysql.iotmaterial.IotSapMaterialMapper;
-import cn.iocoder.yudao.module.pms.sap.vo.IotSapMaterialVO;
-import cn.iocoder.yudao.module.pms.sap.vo.IotSapMerchantVO;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotsappickinglist.IotSapPickingListMapper;
+import cn.iocoder.yudao.module.pms.dal.mysql.iotsapstock.IotSapStockMapper;
+import cn.iocoder.yudao.module.pms.sap.vo.*;
 import cn.iocoder.yudao.module.supplier.dal.dataobject.product.SupplierDO;
 import cn.iocoder.yudao.module.supplier.dal.mysql.product.SupplierMapper;
+import cn.iocoder.yudao.module.system.api.dept.DeptApi;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.api.saporg.SapOrgApi;
+import cn.iocoder.yudao.module.system.api.saporg.dto.SapOrgRespDTO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -20,6 +29,8 @@ import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.concurrent.CountDownLatch;
@@ -43,6 +54,16 @@ public class IotSapServiceImpl implements IotSapService {
     private ThreadPoolTaskExecutor pmsThreadPoolTaskExecutor;
     @Autowired
     private SupplierMapper supplierMapper;
+    @Autowired
+    private SapOrgApi sapOrgApi;
+    @Autowired
+    private DeptApi deptApi;
+    @Autowired
+    private IotLockStockMapper iotLockStockMapper;
+    @Autowired
+    private IotSapStockMapper iotSapStockMapper;
+    @Autowired
+    private IotSapPickingListMapper iotSapPickingListMapper;
 
     @Override
     public void processMaterials(List<IotSapMaterialVO> sapMaterials) {
@@ -189,6 +210,298 @@ public class IotSapServiceImpl implements IotSapService {
         }
     }
 
+    @Override
+    public void processPickingLists(String factoryCode, List<IotSapPickingListHeadVO> pickingListHeads, List<IotSapPickingListItemVO> pickingListItems) {
+        // 查询出所有成本中心 对应的 deptId 新增本地库存时 可以匹配
+        List<SapOrgRespDTO> costCenters = TenantUtils.execute(1L, () -> sapOrgApi.getSapOrgByType(2));
+        // 查询所有工厂
+        List<SapOrgRespDTO> factories = TenantUtils.execute(1L, () -> sapOrgApi.getSapOrgByType(1));
+        // key成本中心id    value成本中心code
+        Map<Long, String> costCenterCodeIdPair = new HashMap<>();
+        // key工厂code    value工厂id
+        Map<String, Long> factoryIdPair = new HashMap<>();
+        // key成本中心code    value成本中心id
+        Map<String, Long> costCenterIdPair = new HashMap<>();
+        // key成本中心code    value工厂code
+        Map<String, String> costCenterFactoryCodePair = new HashMap<>();
+        // key成本中心code  value部门id
+        Map<String, Long> costCenterCodeDeptIdPair = new HashMap<>();
+        // 工厂集合
+        factories.forEach(factory -> {
+            factoryIdPair.put(factory.getFactoryCode(), factory.getId());
+        });
+        // 成本中心集合
+        costCenters.forEach(center -> {
+            costCenterCodeIdPair.put(center.getId(), center.getCostCenterCode());
+            costCenterIdPair.put(center.getCostCenterCode(), center.getId());
+            costCenterFactoryCodePair.put(center.getCostCenterCode(), center.getFactoryCode());
+        });
+
+        // 查询所有部门
+        List<DeptRespDTO> depts = TenantUtils.execute(1L, () -> deptApi.getDeptList());
+        // 筛选出所有设置了成本中心的部门
+        depts.forEach(dept -> {
+            Set<Long> costCenterIds = dept.getCostCenterIds();
+            // 循环遍历 costCenterIds
+            if (CollUtil.isNotEmpty(costCenterIds)) {
+                costCenterIds.forEach(center -> {
+                    if (costCenterCodeIdPair.containsKey(center)) {
+                        // 当前部门设置的成本中心
+                        String costCenterCode = costCenterCodeIdPair.get(center);
+                        costCenterCodeDeptIdPair.put(costCenterCode, dept.getId());
+                    }
+                });
+            }
+        });
+        // 将集合 pickingListHeads 设置成 Map<String, String> key领料单号 value成本中心
+        Map<String, String> pickingCodeCostCenterPair = new HashMap<>();
+        // 遍历主表
+        pickingListHeads.forEach(head -> {
+            pickingCodeCostCenterPair.put(head.getZLTNO(), head.getKOSTL());
+        });
+        // 遍历子表 所有物料
+        // 领料单表不合并物料数量、单价 审核入本地库时 合并相同成本中心下的物料数量 单价
+        List<IotSapPickingListDO> pickingLists = new ArrayList<>();
+        // 本地库存初始化时合并相同成本中心的 物料数量 单价
+        List<IotLockStockDO> lockStocks = new ArrayList<>();
+        // 本地库存初始化 成本中心+物料编码,确定唯一明细记录,合并数量、单价
+        // 合并的物料数量集合
+        Map<String, BigDecimal> mergeMaterialQuantities = new HashMap<>();
+        // 合并的物料单价
+        Map<String, BigDecimal> mergeMaterialUnitPrices = new HashMap<>();
+        // 合并的物料总价
+        Map<String, BigDecimal> mergeMaterialTotalPrices = new HashMap<>();
+        Map<String, IotSapPickingListItemVO> basicMaterials = new HashMap<>();
+        // 以 成本中心-物料编码 维度统计 物料总数量 物料总金额
+        pickingListItems.forEach(item -> {
+            if (StrUtil.isNotBlank(item.getMATNR())
+                    && StrUtil.isNotBlank(item.getZLTNO()) && pickingCodeCostCenterPair.containsKey(item.getZLTNO())) {
+
+                // 领料单号<->成本中心编码
+                String costCenterCode = pickingCodeCostCenterPair.get(item.getZLTNO());
+                if (StrUtil.isNotBlank(costCenterCode)) {
+                    String uniqueKey = StrUtil.join("~~", costCenterCode, item.getMATNR());
+                    System.out.println("唯一key:" + uniqueKey);
+                    // 当前明细行 物料数量
+                    BigDecimal currentQuantity = ObjUtil.isEmpty(item.getMENGE()) ? BigDecimal.ZERO : item.getMENGE();
+                    // 当前明细行 物料单价 移动平均价或标准价
+                    BigDecimal currentUnitPrice = ObjUtil.isEmpty(item.getVERPR()) ? BigDecimal.ZERO : item.getVERPR();
+                    // 当前明细行 物料总价
+                    BigDecimal currentTotalPrice = currentQuantity.multiply(currentUnitPrice);
+                    // 物料总数量
+                    if (mergeMaterialQuantities.containsKey(uniqueKey)) {
+                        BigDecimal tempQuantity = mergeMaterialQuantities.get(uniqueKey);
+                        mergeMaterialQuantities.put(uniqueKey, tempQuantity.add(currentQuantity));
+                    } else {
+                        mergeMaterialQuantities.put(uniqueKey, currentQuantity);
+                    }
+                    // 物料总价 单价*数量
+                    if (mergeMaterialTotalPrices.containsKey(uniqueKey)) {
+                        BigDecimal tempTotalPrice = mergeMaterialTotalPrices.get(uniqueKey);
+                        // 查询已经暂存的 物料总数量
+                        mergeMaterialTotalPrices.put(uniqueKey, tempTotalPrice.add(currentTotalPrice));
+                    } else {
+                        mergeMaterialTotalPrices.put(uniqueKey, currentTotalPrice);
+                    }
+                    // 基准物料集合
+                    if (!basicMaterials.containsKey(uniqueKey)) {
+                        basicMaterials.put(uniqueKey, item);
+                    }
+                }
+            }
+        });
+        System.out.println(factoryCode + "基准物料集合容量:" + basicMaterials.size());
+        // 以 成本中心-物料编码 维度统计 物料平均单价=物料总金额/物料总数量
+        if (CollUtil.isNotEmpty(mergeMaterialTotalPrices)) {
+            mergeMaterialTotalPrices.forEach((k,v) -> {
+                // k成本中心code+物料编码    v物料总价
+                if (mergeMaterialQuantities.containsKey(k)) {
+                    BigDecimal totalQuantity = mergeMaterialQuantities.get(k);
+                    if (totalQuantity.compareTo(BigDecimal.ZERO) > 0) {
+                        BigDecimal unitPrice = v.divide(totalQuantity, 2, RoundingMode.HALF_UP);
+                        mergeMaterialUnitPrices.put(k, unitPrice);
+                    }
+                }
+            });
+        }
+        // 用合并后的物料数量、单价 初始化本地库存
+        if (CollUtil.isNotEmpty(basicMaterials)) {
+            basicMaterials.forEach((k,v) -> {
+                // k成本中心code-物料编码    v随机明细物料对象
+                String[] costCenterMaterialAttr = k.split("~~");
+                if (costCenterMaterialAttr.length > 1) {
+                    // 领料单<->成本中心<->部门
+                    String costCenterCode = costCenterMaterialAttr[0];
+                    if (costCenterCodeDeptIdPair.containsKey(costCenterCode)) {
+                        IotLockStockDO lockStock = new IotLockStockDO();
+                        if (costCenterCodeDeptIdPair.containsKey(costCenterCode)) {
+                            lockStock.setDeptId(costCenterCodeDeptIdPair.get(costCenterCode));
+                        }
+                        // sap成本中心 在pms系统中的id
+                        if (costCenterIdPair.containsKey(costCenterCode)) {
+                            lockStock.setCostCenterId(costCenterIdPair.get(costCenterCode));
+                        }
+                        // sap工厂 在pms系统中的id
+                        if (costCenterFactoryCodePair.containsKey(costCenterCode)) {
+                            String tempFactoryCode = costCenterFactoryCodePair.get(costCenterCode);
+                            if (factoryIdPair.containsKey(tempFactoryCode)) {
+                                lockStock.setFactoryId(factoryIdPair.get(tempFactoryCode));
+                            }
+                        }
+                        // 物料编码
+                        lockStock.setMaterialCode(costCenterMaterialAttr[1]);
+                        // 物料描述
+                        lockStock.setMaterialName(v.getMAKTX());
+                        // 单位
+                        lockStock.setUnit(v.getMEINS());
+                        // 物料数量
+                        if (mergeMaterialQuantities.containsKey(k)) {
+                            lockStock.setQuantity(mergeMaterialQuantities.get(k));
+                        }
+                        // 单价
+                        if (mergeMaterialUnitPrices.containsKey(k)) {
+                            lockStock.setUnitPrice(mergeMaterialUnitPrices.get(k));
+                        }
+                        lockStocks.add(lockStock);
+                    }
+                }
+            });
+        }
+        pickingListItems.forEach(item -> {
+            IotSapPickingListDO picking = new IotSapPickingListDO();
+            // 领料单<->成本中心<->部门
+            if (pickingCodeCostCenterPair.containsKey(item.getZLTNO())) {
+                String costCenterCode = pickingCodeCostCenterPair.get(item.getZLTNO());
+                if (costCenterCodeDeptIdPair.containsKey(costCenterCode)) {
+                    picking.setDeptId(costCenterCodeDeptIdPair.get(costCenterCode));
+                    // sap成本中心 在pms系统中的id
+                    if (costCenterIdPair.containsKey(costCenterCode)) {
+                        picking.setCostCenterId(costCenterIdPair.get(costCenterCode));
+                    }
+                    // sap工厂 在pms系统中的id
+                    if (factoryIdPair.containsKey(item.getWERKS())) {
+                        picking.setFactoryId(factoryIdPair.get(item.getWERKS()));
+                    }
+                    // 领料单号
+                    picking.setNumber(item.getZLTNO());
+                    // 物料编码
+                    picking.setMaterialCode(item.getMATNR());
+                    // 物料名称 描述
+                    picking.setMaterialName(item.getMAKTX());
+                    // 物料数量
+                    picking.setQuantity(item.getMENGE());
+                    // 单价
+                    picking.setUnitPrice(item.getVERPR());
+                    // 单位
+                    picking.setUnit(item.getMEINS());
+                    // 同步时间
+                    picking.setSyncTime(LocalDateTime.now());
+                    pickingLists.add(picking);
+                }
+            }
+        });
+        // 本地库存 初始化 批量插入本地库存 记录
+        if (CollUtil.isNotEmpty(lockStocks)) {
+            TenantUtils.execute(1L, () -> iotLockStockMapper.insertBatch(lockStocks));
+        }
+        // 新增领料单
+        if (CollUtil.isNotEmpty(pickingLists)) {
+            TenantUtils.execute(1L, () -> iotSapPickingListMapper.insertBatch(pickingLists));
+        }
+        // 记录日志 所有领料单如果有的成本中心 在系统中不存在 或 没有对应的部门 记录到日志
+
+    }
+
+    @Override
+    public void processSapStock(String factoryCode, List<IotSapStockVO> sapStocks) {
+        // 查询出所有工厂 对应的 deptId 新增本地库存时 可以匹配
+        List<SapOrgRespDTO> storageLocations = TenantUtils.execute(1L, () -> sapOrgApi.getSapOrgByType(3));
+        // 查询所有工厂
+        List<SapOrgRespDTO> factories = TenantUtils.execute(1L, () -> sapOrgApi.getSapOrgByType(1));
+        // key工厂code    value工厂id
+        Map<String, Long> factoryIdPair = new HashMap<>();
+        // key工厂code    value工厂名称
+        Map<String, String> factoryNamePair = new HashMap<>();
+        // key库存地点code    value库存地点id
+        Map<String, Long> storageLocationIdPair = new HashMap<>();
+        // key库存地点id    value库存地点code
+        Map<Long, String> stockLocationCodeIdPair = new HashMap<>();
+        // key库存地点code  value部门id
+        Map<String, Long> locationCodeDeptIdPair = new HashMap<>();
+        // key库存地点code    value库存地点名称描述
+        Map<String, String> stockLocationNamePair = new HashMap<>();
+        // 工厂集合
+        factories.forEach(factory -> {
+            factoryIdPair.put(factory.getFactoryCode(), factory.getId());
+            factoryNamePair.put(factory.getFactoryCode(), factory.getFactoryName());
+        });
+        // 库存地点集合
+        storageLocations.forEach(location -> {
+            stockLocationCodeIdPair.put(location.getId(), location.getStorageLocationCode());
+            storageLocationIdPair.put(location.getStorageLocationCode(), location.getId());
+            stockLocationNamePair.put(location.getStorageLocationCode(), location.getStorageLocationName());
+        });
+        // 查询所有部门
+        List<DeptRespDTO> depts = TenantUtils.execute(1L, () -> deptApi.getDeptList());
+        // 筛选出所有设置了 库存地点 的部门
+        depts.forEach(dept -> {
+            Set<Long> stockLocationIds = dept.getStockLocationIds();
+            // 循环遍历 stockLocationIds
+            if (CollUtil.isNotEmpty(stockLocationIds)) {
+                stockLocationIds.forEach(location -> {
+                    if (stockLocationCodeIdPair.containsKey(location)) {
+                        // 当前部门设置的 库存地点
+                        String locationCode = stockLocationCodeIdPair.get(location);
+                        locationCodeDeptIdPair.put(locationCode, dept.getId());
+                    }
+                });
+            }
+        });
+        // 遍历明细数据 新增 修改 SAP库存数据
+        List<IotSapStockDO> tobeSapStocks = new ArrayList<>();
+        sapStocks.forEach(stock -> {
+            // 只保存pms维护过库存地点的数据
+            if (locationCodeDeptIdPair.containsKey(stock.getLGORT())) {
+                IotSapStockDO sapStock = new IotSapStockDO();
+                // 部门id
+                sapStock.setDeptId(locationCodeDeptIdPair.get(stock.getLGORT()));
+                // 工厂id
+                if (factoryIdPair.containsKey(stock.getWERKS())) {
+                    sapStock.setFactoryId(factoryIdPair.get(stock.getWERKS()));
+                }
+                // 工厂名称
+                if (factoryNamePair.containsKey(stock.getWERKS())) {
+                    sapStock.setFactory(factoryNamePair.get(stock.getWERKS()));
+                }
+                // 库存地点id
+                if (storageLocationIdPair.containsKey(stock.getLGORT())) {
+                    sapStock.setStorageLocationId(storageLocationIdPair.get(stock.getLGORT()));
+                }
+                // 库存地点名称
+                if (stockLocationNamePair.containsKey(stock.getLGORT())) {
+                    sapStock.setProjectDepartment(stockLocationNamePair.get(stock.getLGORT()));
+                }
+                // 物料编码
+                sapStock.setMaterialCode(stock.getMATNR());
+                // 物料描述
+                sapStock.setMaterialName(stock.getMAKTX());
+                // 库存数量
+                sapStock.setQuantity(stock.getLABST());
+                // 单价
+                sapStock.setUnitPrice(stock.getJIAGE());
+                // 基本单位
+                sapStock.setUnit(stock.getMEINS());
+                // 同步时间
+                sapStock.setSyncTime(LocalDateTime.now());
+                tobeSapStocks.add(sapStock);
+            }
+        });
+        // 本地库存 初始化 批量插入本地库存 记录
+        if (CollUtil.isNotEmpty(tobeSapStocks)) {
+            TenantUtils.execute(1L, () -> iotSapStockMapper.insertBatch(tobeSapStocks));
+        }
+    }
+
     /**
      * 创建物料编码到描述的映射
      * @param sapMaterials SAP返回的物料列表

+ 50 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/vo/IotSapPickingListHeadVO.java

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.pms.sap.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - SAP 同步接口 领料单 HEAD VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotSapPickingListHeadVO {
+
+    @Schema(description = "工厂code", example = "6011")
+    private String WERKS;
+
+    @Schema(description = "工厂名称", example = "陕西瑞鹰")
+    private String TXTMD;
+
+    @Schema(description = "领料/退料编号", example = "10000001")
+    private String ZLTNO;
+
+    @Schema(description = "领料/退料单名称", example = "生产小队退料")
+    private String ZLLLX;
+
+    @Schema(description = "日期", example = "20250614")
+    private LocalDateTime DATUM;
+
+    @Schema(description = "项目定义", example = "OD-CN20001")
+    private String PSPID;
+
+    @Schema(description = "WBS元素", example = "OD-CN20001-02-0009")
+    private String POSID;
+
+    @Schema(description = "描述 ", example = "50032队/YB058-H02井")
+    private String POST1;
+
+    @Schema(description = "所属项目部编码", example = "1003")
+    private String ZSSXMB;
+
+    @Schema(description = "所属项目部描述", example = "陕西项目部")
+    private String LGOBE;
+
+    @Schema(description = "成本中心 编码", example = "6010F-0273")
+    private String KOSTL;
+
+    @Schema(description = "成本中心描述", example = "陕西瑞鹰-陕西-50010队")
+    private String LTEXT;
+
+}

+ 86 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/vo/IotSapPickingListItemVO.java

@@ -0,0 +1,86 @@
+package cn.iocoder.yudao.module.pms.sap.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Schema(description = "管理后台 - SAP 同步接口 领料单 ITEM VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotSapPickingListItemVO {
+
+    @Schema(description = "工厂编号", example = "6011")
+    private String WERKS;
+
+    @Schema(description = "领料/退料编号", example = "20000003")
+    private String ZLTNO;
+
+    @Schema(description = "物料编码", example = "2000000037")
+    private String MATNR;
+
+    @Schema(description = "物料描述", example = "柴油 -20#")
+    private String MAKTX;
+
+    @Schema(description = "物料数量", example = "320.6")
+    private BigDecimal MENGE;
+
+    @Schema(description = "基本单位", example = "PC")
+    private String MEINS;
+
+    @Schema(description = "特殊库存")
+    private String SOBKZ;
+
+    @Schema(description = "移动原因", example = "无")
+    private String GRUND;
+
+    @Schema(description = "原因", example = "项目需要")
+    private String GRTXT;
+
+    @Schema(description = "库存地点编码", example = "1003")
+    private String LGORT;
+
+    @Schema(description = "库存地点描述", example = "陕西项目部")
+    private String LGOBE;
+
+    @Schema(description = "库存仓位", example = "")
+    private String LGPBE;
+
+    @Schema(description = "批次", example = "")
+    private String CHARG;
+
+    @Schema(description = "转入工厂")
+    private String WERKS_ZR;
+
+    @Schema(description = "备注", example = "")
+    private String BEIZHU;
+
+    @Schema(description = "物料凭证编号", example = "4900004921")
+    private String MBLNR;
+
+    @Schema(description = "物料凭证年度", example = "2021")
+    private String MJAHR;
+
+    @Schema(description = "行项目号", example = "")
+    private String ZEILE;
+
+    @Schema(description = "本位币金额(单价)")
+    private BigDecimal DMBTR;
+
+    @Schema(description = "货币码", example = "CNY")
+    private String WAERS;
+
+    @Schema(description = "交易后库存数量 - 以输入单位计", example = "215.26")
+    private BigDecimal LBKUM;
+
+    @Schema(description = "本位币库存总价值", example = "787.2")
+    private BigDecimal SALK3;
+
+    @Schema(description = "价格控制标识")
+    private String VPRSV;
+
+    @Schema(description = "移动平均价或标准价")
+    private BigDecimal VERPR;
+
+}

+ 53 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/sap/vo/IotSapStockVO.java

@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.module.pms.sap.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Schema(description = "管理后台 - SAP 库存 VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotSapStockVO {
+
+    @Schema(description = "工厂code", example = "6011")
+    private String WERKS;
+
+    @Schema(description = "物料编码", example = "1000000016")
+    private String MATNR;
+
+    @Schema(description = "物料描述", example = "O形圈 A-20848ARIEL")
+    private String MAKTX;
+
+    @Schema(description = "库存数量 非限制", example = "21.3")
+    private BigDecimal LABST;
+
+    @Schema(description = "库存地点编码", example = "1001")
+    private String LGORT;
+
+    @Schema(description = "批次", example = "")
+    private String CHARG;
+
+    @Schema(description = "特殊库存", example = "")
+    private String SOBKZ;
+
+    @Schema(description = "WBS 要素", example = "")
+    private String PSPNR;
+
+    @Schema(description = "WBS 元素", example = "")
+    private String POSID;
+
+    @Schema(description = "基本单位", example = "")
+    private String MEINS;
+
+    @Schema(description = "质量检验", example = "")
+    private String INSME;
+
+    @Schema(description = "已冻结", example = "")
+    private String SPEME;
+
+    @Schema(description = "库存价格", example = "21.3")
+    private BigDecimal JIAGE;
+
+}

+ 7 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApi.java

@@ -30,6 +30,13 @@ public interface DeptApi {
      */
     List<DeptRespDTO> getDeptList(Collection<Long> ids);
 
+    /**
+     * 获得部门集合
+     *
+     * @return 所有部门
+     */
+    List<DeptRespDTO> getDeptList();
+
     /**
      * 校验部门们是否有效。如下情况,视为无效:
      * 1. 部门编号不存在

+ 14 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java

@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.system.api.dept.dto;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import lombok.Data;
 
+import java.util.Set;
+
 /**
  * 部门 Response DTO
  *
@@ -27,6 +29,18 @@ public class DeptRespDTO {
      * 负责人的用户编号
      */
     private Long leaderUserId;
+    /**
+     * SAP 工厂id 集合 [2018,2004]
+     */
+    private Set<Long> factoryIds;
+    /**
+     * SAP 成本中心id 集合 [2018,2004]
+     */
+    private Set<Long> costCenterIds;
+    /**
+     * SAP 库存地点id 集合 [2018,2004]
+     */
+    private Set<Long> stockLocationIds;
     /**
      * 部门状态
      *

+ 8 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/dept/DeptApiImpl.java

@@ -2,14 +2,13 @@ package cn.iocoder.yudao.module.system.api.dept;
 
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
+import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 import cn.iocoder.yudao.module.system.service.dept.DeptService;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.List;
 
 /**
@@ -41,6 +40,13 @@ public class DeptApiImpl implements DeptApi {
         return BeanUtils.toBean(depts, DeptRespDTO.class);
     }
 
+    @Override
+    public List<DeptRespDTO> getDeptList() {
+        DeptListReqVO reqVO = new DeptListReqVO();
+        List<DeptDO> depts = deptService.getDeptList(reqVO);
+        return BeanUtils.toBean(depts, DeptRespDTO.class);
+    }
+
     @Override
     public void validateDeptList(Collection<Long> ids) {
         deptService.validateDeptList(ids);