Parcourir la source

Merge remote-tracking branch 'origin/master'

lfx il y a 1 semaine
Parent
commit
86e8e67342
74 fichiers modifiés avec 6492 ajouts et 1005 suppressions
  1. 3 2
      mjava-boyang/src/main/java/com/malk/boyang/service/impl/BoyangServiceImpl.java
  2. 4 0
      mjava-fenggefushi/src/main/java/com/malk/fenggefushi/service/HeiHuOrderService.java
  3. 974 322
      mjava-fenggefushi/src/main/java/com/malk/fenggefushi/service/Impl/HeiHuOrderServiceImpl.java
  4. 7 6
      mjava-huagao/src/main/java/com/malk/huagao/service/impl/EqbServiceImpl.java
  5. 6 0
      mjava-huagao/src/main/java/com/malk/huagao/service/impl/KdYdDeliveryServiceImpl.java
  6. 3 2
      mjava-huagao/src/main/java/com/malk/huagao/service/impl/KdYdOrderServiceImpl.java
  7. 6 0
      mjava-jinlun/src/main/java/com/malk/jinlun/schedule/JinlunTask.java
  8. 4 1
      mjava-jinlun/src/main/java/com/malk/jinlun/service/CpClient.java
  9. 3 0
      mjava-jinlun/src/main/java/com/malk/jinlun/service/JinlunTaskService.java
  10. 41 1
      mjava-jinlun/src/main/java/com/malk/jinlun/service/impl/CpClientImpl.java
  11. 248 6
      mjava-jinlun/src/main/java/com/malk/jinlun/service/impl/JinlunTaskServiceImpl.java
  12. 2 2
      mjava-jinlun/src/main/resources/application-dev.yml
  13. 2 2
      mjava-jinlun/src/main/resources/application-prod.yml
  14. 4 0
      mjava-jinlun/src/test/java/com/malk/jinlun/DdTest.java
  15. 26 0
      mjava-kabeiyi/pom.xml
  16. 35 0
      mjava-kabeiyi/src/main/java/com/malk/kabeiyi/controller/KabeiyiController.java
  17. 5 0
      mjava-kabeiyi/src/main/java/com/malk/kabeiyi/service/KabeiyiService.java
  18. 612 393
      mjava-kabeiyi/src/main/java/com/malk/kabeiyi/service/impl/KabeiyiServiceImpl.java
  19. 37 0
      mjava-kabeiyi/src/main/resources/application-dev.yml
  20. 14 0
      mjava-kabeiyi/src/main/resources/application-prod.yml
  21. 1 1
      mjava-kabeiyi/src/main/resources/application.yml
  22. 3 5
      mjava-lilin/src/main/java/com/malk/lilin/Controller/LiLinController.java
  23. 93 56
      mjava-lilin/src/main/java/com/malk/lilin/Service/impl/LiLinServiceImpl.java
  24. 5 5
      mjava-lingmingguangzi/src/main/java/com/malk/lingmingguangzi/service/LingmingguangziServiceImpl.java
  25. 1 1
      mjava-lingmingguangzi/src/main/resources/application.yml
  26. 2 2
      mjava-mc/src/main/java/com/malk/mc/service/impl/McYdServiceImpl.java
  27. 1 1
      mjava-mc/src/main/resources/application.yml
  28. 37 0
      mjava-ounuo/src/main/java/com/malk/tuosi/entity/CommissionTable.java
  29. 7 1
      mjava-ounuo/src/main/java/com/malk/tuosi/entity/PersonalMonthlySuccessrate.java
  30. 13 0
      mjava-ounuo/src/main/java/com/malk/tuosi/mapper/CommissionTableMapper.java
  31. 1014 2
      mjava-ounuo/src/main/java/com/malk/tuosi/schedule/ScheduleTask.java
  32. 7 0
      mjava-ounuo/src/main/java/com/malk/tuosi/service/CommissionTableService.java
  33. 13 0
      mjava-ounuo/src/main/java/com/malk/tuosi/service/impl/CommissionTableServiceImpl.java
  34. 7 4
      mjava-ounuo/src/main/java/com/malk/tuosi/service/impl/TbServiceImpl.java
  35. 1 1
      mjava-ounuo/src/main/resources/application.yml
  36. 2 0
      mjava-pake/src/main/java/com/malk/pake/service/impl/PkProjectServiceImpl.java
  37. 78 0
      mjava-siku/src/main/java/com/malk/siku/controller/SikuController.java
  38. 29 0
      mjava-siku/src/main/java/com/malk/siku/schedule/SikuTask.java
  39. 16 0
      mjava-siku/src/main/java/com/malk/siku/service/SikuService.java
  40. 6 0
      mjava-siku/src/main/java/com/malk/siku/service/SikuTaskService.java
  41. 1166 46
      mjava-siku/src/main/java/com/malk/siku/service/impl/SikuServiceImpl.java
  42. 214 0
      mjava-siku/src/main/java/com/malk/siku/service/impl/SikuTaskServiceImpl.java
  43. 154 6
      mjava-siku/src/main/java/com/malk/siku/utils/MkBxUtil.java
  44. 17 6
      mjava-siku/src/main/java/com/malk/siku/utils/MkYpUtil.java
  45. 0 8
      mjava-siku/src/main/resources/application-dev.yml
  46. 1 9
      mjava-siku/src/main/resources/application-prod.yml
  47. 1 1
      mjava-siku/src/main/resources/application.yml
  48. 25 1
      mjava-siku/src/test/java/com.malk.siku/SkTest.java
  49. 0 1
      mjava-tonglibo/pom.xml
  50. 37 22
      mjava-tonglibo/src/main/java/com/malk/tonglibo/controller/machineController.java
  51. 7 0
      mjava-tonglibo/src/main/java/com/malk/tonglibo/entity/MachineData.java
  52. 5 4
      mjava-tonglibo/src/main/java/com/malk/tonglibo/utils/ChangeDetector.java
  53. 81 31
      mjava-tonglibo/src/main/java/com/malk/tonglibo/utils/DeviceDataPersistTask.java
  54. 5 4
      mjava-tonglibo/src/main/resources/application-dev.yml
  55. 4 4
      mjava-tonglibo/src/main/resources/application-prod.yml
  56. 27 23
      mjava-tonglibo/src/main/resources/mapper/MachineDataMapper.xml
  57. 19 0
      mjava-zhiwei/src/main/java/com/malk/zhiwei/controller/ZwErpController.java
  58. 34 1
      mjava-zhiwei/src/main/java/com/malk/zhiwei/entity/CustomerModel.java
  59. 1 1
      mjava-zhiwei/src/main/java/com/malk/zhiwei/entity/FBillHead.java
  60. 1 1
      mjava-zhiwei/src/main/java/com/malk/zhiwei/entity/SaleOrderModel.java
  61. 68 0
      mjava-zhiwei/src/main/java/com/malk/zhiwei/schedule/ScheduleTask.java
  62. 30 0
      mjava-zhiwei/src/main/java/com/malk/zhiwei/service/ZwService.java
  63. 826 2
      mjava-zhiwei/src/main/java/com/malk/zhiwei/service/impl/ZwServiceImpl.java
  64. 1 1
      mjava-zhiwei/src/main/resources/application-dev.yml
  65. 46 0
      mjava-zhiwei/src/main/resources/application-prod.yml
  66. 1 1
      mjava-zhiwei/src/main/resources/application.yml
  67. 21 3
      mjava-zhiwei/src/test/java/com/malk/zhiwei/JdTest.java
  68. 24 0
      mjava-zhongche/pom.xml
  69. 29 0
      mjava-zhongche/src/main/java/com/malk/zhongche/controller/ZhongcheController.java
  70. 12 0
      mjava-zhongche/src/main/java/com/malk/zhongche/service/ZhongcheService.java
  71. 238 0
      mjava-zhongche/src/main/java/com/malk/zhongche/service/impl/ZhongcheServiceImpl.java
  72. 9 5
      mjava-zhongche/src/main/resources/application-dev.yml
  73. 12 8
      mjava-zhongche/src/main/resources/application-prod.yml
  74. 4 0
      mjava-zhongche/src/test/java/com/malk/zhongche/ZcTest.java

+ 3 - 2
mjava-boyang/src/main/java/com/malk/boyang/service/impl/BoyangServiceImpl.java

@@ -120,8 +120,9 @@ public class BoyangServiceImpl implements BoyangService {
                 case "TextField-K2AD4O5B"://文件名称
                     subject = UtilMap.getString(formComponentValue, "value");
 
-                    //将subject里的"/"替换为","
-                    subject = subject.replaceAll("/",",");
+                    //不支持: $\/:*?"<>|
+                    subject = subject.replaceAll("[$/:*?\"<>]"," ");
+
                     break;
                 case "DDSelectField_RIHDKAA2UK00"://文件类型
                     String fileType = UtilMap.getString(formComponentValue, "value");

+ 4 - 0
mjava-fenggefushi/src/main/java/com/malk/fenggefushi/service/HeiHuOrderService.java

@@ -4,6 +4,7 @@ package com.malk.fenggefushi.service;
 import com.fasterxml.jackson.core.JacksonException;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.malk.server.common.McR;
+import lombok.SneakyThrows;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 
@@ -45,6 +46,9 @@ public interface HeiHuOrderService {
     /*采购订单定时同步*/
     McR purchaseSchedule(List<Map<String, Object>> dataList) throws JacksonException;
 
+    @SneakyThrows
+    McR purchaseScheduleTest(List<Map<String, Object>> dataList);
+
     List<Map<String, Object>> queryAllPurchase();
 
     McR purchaseUpdateSchedule() throws JacksonException;

Fichier diff supprimé car celui-ci est trop grand
+ 974 - 322
mjava-fenggefushi/src/main/java/com/malk/fenggefushi/service/Impl/HeiHuOrderServiceImpl.java


+ 7 - 6
mjava-huagao/src/main/java/com/malk/huagao/service/impl/EqbServiceImpl.java

@@ -426,12 +426,12 @@ public class EqbServiceImpl implements EqbService {
             String xssl = UtilMap.getString(xshtmxList.get(i), "numberField_mfbx1pr4");//销售数量
             double lsdj = UtilMap.getDouble(xshtmxList.get(i), "numberField_mf50cbri");//零售单价
             double pfyhdj = UtilMap.getDouble(xshtmxList.get(i), "numberField_mf50cbrj");//批发优惠单价
-            String zbq = UtilMap.getString(xshtmxList.get(i), "textField_mjas1rkx");//质保期
-
+            int zbq = UtilMap.getInt(xshtmxList.get(i), "numberField_mjb71qay");//质保期
+            String zbqValue = zbq > 0 ? zbq + "年" : "";
             if (i == 0){
-                xshtmx.add(getRowMap(false,i+1,cpmc,cpxh,dw,lsdj,pfyhdj,zbq));
+                xshtmx.add(getRowMap(false,i+1,cpmc,cpxh,dw,lsdj,pfyhdj,zbqValue));
             }else {
-                xshtmx.add(getRowMap(true,i+1,cpmc,cpxh,dw,lsdj,pfyhdj,zbq));
+                xshtmx.add(getRowMap(true,i+1,cpmc,cpxh,dw,lsdj,pfyhdj,zbqValue));
             }
         }
         Map jxsComponent16 = new HashMap();
@@ -558,10 +558,11 @@ public class EqbServiceImpl implements EqbService {
             double zke = UtilMap.getDouble(xshtmxList.get(i), "numberField_mjb71qao");//折扣额
             String bz = UtilMap.getString(xshtmxList.get(i), "textField_mjb71qaq");//备注
 
+            String zbqValue = zbq > 0 ? zbq + "年" : "";
             if (i == 0){
-                xshtmx.add(getRowMap(false,cpmc,cpxh,dw,xssl,hsdj,zbq+"年",smzs,jshj,zke,bz));
+                xshtmx.add(getRowMap(false,cpmc,cpxh,dw,xssl,hsdj,zbqValue,smzs,jshj,zke,bz));
             }else {
-                xshtmx.add(getRowMap(true,cpmc,cpxh,dw,xssl,hsdj,zbq+"年",smzs,jshj,zke,bz));
+                xshtmx.add(getRowMap(true,cpmc,cpxh,dw,xssl,hsdj,zbqValue,smzs,jshj,zke,bz));
             }
         }
         Map jxsComponent9 = new HashMap();

+ 6 - 0
mjava-huagao/src/main/java/com/malk/huagao/service/impl/KdYdDeliveryServiceImpl.java

@@ -369,6 +369,12 @@ public class KdYdDeliveryServiceImpl extends ServiceImpl<KdYdDeliveryMapper, KdY
             } catch (Exception e) {
                 log.error("创建新单据失败,dz=" + dz, e);
             }
+            try {
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                log.error("线程被中断", e);
+            }
         }
     }
 

+ 3 - 2
mjava-huagao/src/main/java/com/malk/huagao/service/impl/KdYdOrderServiceImpl.java

@@ -197,7 +197,7 @@ public class KdYdOrderServiceImpl extends ServiceImpl<KdYdOrderMapper, KdYdOrder
                     Map item = tableField.get(i);
                     Map<String, Object> table1Map = new HashMap<>();
 
-                    int detailId = parseInt(safeGetString(item, "numberField_mjzfodew"), 0);
+                    int detailId = parseInt(safeGetString(item, "numberField_mjzfodew"), 1);
                     String wlbm = safeGetString(item, "textField_mfbx1pqt");
 //                    String wlbm = "010101010003";
                     String wlmc = safeGetString(item, "textField_mfbx1pqs");
@@ -399,6 +399,7 @@ public class KdYdOrderServiceImpl extends ServiceImpl<KdYdOrderMapper, KdYdOrder
 
             Map formData1 = ddrNew.getFormData();
             String ddje = UtilMap.getString(formData1, "numberField_mfxv2vgj");
+            Long zhcjrq = UtilMap.getLong(formData1, "dateField_mejowmnb");
 
             // 订单金额校验
             if (ddje == null || ddje.trim().isEmpty()) {
@@ -560,7 +561,7 @@ public class KdYdOrderServiceImpl extends ServiceImpl<KdYdOrderMapper, KdYdOrder
             Map<String, Object> formData = new HashMap<>();
 
             // 必须更新的字段
-            formData.put("dateField_mjm9k35j", dddateTimestampStr);  // 最后成交日期
+            formData.put("dateField_mjm9k35j", zhcjrq);  // 最后成交日期
             formData.put("numberField_mjm9k35k", totalAmount);       // 累计金额
             formData.put("selectField_mjsco9d4", khsx);              // 销售属性
 

+ 6 - 0
mjava-jinlun/src/main/java/com/malk/jinlun/schedule/JinlunTask.java

@@ -56,4 +56,10 @@ public class JinlunTask {
         jinlunTaskService.syncXingneng();
     }
 
+    //定时同步销售订单
+    @Scheduled(cron = "0 6 0 * * ?")
+    public void syncSaleOrder(){
+        jinlunTaskService.syncSaleOrder();
+    }
+
 }

+ 4 - 1
mjava-jinlun/src/main/java/com/malk/jinlun/service/CpClient.java

@@ -1,5 +1,6 @@
 package com.malk.jinlun.service;
 
+import java.util.List;
 import java.util.Map;
 
 public interface CpClient {
@@ -11,7 +12,9 @@ public interface CpClient {
 
     Map getCpBo(String schemaCode, String objectId, String userId);
 
-    Map getCpBoList(String schemaCode, Map queryCondition,int page, int size, String userId);
+    Map getCpBoList(String schemaCode, Map queryCondition, Map options,int page, int size, String userId);
+
+    List<Map> getCpUserInfo(String corpId, List<String> departmentIds, List<String> ids, String mobile, String name, int page, int size);
 
     Map getCpBoResultData(Map result);
 

+ 3 - 0
mjava-jinlun/src/main/java/com/malk/jinlun/service/JinlunTaskService.java

@@ -12,4 +12,7 @@ public interface JinlunTaskService {
     void syncSaleReturn();
 
     void syncXingneng();
+
+    void syncSaleOrder();
+
 }

+ 41 - 1
mjava-jinlun/src/main/java/com/malk/jinlun/service/impl/CpClientImpl.java

@@ -12,7 +12,9 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 @Service
 public class CpClientImpl implements CpClient {
@@ -139,11 +141,12 @@ public class CpClientImpl implements CpClient {
      * @return
      */
     @Override
-    public Map getCpBoList(String schemaCode, Map queryCondition,int page, int size, String userId){
+    public Map getCpBoList(String schemaCode, Map queryCondition, Map options,int page, int size, String userId){
         Map body = new HashMap();
 
         body.put("queryCondition",queryCondition);
         body.put("schemaCode",schemaCode);
+        body.put("options",options);
         body.put("page",page);
         body.put("size",size);
         body.put("showTotal",true);
@@ -163,6 +166,43 @@ public class CpClientImpl implements CpClient {
         return result;
     }
 
+    /**
+     * 云枢分页查询用户详情
+     * @param corpId
+     * @param departmentIds
+     * @param ids
+     * @param mobile
+     * @param name
+     * @param page
+     * @param size
+     * @return
+     */
+    @Override
+    public List<Map> getCpUserInfo(String corpId, List<String> departmentIds, List<String> ids, String mobile, String name, int page, int size) {
+        Map body = new HashMap();
+        if (Objects.nonNull(corpId)) body.put("corpId",corpId);
+        if (Objects.nonNull(departmentIds)) body.put("departmentIds",departmentIds);
+        if (Objects.nonNull(ids)) body.put("ids",ids);
+        if (Objects.nonNull(mobile)) body.put("mobile",mobile);
+        if (Objects.nonNull(name)) body.put("name",name);
+
+        body.put("page",page);
+        body.put("size",size);
+
+        String s = UtilHttp.doPost(cloudpivotConfig.getRedirectUri() + "openapi/v3/organization/user/detail/query", CloudpivotConfig.initTokenHeader(getCpAccessToken()), null, body);
+
+        Map result = (Map) JSONObject.parse(s);
+
+        isSuccess(result);
+
+        Map data = UtilMap.getMap(result, "data");
+
+        List<Map> content = UtilMap.getList(data, "content");
+
+        return content;
+    }
+
+
     //获取云枢表单详情返回结果中单据字段值
     @Override
     public Map getCpBoResultData(Map result){

Fichier diff supprimé car celui-ci est trop grand
+ 248 - 6
mjava-jinlun/src/main/java/com/malk/jinlun/service/impl/JinlunTaskServiceImpl.java


+ 2 - 2
mjava-jinlun/src/main/resources/application-dev.yml

@@ -5,7 +5,7 @@ server:
 
 spring:
   datasource:
-    url: jdbc:mysql://192.168.0.12:3306/cloudpivot?serverTimezone=GMT%2B8
+    url: jdbc:mysql://172.16.10.1:3306/cloudpivot?serverTimezone=GMT%2B8
     username: root
     password: test123456!@#$%
     driver-class-name: com.mysql.cj.jdbc.Driver
@@ -40,7 +40,7 @@ cloudpivot:
   grant_type: client_credentials
   client_id: xclient
   client_secret: 0a417ecce58c31b32364ce19ca8fcd15
-  redirect_uri: http://192.168.0.12/api/
+  redirect_uri: http://172.16.10.1/api/
   operator_user_id: 8ac194c0811240a6b483ebc86aeb9147
 
 kingdee:

+ 2 - 2
mjava-jinlun/src/main/resources/application-prod.yml

@@ -5,7 +5,7 @@ server:
 
 spring:
   datasource:
-    url: jdbc:mysql://192.168.0.12:3306/cloudpivot?serverTimezone=GMT%2B8
+    url: jdbc:mysql://172.16.10.1:3306/cloudpivot?serverTimezone=GMT%2B8
     username: root
     password: test123456!@#$%
     driver-class-name: com.mysql.cj.jdbc.Driver
@@ -40,7 +40,7 @@ cloudpivot:
   grant_type: client_credentials
   client_id: xclient
   client_secret: 0a417ecce58c31b32364ce19ca8fcd15
-  redirect_uri: http://192.168.0.12/api/
+  redirect_uri: http://172.16.10.1/api/
   operator_user_id: 8ac194c0811240a6b483ebc86aeb9147
 
 kingdee:

+ 4 - 0
mjava-jinlun/src/test/java/com/malk/jinlun/DdTest.java

@@ -71,6 +71,10 @@ public class DdTest {
     public void test7() {
         jinlunTaskService.syncSaleReturn();
     }
+    @Test
+    public void test16() {
+        jinlunTaskService.syncSaleOrder();
+    }
 
     @Test
     public void test8() {

+ 26 - 0
mjava-kabeiyi/pom.xml

@@ -45,6 +45,32 @@
             <artifactId>alibabacloud-ocr_api20210707</artifactId>
             <version>3.0.2</version>
         </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.34</version> <!-- 推荐使用最新稳定版 -->
+            <scope>provided</scope> <!-- 必须是 provided -->
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>8.0.33</version>  <!-- 必须 >= 8.0 -->
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.5.3.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.14</version> <!-- 4.x 版本 -->
+        </dependency>
+        <dependency>
+            <groupId>org.json</groupId>
+            <artifactId>json</artifactId>
+            <version>20231013</version> <!-- 或最新版本 -->
+        </dependency>
 
     </dependencies>
 

+ 35 - 0
mjava-kabeiyi/src/main/java/com/malk/kabeiyi/controller/KabeiyiController.java

@@ -1,6 +1,8 @@
 package com.malk.kabeiyi.controller;
 
+import com.malk.kabeiyi.entity.OperatingRecordEntity;
 import com.malk.kabeiyi.service.KabeiyiService;
+import com.malk.kabeiyi.service.OperatingRecordService;
 import com.malk.server.common.McR;
 import com.malk.service.dingtalk.DDClient;
 import com.malk.service.dingtalk.DDClient_Workflow;
@@ -27,6 +29,9 @@ public class KabeiyiController {
     @Autowired
     private KabeiyiService kabeiyiService;
 
+    @Autowired
+    private OperatingRecordService  operatingRecordServiceImpl;
+
     //审批实例url前缀
     private static final String PROC_INST_PREFIX_URL = "https://aflow.dingtalk.com/dingtalk/web/query/pchomepage.htm?from=oflow&op=true&corpid=dingc3a744cb591a7346f2c783f7214b6d69#/plainapproval?procInstId=";
     @GetMapping("test")
@@ -108,4 +113,34 @@ public class KabeiyiController {
         kabeiyiService.addVoucher(map);
         return McR.success();
     }
+
+//    付款推送cbs
+    @PostMapping("pushCbs")
+    public McR puchCBS(@RequestBody Map map){
+        kabeiyiService.puchCBS(map);
+        return McR.success();
+    }
+
+//    定时查询cbs付款情况并推送u8凭证
+    @Scheduled(cron = "0 0/40 8-19 * * ?")
+    public McR schedulePaymentCBSToU8() {
+        try {
+            String[] statusList = {"1"};
+            List<OperatingRecordEntity> rescords = operatingRecordServiceImpl.findByStatusAndResCode(statusList);
+            log.info("开始获取排程单,并推送用友,推送数量为:{}",rescords.size());
+            if(rescords.isEmpty() || rescords.size()==0){
+                log.info("没有需要推送的订单。");
+                return McR.success();
+            }
+            for(OperatingRecordEntity entity:rescords){
+                log.info("开始推送订单:{}",entity.toString());
+                kabeiyiService.schedulePaymentCBSToU8(entity);
+            }
+
+            return McR.success();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
 }

+ 5 - 0
mjava-kabeiyi/src/main/java/com/malk/kabeiyi/service/KabeiyiService.java

@@ -1,5 +1,6 @@
 package com.malk.kabeiyi.service;
 
+import com.malk.kabeiyi.entity.OperatingRecordEntity;
 import com.malk.server.common.McR;
 import org.springframework.scheduling.annotation.Async;
 
@@ -39,4 +40,8 @@ public interface KabeiyiService {
     void addVoucher(Map map);
 
     String getWeekRange(String dateStr);
+
+    void puchCBS(Map map);
+
+    void schedulePaymentCBSToU8(OperatingRecordEntity entity);
 }

Fichier diff supprimé car celui-ci est trop grand
+ 612 - 393
mjava-kabeiyi/src/main/java/com/malk/kabeiyi/service/impl/KabeiyiServiceImpl.java


+ 37 - 0
mjava-kabeiyi/src/main/resources/application-dev.yml

@@ -17,6 +17,13 @@ logging:
   level:
     com.malk.*: debug
 
+spring:
+  datasource:
+    url: jdbc:mysql://114.55.244.55:3306/kby?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
+    username: root
+    password: Kabeiyi@2025++
+    driver-class-name: com.mysql.cj.jdbc.Driver
+
 mybatis-plus:
   configuration:
     #开启驼峰命名自动映射
@@ -70,3 +77,33 @@ u8:
   appKey : opa52c74dd3e0563458
   appSecret : 5b96fad7470a489bbae369ec79406fb1
 
+#cbs:
+#  ADDRESS: https://cbs8-openapi-reprd.csuat.cmburl.cn/
+#  APP_ID: WmBnthl
+#  APP_SECRET: e8f2a01b20ad4a31ed2f1783578db4cfde1badb5
+#  GRANT_TYPE: client_credentials
+#  PLATFORM_PUBLIC_KEY: 04D56804DC5CB1BC710E6DA73FD9FEDECD82110B0D1B629688C6849AE349BE5B3CB1A5C11528B7ECDCDC2CC20464B232F54C01F2C3B049EEBB4A8158B8C006987A
+#  ENTERPRISE_PRIVATE_KEY: bbb04781d69d4d74a707ee3b22dd28e73190d5919c5279c5de0d4562509182f7
+
+yida:
+  company: selectField_lxwwvggb # 公司抬头
+  schPayAccount : selectField_lxydz0ub  # 付款账号
+  revName: textField_lxwwvggc # 收款人名称
+  revAccount: textField_lxwwvgge # 收款账号
+  revBankName: textField_lxwwvggd # 收款银行
+  revCnapsCode: numberField_lycr2xlb # 收款银行联行号
+  deptName: textField_m2sekyf7 # 部门名称
+  orderCode: textField_lxwwvggg # 合同(订单)名称编号
+  dsSequence: numberField_m2o5b8sh # 数据源序号
+  type: selectField_m2sdpe2p # 类型 固定:采购部专用资金审批
+  purpose: textField_lxwwvggy # 付款用途
+  currency: textField_mhivb4yf # 币种
+  expectTime: dateField_lxwwvggf # 预计付款时间
+  displayUnitCode: textField_mhiyxcb3 # 显示单位编码
+  applyAmount: numberField_lxwwvggi # 申请金额
+  details: tableField_lxwwvggl # 付款明细
+  producter: textField_mhiyxcb4 # 制单人
+  detailMapping:
+    productName: textField_lxwwvggm  #货物或劳务名称
+
+

+ 14 - 0
mjava-kabeiyi/src/main/resources/application-prod.yml

@@ -16,6 +16,12 @@ logging:
   path: /home/server/kabeiyi/log/
   level:
     com.malk.*: info
+spring:
+  datasource:
+    url: jdbc:mysql://114.55.244.55:3306/kby?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC
+    username: root
+    password: Kabeiyi@2025++
+    driver-class-name: com.mysql.cj.jdbc.Driver
 
 mybatis-plus:
   configuration:
@@ -69,3 +75,11 @@ u8:
   toAccount: kbeapi
   appKey : opa52c74dd3e0563458
   appSecret : 5b96fad7470a489bbae369ec79406fb1
+
+cbs:
+  ADDRESS: https://cbs8-openapi-reprd.csuat.cmburl.cn/
+  APP_ID: WmBnthl
+  APP_SECRET: e8f2a01b20ad4a31ed2f1783578db4cfde1badb5
+  GRANT_TYPE: client_credentials
+  PLATFORM_PUBLIC_KEY: 04CF771DF8D041481D91F274DADDD404EB271ABB2EF1AF287FF48753477C30B60F0262D21430B6D26AF20A62C5E6D83735EAF2F011C71901661E4F0AF4B9DFA6F6
+  ENTERPRISE_PRIVATE_KEY: 24c0ebb4b3c074ce38318c1a83449200c472bb6ef7bbfe8a7146128e70f96571

+ 1 - 1
mjava-kabeiyi/src/main/resources/application.yml

@@ -1,6 +1,6 @@
 spring:
   profiles:
-    active: prod
+    active: dev
   servlet:
     multipart:
       max-file-size: 100MB

+ 3 - 5
mjava-lilin/src/main/java/com/malk/lilin/Controller/LiLinController.java

@@ -17,10 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
 
 @RestController
 @Slf4j
@@ -37,7 +34,7 @@ public class LiLinController {
     @Autowired
     private DDConf ddConf;
     @GetMapping("/test")
-    public McR test() {
+    public McR test() throws IOException {
 //        List<Map> list = (List<Map>) ydClient.queryData(YDParam.builder()
 //                .formUuid("FORM-754586D31BF6414586E5C20DB3774A7320CV")
 //                .searchFieldJson(JSONObject.toJSONString(Arrays.asList(
@@ -60,6 +57,7 @@ public class LiLinController {
 //                        .build(), YDConf.FORM_OPERATION.multi_update);
 //            }
 //        }
+         liLinService.lilinLS(new HashMap<>());
         return McR.success();
     }
 

+ 93 - 56
mjava-lilin/src/main/java/com/malk/lilin/Service/impl/LiLinServiceImpl.java

@@ -921,58 +921,98 @@ public class LiLinServiceImpl implements LiLinService {
                 accountNo = accountNo.trim();
 
                 log.info("开始对账单同步,accountNo: {}", accountNo);
-
-                // 准备时间范围
+// 准备时间范围
                 String dayFromId = LocalDate.now().minusDays(8).format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                 String dayToId = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+                // 准备时间范围
+//                String dayFromId = LocalDate.of(2026, 2, 26).format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+//                String dayToId = LocalDate.of(2026, 2, 26).format(DateTimeFormatter.ofPattern("yyyyMMdd"));
+
+                // ========== 分页查询 ==========
+                int pageSize = 20;
+                int pageNow = 1;
+                boolean hasMore = true;
+                List<JSONObject> allStatementList = new ArrayList<>();
+
+                while (hasMore) {
+                    // 构建 POST 请求体
+                    MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
+                    String requestBodyStr = "securityCode=" + securityCode +
+                            "&accountNo=" + accountNo +
+                            "&dayFromId=" + dayFromId +
+                            "&dayToId=" + dayToId +
+                            "&instructionIdFlag=1" +
+                            "&pageNow=" + pageNow +
+                            "&trxFlag=R" +
+                            "&pageSize=" + pageSize;
+
+                    RequestBody body = RequestBody.create(mediaType, requestBodyStr);
+                    log.info("请求体: {},当前页: {}", requestBodyStr, pageNow);
+
+                    Request request = new Request.Builder()
+                            .url("https://x.xencio.com/c4c3/api/bs/list")
+                            .post(body)
+                            .addHeader("x-xencio-client-id", "7dc3a31209b94a91ba40a44358fe70eb")
+                            .addHeader("content-type", "application/x-www-form-urlencoded")
+                            .build();
+
+                    response = client.newCall(request).execute();
+
+                    if (!response.isSuccessful()) {
+                        log.error("银行接口调用失败,HTTP状态码: {}", response.code());
+                        break; // 当前账号查询失败,跳出分页循环
+                    }
 
-                // 构建 POST 请求体
-                MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
-                String requestBodyStr = "securityCode=" + securityCode +
-                        "&accountNo=" + accountNo +
-                        "&dayFromId=" + dayFromId +
-                        "&dayToId=" + dayToId +
-                        "&instructionIdFlag=1" +
-                        "&pageNow=1" +
-                        "&trxFlag=R" +
-                        "&pageSize=20";
-
-                RequestBody body = RequestBody.create(mediaType, requestBodyStr);
-
-                Request request = new Request.Builder()
-                        .url("https://x.xencio.com/c4c3/api/bs/list")
-                        .post(body)
-                        .addHeader("x-xencio-client-id", "7dc3a31209b94a91ba40a44358fe70eb")
-                        .addHeader("content-type", "application/x-www-form-urlencoded")
-                        .build();
-
-                response = client.newCall(request).execute();
-
-                if (!response.isSuccessful()) {
-                    log.error("银行接口调用失败,HTTP状态码: {}", response.code());
-                    continue; // 跳过当前账号
-                }
+                    String jsonStr = response.body().string();
+                    log.info("银行接口响应原始数据: {}", jsonStr);
 
-                String jsonStr = response.body().string();
-                log.debug("银行接口响应原始数据: {}", jsonStr);
+                    JSONObject jsonObject = JSON.parseObject(jsonStr);
+                    JSONObject data = jsonObject.getJSONObject("data");
+                    if (data == null) {
+                        log.info("响应中缺少 'data' 字段, accountNo: {}", accountNo);
+                        break;
+                    }
 
-                JSONObject jsonObject = JSON.parseObject(jsonStr);
-                JSONObject data = jsonObject.getJSONObject("data");
-                if (data == null) {
-                    log.error("响应中缺少 'data' 字段, accountNo: {}", accountNo);
-                    continue;
+                    JSONArray statementList = data.getJSONArray("searchBankStatementList");
+                    if (statementList == null || statementList.isEmpty()) {
+                        log.info("银行接口返回空列表,accountNo: {},pageNow: {}", accountNo, pageNow);
+                        break;
+                    }
+
+                    // 将当前页数据添加到总列表中
+                    for (int i = 0; i < statementList.size(); i++) {
+                        allStatementList.add(statementList.getJSONObject(i));
+                    }
+
+                    // 判断是否还有下一页
+                    // 方式1:如果返回的数据量小于 pageSize,说明是最后一页
+                    if (statementList.size() < pageSize) {
+                        hasMore = false;
+                        log.info("已查询完所有数据,总页数: {}", pageNow);
+                    } else {
+                        pageNow++;
+                        // 添加适当延迟,避免请求过快
+                        Thread.sleep(100);
+                    }
+
+                    // 关闭旧的response,准备下一次请求
+                    if (response != null) {
+                        response.close();
+                        response = null;
+                    }
                 }
 
-                JSONArray statementList = data.getJSONArray("searchBankStatementList");
-                if (statementList == null || statementList.isEmpty()) {
-                    log.info("银行接口返回空列表,accountNo: {}", accountNo);
+                log.info("账号 {} 共查询到 {} 条对账单记录", accountNo, allStatementList.size());
+
+                // ========== 处理所有分页数据 ==========
+                if (allStatementList.isEmpty()) {
+                    log.info("账号 {} 无数据需要处理", accountNo);
                     continue;
                 }
 
                 List<Map<String, String>> extractedList = new ArrayList<>();
 
-                for (int i = 0; i < statementList.size(); i++) {
-                    JSONObject item = statementList.getJSONObject(i);
+                for (JSONObject item : allStatementList) {
                     if (item == null) continue;
 
                     Map<String, String> extractedItem = new HashMap<>();
@@ -981,12 +1021,12 @@ public class LiLinServiceImpl implements LiLinService {
                     String crAmount = getStringValue(item, "crAmount");
                     String trxDate = getStringValue(item, "trxDate");
                     String createDate = getStringValue(item, "createDate");
-                    String accountName = getStringValue(item, "accountName"); // 本方账号名称
+                    String accountName = getStringValue(item, "accountName");
                     String userRemarks = getStringValue(item, "userRemarks");
                     String userMemo = getStringValue(item, "userMemo");
                     String transFlag = getStringValue(item, "transFlag");
                     String catalogName = getStringValue(item, "catalogName");
-                    String customerName = getStringValue(item, "customerName"); // 对手方账户名称
+                    String customerName = getStringValue(item, "customerName");
 
                     Long timestamp = null;
                     if (trxDate != null && !trxDate.isEmpty()) {
@@ -994,7 +1034,7 @@ public class LiLinServiceImpl implements LiLinService {
                             timestamp = LocalDateTime.parse(trxDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
                                     .atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                         } catch (Exception e) {
-                            log.warn("日期解析失败: {}", trxDate);
+                            log.info("日期解析失败: {}", trxDate);
                         }
                     }
                     Long timestamp1 = null;
@@ -1003,7 +1043,7 @@ public class LiLinServiceImpl implements LiLinService {
                             timestamp1 = LocalDateTime.parse(createDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
                                     .atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                         } catch (Exception e) {
-                            log.warn("日期解析失败: {}", createDate);
+                            log.info("日期解析失败: {}", createDate);
                         }
                     }
 
@@ -1019,7 +1059,7 @@ public class LiLinServiceImpl implements LiLinService {
                     // 检查是否已存在该对账单记录
                     boolean exists = false;
                     int maxRetries = 3;
-                    long retryDelayMs = 1000; // 1秒后重试
+                    long retryDelayMs = 1000;
 
                     for (int attempt = 1; attempt <= maxRetries; attempt++) {
                         try {
@@ -1034,11 +1074,10 @@ public class LiLinServiceImpl implements LiLinService {
                             ).getData();
 
                             exists = list != null && !list.isEmpty();
-                            break; // ✅ 查询成功,跳出重试循环
+                            break;
 
                         } catch (Exception e) {
                             String errorMsg = e.getMessage();
-                            // 🔁 判断是否是“可重试”的临时错误
                             boolean isTransientError = errorMsg != null &&
                                     (errorMsg.contains("temporary failure") ||
                                             errorMsg.contains("500") ||
@@ -1051,30 +1090,27 @@ public class LiLinServiceImpl implements LiLinService {
                                     attempt, bankStatementId, e.getMessage());
 
                             if (attempt == maxRetries) {
-                                // ❌ 最后一次重试仍失败,才抛出异常
-                                log.error("查询宜搭系统最终失败,已重试 {} 次,bankStatementId: {}",
+                                log.info("查询宜搭系统最终失败,已重试 {} 次,bankStatementId: {}",
                                         maxRetries, bankStatementId, e);
                                 throw new RuntimeException("查询宜搭失败,bankStatementId=" + bankStatementId, e);
                             }
 
                             if (isTransientError) {
-                                // ✅ 是临时错误,等待后重试
                                 try {
-                                    Thread.sleep(retryDelayMs * attempt); // 指数退避:1s, 2s, 3s...
+                                    Thread.sleep(retryDelayMs * attempt);
                                 } catch (InterruptedException ie) {
                                     Thread.currentThread().interrupt();
                                     throw new RuntimeException("重试等待被中断", ie);
                                 }
                             } else {
-                                // ❌ 非临时错误(如参数错误、表单不存在),直接放弃重试
-                                log.error("查询失败:非临时性错误,不再重试,bankStatementId: {}", bankStatementId, e);
+                                log.info("查询失败:非临时性错误,不再重试,bankStatementId: {}", bankStatementId, e);
                                 throw new RuntimeException("查询宜搭失败(非临时错误):" + errorMsg, e);
                             }
                         }
                     }
 
                     if (exists) {
-                        log.debug("记录已存在,跳过: bankStatementId={}", bankStatementId);
+                        log.info("记录已存在,跳过: bankStatementId={}", bankStatementId);
                         continue;
                     }
 
@@ -1108,7 +1144,6 @@ public class LiLinServiceImpl implements LiLinService {
                             khaccountName = customerName;
                         }
 
-
                         if (khformInstanceId == null || khaccountName == null) {
                             log.warn("未找到匹配的客户信息: customerName={}", customerName);
                         }
@@ -1158,10 +1193,12 @@ public class LiLinServiceImpl implements LiLinService {
 
             } catch (IOException e) {
                 log.error("网络IO异常: accountNo={}", accountNo, e);
+            } catch (InterruptedException e) {
+                log.error("线程中断异常: accountNo={}", accountNo, e);
+                Thread.currentThread().interrupt();
             } catch (Exception e) {
                 log.error("处理账号异常: accountNo={}", accountNo, e);
             } finally {
-                // 确保 response 被安全关闭
                 if (response != null) {
                     try {
                         response.close();

+ 5 - 5
mjava-lingmingguangzi/src/main/java/com/malk/lingmingguangzi/service/LingmingguangziServiceImpl.java

@@ -544,8 +544,8 @@ public class LingmingguangziServiceImpl implements LingmingguangziService {
             detail.put("die_model","");//
             return detail;
         }).collect(Collectors.toList());
-        //附件
-        List<Map> list2 = (List<Map>) formData.get("tableField_ly8fxusx");
+        //附件  20250413 附件过大可能上传超时 暂时不推送erp
+        /*List<Map> list2 = (List<Map>) formData.get("tableField_ly8fxusx");
 
         String[] ERP_FILEPATHS = new String[]{filePathSz,filePathXg,filePathZj,filePathHz};
         String[] ERP_ENVS = new String[]{"深圳","香港","浙江","杭州"};
@@ -585,7 +585,7 @@ public class LingmingguangziServiceImpl implements LingmingguangziService {
                         break;
                     }
                 }
-                /*if ("深圳".equals(type)){
+                if ("深圳".equals(type)){
                     //将downloadurl下载到本地
                     try {
                         downloadFile(ydDownloadUrl, filePathSz,fileName);
@@ -627,12 +627,12 @@ public class LingmingguangziServiceImpl implements LingmingguangziService {
                     } catch (UnsupportedEncodingException e) {
                         throw new RuntimeException(e);
                     }
-                }*/
+                }
 
                 return detail;
             }).collect(Collectors.toList());
             body.put("makSoFilesList",makSoFilesList);
-        }
+        }*/
         body.put("makSoDetailList",makSoDetailList);
 
 

+ 1 - 1
mjava-lingmingguangzi/src/main/resources/application.yml

@@ -1,6 +1,6 @@
 spring:
   profiles:
-    active: dev
+    active: prod
   servlet:
     multipart:
       max-file-size: 100MB

+ 2 - 2
mjava-mc/src/main/java/com/malk/mc/service/impl/McYdServiceImpl.java

@@ -700,8 +700,8 @@ public class McYdServiceImpl implements McYdService {
             }
 
             BigDecimal VirtualQuantity1 = null;
-            if(!data1.get("numberField_m8obn6wl_value").toString().isEmpty()){
-                VirtualQuantity1 = new BigDecimal( data1.get("numberField_m8obn6wl").toString());//虚拟数量
+            if(!data1.get("numberField_m8obn6wq_value").toString().isEmpty()){
+                VirtualQuantity1 = new BigDecimal( data1.get("numberField_m8obn6wq").toString());//虚拟数量
             }else {
                 VirtualQuantity1 = BigDecimal.valueOf(0);
             }

+ 1 - 1
mjava-mc/src/main/resources/application.yml

@@ -1,6 +1,6 @@
 spring:
   profiles:
-    active: prod
+    active: dev
   servlet:
     multipart:
       max-file-size: 100MB

+ 37 - 0
mjava-ounuo/src/main/java/com/malk/tuosi/entity/CommissionTable.java

@@ -0,0 +1,37 @@
+package com.malk.tuosi.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.math3.linear.PreconditionedIterativeLinearSolver;
+
+/**
+ * 用户实体类
+ * 注意:实体类使用驼峰命名,对应数据库的下划线命名
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class CommissionTable {
+    /*任务id*/
+    private String taskId;
+    /*任务名称*/
+    private String taskName;
+    /*任务类型*/
+    private String taskType;
+    /*客户*/
+    private String customer;
+    /*设计人员*/
+    private String designPerson;
+    /*所属部门*/
+    private String department;
+    /*设计等级*/
+    private String designLevel;
+    /*是否扩版*/
+    private String expandOr;
+    /*设计扩版数量*/
+    private String addedPlates;
+    /*单价*/
+    private String price;
+
+}

+ 7 - 1
mjava-ounuo/src/main/java/com/malk/tuosi/entity/PersonalMonthlySuccessrate.java

@@ -20,8 +20,14 @@ public class PersonalMonthlySuccessrate {
     private String taskType;
     /*设计人员*/
     private String designPerson;
+    /*所属部门*/
+    private String department;
     /*客户*/
     private String customer;
-    /*时间*/
+    /*设计等级*/
+    private String designlevel;
+    /*完成时间*/
     private String time;
+    /*节点完成时间*/
+    private String deadlineTime;
 }

+ 13 - 0
mjava-ounuo/src/main/java/com/malk/tuosi/mapper/CommissionTableMapper.java

@@ -0,0 +1,13 @@
+package com.malk.tuosi.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.malk.tuosi.entity.CommissionTable;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 用户数据访问接口
+ * 注意:使用@Mapper注解,Spring Boot会自动扫描
+ */
+@Mapper
+public interface CommissionTableMapper extends BaseMapper<CommissionTable> {
+}

Fichier diff supprimé car celui-ci est trop grand
+ 1014 - 2
mjava-ounuo/src/main/java/com/malk/tuosi/schedule/ScheduleTask.java


+ 7 - 0
mjava-ounuo/src/main/java/com/malk/tuosi/service/CommissionTableService.java

@@ -0,0 +1,7 @@
+package com.malk.tuosi.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.malk.tuosi.entity.CommissionTable;
+
+public interface CommissionTableService extends IService<CommissionTable> {
+}

+ 13 - 0
mjava-ounuo/src/main/java/com/malk/tuosi/service/impl/CommissionTableServiceImpl.java

@@ -0,0 +1,13 @@
+package com.malk.tuosi.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.malk.tuosi.entity.CommissionTable;
+import com.malk.tuosi.mapper.CommissionTableMapper;
+import com.malk.tuosi.service.CommissionTableService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class CommissionTableServiceImpl extends ServiceImpl<CommissionTableMapper, CommissionTable> implements CommissionTableService {
+}

+ 7 - 4
mjava-ounuo/src/main/java/com/malk/tuosi/service/impl/TbServiceImpl.java

@@ -302,7 +302,8 @@ public class TbServiceImpl implements TBService {
                         header,
                         null,
                         body_AAA);
-                log.info("[创建任务自动更新确认流程]");
+                log.info("自动流程确认,任务id: {}",taskId );
+                log.info("[创建任务自动更新确认流程],{}",doPut);
             }
         }else if (event.equals("v3.task.node.status.update")) {
             /*群卡片推送*/
@@ -459,16 +460,18 @@ public class TbServiceImpl implements TBService {
                     message.put("openSpaceId", "dtv1.card//IM_GROUP.cid2niI2sTPksK5PHpfrLgCPQ==");
                 } else if ("姜华".equals(businessManager)) {
                     message.put("openSpaceId", "dtv1.card//IM_GROUP.cid+J9H07847VNwIYiLpNay0Q==");
-                }else if ("赵宇娟".equals(businessManager)) {
+                }else if ("赵宇娟".equals(businessManager) || "孟露".equals(businessManager)) {
                     message.put("openSpaceId", "dtv1.card//IM_GROUP.cidaUtMTIjDHM60UXFfHegKtg==");
-                } else if ("陈晶".equals(businessManager) || "郝俊秀".equals(businessManager) || "鲁萍".equals(businessManager)) {
+                } else if ("陈晶".equals(businessManager) || "郝俊秀".equals(businessManager)) {
                     message.put("openSpaceId", "dtv1.card//IM_GROUP.cidTppONwRCrkshRlCt28O+NA==");
                 }else if ("张曼".equals(businessManager)){
                     message.put("openSpaceId","dtv1.card//IM_GROUP.cidXES2AIusSs+mb9gD8i4w1w==");
                 }else if("张昆".equals(businessManager)){
                     message.put("openSpaceId","dtv1.card//IM_GROUP.cidI3G/EnCvlem5w3+qKfTMDA==");
-                }else if("谷晨".equals(businessManager)){
+                }else if("谷晨".equals(businessManager)){
                     message.put("openSpaceId","dtv1.card//IM_GROUP.cidqXtqGAN+Es7L/5m3uaZzSg==");
+                }else if("鲁萍".equals(businessManager)){
+                    message.put("openSpaceId","dtv1.card//IM_GROUP.cidibXgbOJLBc5L8xHNRzo5Jg==");
                 }
 //                message.put("openSpaceId", "dtv1.card//IM_GROUP.cidTppONwRCrkshRlCt28O+NA==");//正式群id:cidTppONwRCrkshRlCt28O+NA==   测试群id:cidKoVDKhvynnj+73h0uxSJBA==
                 message.put("cardTemplateId", "160b26bf-d699-49fc-a6dc-9cd20eed7750.schema");

+ 1 - 1
mjava-ounuo/src/main/resources/application.yml

@@ -1,3 +1,3 @@
 spring:
   profiles:
-    active: prod
+    active: dev

+ 2 - 0
mjava-pake/src/main/java/com/malk/pake/service/impl/PkProjectServiceImpl.java

@@ -447,6 +447,7 @@ public class PkProjectServiceImpl implements PkProjectService {
     public static String getBusinessTravelToken(){
         String result = HttpUtils.httpGet("https://btripopen.alibtrip.com/api/btrip-open-auth/v1/corp-token/action/take?app_key=pqm6bkfs0800&type=0&corp_id=open12pqm6bkfju87v16348dd896bc361558&app_secret=cHFtNmJrZnMwODAwXS1ceXpINzUsazUkVT1tejohZ1o");
         JSONObject jsonObject = JSONObject.parseObject(result);
+        log.info("获取token:{}",jsonObject);
         if (ObjectUtil.isNotNull(jsonObject) && Boolean.parseBoolean(jsonObject.get("success").toString())){
             Object module = jsonObject.get("module");
             jsonObject = JSONObject.parseObject(module.toString());
@@ -456,6 +457,7 @@ public class PkProjectServiceImpl implements PkProjectService {
     }
     //根据token和分页获取所有数据
     public static List<Object> getResult(String url,Map<String,Object> param){
+        log.info("开始第一次获取总数据量:{}",param);
         int pageSize = 100;
         if (param.containsKey("page_size")){
             pageSize = Integer.parseInt(param.get("page_size").toString());

+ 78 - 0
mjava-siku/src/main/java/com/malk/siku/controller/SikuController.java

@@ -75,6 +75,26 @@ public class SikuController {
         return sikuService.saveBxReimbursement2(map);
     }
 
+    /**
+     * 预付退回导入
+     * @param map
+     * @return
+     */
+    @PostMapping("/saveRepayment")
+    public McR saveRepayment(@RequestBody Map map){
+        return sikuService.saveRepayment(map);
+    }
+
+    /**
+     * 采购单可用预算校验-停用
+     * @param map
+     * @return
+     */
+    /*@PostMapping("/checkBudgetAmt")
+    public McR checkBudgetAmt(@RequestBody Map map){
+        return sikuService.checkBudgetAmt(map);
+    }*/
+
     //每刻云票收款单核销回调
     @PostMapping("/receive/callback")
     public McR callback(@RequestBody Map map){
@@ -105,6 +125,64 @@ public class SikuController {
         return McR.success();
     }
 
+    //每刻报销付款单完成回调
+    @PostMapping("/pay/callback")
+    public McR callback4(@RequestBody Map map){
+        log.info("每刻报销付款单完成回调:{}", JSONObject.toJSONString(map));
+
+        sikuService.invoiceWriteBack4(map);
+
+        return McR.success();
+    }
+
+    //每刻报销预付退回完成回调
+    @PostMapping("/repay/callback")
+    public McR callback5(@RequestBody Map map){
+        log.info("每刻报销预付退回完成回调:{}", JSONObject.toJSONString(map));
+
+        sikuService.invoiceWriteBack5(map);
+
+        return McR.success();
+    }
+
+    //每刻报销借款单完成回调(押金("是否项目相关"为【是】) 、借款单(项目))
+    @PostMapping("/loan/callback")
+    public McR callback6(@RequestBody Map map){
+        log.info("每刻报销借款单完成回调:{}", JSONObject.toJSONString(map));
+
+        sikuService.invoiceWriteBack6(map);
+
+        return McR.success();
+    }
+
+    //每刻报销还款单完成回调
+    @PostMapping("/repayment/callback")
+    public McR callback7(@RequestBody Map map){
+        log.info("每刻报销还款单完成回调:{}", JSONObject.toJSONString(map));
+
+        sikuService.invoiceWriteBack7(map);
+
+        return McR.success();
+    }
+
+    //每刻报销费用报销单完成回调(项目报销单(个人)、项目差旅报销单、打车(企业支付)("是否有项目"为【是】))
+    @PostMapping("/reimbursement2/callback")
+    public McR callback8(@RequestBody Map map){
+        log.info("每刻报销费用报销单完成回调:{}", JSONObject.toJSONString(map));
+
+        sikuService.invoiceWriteBack8(map);
+
+        return McR.success();
+    }
+
+    //每刻预算冻结/释放
+    @PostMapping("/updateBudget")
+    public McR updateBudget(@RequestBody Map map){
+        sikuService.updateBudget(map);
+
+        return McR.success();
+    }
+
     @GetMapping("/files/{fileId}")
     public ResponseEntity<Resource> getFileResource(
             @PathVariable String fileId,

+ 29 - 0
mjava-siku/src/main/java/com/malk/siku/schedule/SikuTask.java

@@ -0,0 +1,29 @@
+package com.malk.siku.schedule;
+
+import com.malk.siku.service.SikuTaskService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+
+/**
+ * @EnableScheduling 开启定时任务 [配置参考McScheduleTask]
+ */
+@Slf4j
+@Configuration
+@EnableScheduling
+@ConditionalOnProperty(name = {"enable.scheduling"})
+public class SikuTask {
+
+    @Autowired
+    private SikuTaskService sikuTaskService;
+
+    //定时同步借款台账
+    @Scheduled(cron = "0 0 0 * * ?")
+    public void syncMaterial(){
+        sikuTaskService.syncLoanManage();
+    }
+
+}

+ 16 - 0
mjava-siku/src/main/java/com/malk/siku/service/SikuService.java

@@ -20,4 +20,20 @@ public interface SikuService {
     void invoiceWriteBack3(Map map);
 
     McR saveBxReimbursement2(Map map);
+
+    McR checkBudgetAmt(Map map);
+
+    void updateBudget(Map map);
+
+    void invoiceWriteBack4(Map map);
+
+    void invoiceWriteBack5(Map map);
+
+    void invoiceWriteBack6(Map map);
+
+    void invoiceWriteBack7(Map map);
+
+    void invoiceWriteBack8(Map map);
+
+    McR saveRepayment(Map map);
 }

+ 6 - 0
mjava-siku/src/main/java/com/malk/siku/service/SikuTaskService.java

@@ -0,0 +1,6 @@
+package com.malk.siku.service;
+
+public interface SikuTaskService {
+    void syncLoanManage();
+
+}

Fichier diff supprimé car celui-ci est trop grand
+ 1166 - 46
mjava-siku/src/main/java/com/malk/siku/service/impl/SikuServiceImpl.java


+ 214 - 0
mjava-siku/src/main/java/com/malk/siku/service/impl/SikuTaskServiceImpl.java

@@ -0,0 +1,214 @@
+package com.malk.siku.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McException;
+import com.malk.server.dingtalk.DDR_New;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.siku.service.SikuTaskService;
+import com.malk.siku.utils.MkBxUtil;
+import com.malk.utils.UtilHttp;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Slf4j
+@Service
+public class SikuTaskServiceImpl implements SikuTaskService {
+    @Autowired
+    private YDClient ydClient;
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Override
+    public void syncLoanManage() {
+        try {
+            //删除宜搭借款台账
+            List<List<String>> formInstanceIdListList = new ArrayList<>();//实例id集合,每100条
+
+            DDR_New ddrNew = new DDR_New();
+            int pageSize = 50;
+            int pageNumber = 0;
+            do {
+                pageNumber++;
+
+                ddrNew = retryQueryData(YDParam.builder()
+                        .formUuid("FORM-14F79868B683481295062CD1D643E06EVB7B")
+                        .searchFieldJson("")
+                        .pageNumber(pageNumber)
+                        .pageSize(pageSize)
+                        .build(), YDConf.FORM_QUERY.retrieve_search_form_id);
+
+                formInstanceIdListList.addAll(Collections.singleton((List<String>) ddrNew.getData()));
+
+//                Thread.sleep(1000);
+            }while (ddrNew.getPageNumber() * pageSize < ddrNew.getTotalCount());
+
+            for (List<String> formInstanceIdList : formInstanceIdListList) {
+                if (!formInstanceIdList.isEmpty()){
+                    retryOperateData(YDParam.builder()
+                            .formUuid("FORM-14F79868B683481295062CD1D643E06EVB7B")
+                            .formInstanceIdList(formInstanceIdList)
+                            .build(), YDConf.FORM_OPERATION.delete_batch);
+                }
+            }
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+
+        //查询每刻最新借款台账
+        List<Map> loanManageList = MkBxUtil.loanManageList();
+
+        for (Map loanManage : loanManageList) {
+            String code = UtilMap.getString(loanManage, "code");//台账编号\
+            String formCode = UtilMap.getString(loanManage, "formCode");//借款单单据号
+
+            String legalEntityName = UtilMap.getString(loanManage, "legalEntityName");//所属公司
+            String departmentName = UtilMap.getString(loanManage, "departmentName");//借款部门
+            String employeeName = UtilMap.getString(loanManage, "employeeName");//借款人
+            List<String> employeeDdUser = getDdUserId(employeeName);
+            String responseUserName = UtilMap.getString(loanManage, "responseUserName");//负责人
+            List<String> responseDdUser = getDdUserId(responseUserName);
+
+            String formName = UtilMap.getString(loanManage, "formName");//事由
+            String formSubTypeName = UtilMap.getString(loanManage, "formSubTypeName");//单据类型
+            long submittedAt = UtilMap.getLong(loanManage, "submittedAt");//提单时间
+            long expectRepaymentTime = UtilMap.getLong(loanManage, "expectRepaymentTime");//预计归还时间
+            int loanAge = UtilMap.getInt(loanManage, "loanAge");//账龄
+            Double amount = UtilMap.getDouble(UtilMap.getMap(loanManage, "approvedAmount"), "amount");//借款金额
+            Double owedAmount = UtilMap.getDouble(UtilMap.getMap(loanManage, "owedAmount"), "amount");//未归还(未核销)
+            Double pendingAmount = UtilMap.getDouble(UtilMap.getMap(loanManage, "pendingAmount"), "amount");//核销中金额
+
+            //借款单详情
+            Map loanDetailInfo = MkBxUtil.loanDetailInfo(formCode);
+            Map customObject = UtilMap.getMap(loanDetailInfo, "customObject");
+
+            Map cf0 = UtilMap.getMap(customObject, "CF0");
+            String projectCode = UtilMap.getString(cf0, "detailBusinessCode");//项目流水号
+            String projectName = UtilMap.getString(cf0, "text");//项目名称
+
+            long settledAt = UtilMap.getLong(loanDetailInfo, "settledAt");//支付时间
+
+            Map formData = new HashMap();
+            formData.put("textField_mnsly3li",code);
+            formData.put("textField_mnsly3lb",legalEntityName);
+            formData.put("textField_mnsly3lc",departmentName);
+            formData.put("employeeField_mnsly3mc",employeeDdUser);
+            formData.put("employeeField_mnsly3md",responseDdUser);
+            formData.put("textField_mnsm8q6f",projectName);
+            formData.put("textField_mnwtwu9z",projectCode);
+            formData.put("textareaField_mnsly3ll",formName);
+            formData.put("textField_mnsly3lg",formSubTypeName);
+            formData.put("dateField_mnsly3lx",submittedAt);
+            formData.put("dateField_mnsly3ly",expectRepaymentTime);
+            formData.put("dateField_mnsly3m3",settledAt);
+            formData.put("numberField_mnsly3m4",loanAge);
+            formData.put("numberField_mnsly3m5",amount);
+            formData.put("numberField_mnsly3ma",owedAmount);
+            formData.put("numberField_mnsly3mb",pendingAmount);
+
+            //同步宜搭借款台账
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-14F79868B683481295062CD1D643E06EVB7B")
+                    .formDataJson(JSONObject.toJSONString(formData))
+                    .build(), YDConf.FORM_OPERATION.create);
+        }
+        System.out.println("111");
+
+    }
+
+
+    //自带重试的operateData方法
+    private Object retryOperateData(YDParam param, YDConf.FORM_OPERATION formOperation) {
+        int maxAttempts = 3; // 尝试的最大次数
+        int attempt = 0;
+
+        Object result = null;
+
+        while (attempt < maxAttempts) {
+            try {
+                result = ydClient.operateData(param, formOperation);
+
+                return result;
+            } catch (McException e) {
+                log.info("错误信息:{}",e.getMessage());
+                if (e.getMessage().equals("The request has failed due to a temporary failure of the server.")) {
+                    attempt++;
+                    // 线程睡眠3秒
+                    try {
+                        Thread.sleep(5000);
+                        log.info("尝试第{}次,param:{},FORM_OPERATION:{},异常信息:{}", attempt, JSONObject.toJSONString(param), formOperation,e.getMessage());
+                    } catch (InterruptedException ie) {
+                        Thread.currentThread().interrupt(); // 重新设置中断状态
+                        System.err.println("Sleep interrupted: " + ie.getMessage());
+                    }
+                }
+            } catch (Exception e) {
+                log.error("操作失败,param:{},FORM_OPERATION:{},异常信息:{}", JSONObject.toJSONString(param), formOperation,e.getMessage());
+
+                throw new RuntimeException(e);
+            }
+
+        }
+
+        throw new RuntimeException("超出最大重试次数,param:"+JSONObject.toJSONString(param)+",FORM_OPERATION:{}"+formOperation);
+    }
+
+
+    //自带重试的queryData方法
+    private DDR_New retryQueryData(YDParam param, YDConf.FORM_QUERY formQuery) {
+        int maxAttempts = 3; // 尝试的最大次数
+        int attempt = 0;
+
+        DDR_New result = null;
+
+        while (attempt < maxAttempts) {
+            try {
+                result = ydClient.queryData(param, formQuery);
+
+                return result;
+            } catch (McException e) {
+                log.info("错误信息:{}",e.getMessage());
+                if (e.getMessage().equals("The request has failed due to a temporary failure of the server.")) {
+                    attempt++;
+                    // 线程睡眠3秒
+                    try {
+                        Thread.sleep(5000);
+                        log.info("尝试第{}次,param:{},FORM_QUERY:{},异常信息:{}", attempt, JSONObject.toJSONString(param), formQuery,e.getMessage());
+                    } catch (InterruptedException ie) {
+                        Thread.currentThread().interrupt(); // 重新设置中断状态
+                        System.err.println("Sleep interrupted: " + ie.getMessage());
+                    }
+                }
+            } catch (Exception e) {
+                log.error("操作失败,param:{},FORM_QUERY:{},异常信息:{}", JSONObject.toJSONString(param), formQuery,e.getMessage());
+
+                throw new RuntimeException(e);
+            }
+
+        }
+
+        throw new RuntimeException("超出最大重试次数,param:"+JSONObject.toJSONString(param)+",FORM_QUERY:{}"+formQuery);
+    }
+
+    //根据员工名字匹配员工id
+    private List<String> getDdUserId(String Name){
+        HashMap body = new HashMap();
+
+        body.put("queryWord", Name);
+        body.put("offset",0);
+        body.put("size",1);
+
+        String s1 = UtilHttp.doPost("https://api.dingtalk.com/v1.0/contact/users/search", ddClient.initTokenHeader(), null, body);
+
+        List<String> list = JSONObject.parseObject(s1).getJSONArray("list").toJavaList(String.class);
+
+        return list;
+    }
+}

+ 154 - 6
mjava-siku/src/main/java/com/malk/siku/utils/MkBxUtil.java

@@ -16,15 +16,15 @@ import java.util.*;
  */
 @Slf4j
 public class MkBxUtil {
-
-    @Value("${mk.bx.appCode}")
+    //测试环境
     private final static String appCode = "AP52Y01LHHTAP9";
-
-    @Value("${mk.bx.appSecret}")
     private final static String appSecret = "N4WuERLteAUPaWebnsHy";
+    private final static String host = "ng.maycur.com";
 
-//    private final static String host = "ng-uat.maycur.com";//测试环境
-    private final static String host = "ng.maycur.com";//生产环境
+    //生产环境
+    /*private final static String appCode = "AP52RG1SCG8S6L";
+    private final static String appSecret = "YFTbD2MviqUwztBTbMWd";
+    private final static String host = "ng.maycur.com";*/
 
     private final Object $lock = new Object[0];
 
@@ -72,6 +72,48 @@ public class MkBxUtil {
 
     }
 
+    public static Map initTokenHeader(String thisAppCode,String thisAppSecret){
+
+        Map header = new HashMap();
+
+        String tokenId = UtilToken.get("invalid-tokenId-mkbx");
+        String entCode = UtilToken.get("invalid-entCode-mkbx");
+
+        if (StringUtils.isNotBlank(tokenId) && StringUtils.isNotBlank(entCode)) {
+            header.put("tokenId",tokenId);
+            header.put("entCode",entCode);
+
+            return header;
+        } else {
+            //每刻登录认证
+            Map body = new HashMap();
+
+            long timeMillis = System.currentTimeMillis();
+            body.put("appCode",thisAppCode);
+            body.put("secret",getSecret(thisAppCode,thisAppSecret,timeMillis));
+            body.put("timestamp",timeMillis);
+
+            Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/openapi/auth/login", null, null, body));
+
+            Map data = UtilMap.getMap(result, "data");
+
+            tokenId = UtilMap.getString(data, "tokenId");
+            entCode = UtilMap.getString(data, "entCode");
+
+            log.info("每刻报销tokenId, {}", tokenId);
+            log.info("每刻报销entCode, {}", entCode);
+
+            UtilToken.put("invalid-tokenId-mkbx", tokenId, EXPIRES_IN);
+            UtilToken.put("invalid-entCode-mkbx", entCode, EXPIRES_IN);
+
+            header.put("tokenId",tokenId);
+            header.put("entCode",entCode);
+
+            return header;
+        }
+
+    }
+
     //保存往来单位
     public static Map saveTradingPartner(Object body){
         Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/openapi/tradingPartner/batch/save", MkBxUtil.initTokenHeader(), null, body,(Map) null));
@@ -119,6 +161,16 @@ public class MkBxUtil {
         return expenseCodes;
     }
 
+    //还款单写入接口
+    public static Map receiveRepayment(Object body){
+        log.info("body:{}",JSONObject.toJSONString(body));
+        Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/openapi/receive/repayment", MkBxUtil.initTokenHeader(), null, body,(Map) null));
+
+        log.info("Result:{}",result);
+
+        return result;
+    }
+
     //费用类型查询
     public static String expenseTypeSearch(Object body){
         log.info("body:{}",JSONObject.toJSONString(body));
@@ -153,6 +205,102 @@ public class MkBxUtil {
         }
     }
 
+    //预算信息查询接口
+    public static List<Map> budgetInfo(Object body){
+        log.info("body:{}",JSONObject.toJSONString(body));
+        Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/openapi/budget/page", MkBxUtil.initTokenHeader(), null, body,(Map) null));
+
+        log.info("Result:{}",result);
+
+        Map data = UtilMap.getMap(result, "data");
+
+        if (Objects.nonNull(data)){
+            List<Map> list = UtilMap.getList(data, "list");
+
+            return list;
+        }else {
+            return null;
+        }
+    }
+
+    //批量编制预算额
+    public static Map batchBudget(Map body){
+        log.info("body:{}",JSONObject.toJSONString(body));
+        Map result = (Map) JSONObject.parse(UtilHttp.doPut("https://" + host + "/api/openapi/budget/unit/batch/limit", MkBxUtil.initTokenHeader(), null, body));
+
+        log.info("Result:{}",result);
+
+        return result;
+    }
+
+    //付款单详情
+    public static Map paymentDetailInfo(String formCode){
+        Map result = (Map) JSONObject.parse(UtilHttp.doGet("https://" + host + "/api/openapi/payment/detailInfo/" + formCode, MkBxUtil.initTokenHeader(), (Map) null));
+
+        log.info("Result:{}",result);
+
+        Map data = UtilMap.getMap(result, "data");
+
+        return data;
+    }
+
+    //报销单详情
+    public static Map reimburseDetailInfo(String formCode){
+        Map result = (Map) JSONObject.parse(UtilHttp.doGet("https://" + host + "/api/openapi/form/reimburse/" + formCode, MkBxUtil.initTokenHeader(), (Map) null));
+
+        log.info("Result:{}",result);
+
+        Map data = UtilMap.getMap(result, "data");
+
+        return data;
+    }
+
+    //还款单详情
+    public static Map repayDetailInfo(String formCode){
+        Map result = (Map) JSONObject.parse(UtilHttp.doGet("https://" + host + "/api/openapi/form/repayment/" + formCode, MkBxUtil.initTokenHeader(), (Map) null));
+
+        log.info("Result:{}",result);
+
+        Map data = UtilMap.getMap(result, "data");
+
+        return data;
+    }
+
+    //借款单详情
+    public static Map loanDetailInfo(String formCode){
+        Map result = (Map) JSONObject.parse(UtilHttp.doGet("https://" + host + "/api/openapi/form/loan/" + formCode, MkBxUtil.initTokenHeader("AP52RG1SCG8S6L","YFTbD2MviqUwztBTbMWd"), (Map) null));
+
+        log.info("Result:{}",result);
+
+        Map data = UtilMap.getMap(result, "data");
+
+        return data;
+    }
+
+    //借款单台账列表
+    public static List<Map> loanManageList(){
+        Boolean hasNextPage = false;
+
+        List<Map> totalList = new ArrayList<>();
+        int i = 1;
+        do {
+            Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/openapi/form/loan/manage", MkBxUtil.initTokenHeader("AP52RG1SCG8S6L","YFTbD2MviqUwztBTbMWd"),null, UtilMap.map("pageNo, pageSize",i,100)));
+
+            log.info("Result:{}",result);
+
+            Map data = UtilMap.getMap(result, "data");
+
+            List<Map> list = UtilMap.getList(data, "list");
+
+            totalList.addAll(list);
+
+            hasNextPage = UtilMap.getBoolean(data, "hasNextPage");
+
+            i++;
+        }while (hasNextPage);
+
+        return totalList;
+    }
 
     private static String getSecret(String appCode, String appSecret, long timeMillis){
         log.info("time:{}",timeMillis);

+ 17 - 6
mjava-siku/src/main/java/com/malk/siku/utils/MkYpUtil.java

@@ -18,15 +18,15 @@ import java.util.Map;
  */
 @Slf4j
 public class MkYpUtil {
-
-    @Value("${mk.yp.appCode}")
+    //测试环境
     private final static String appCode = "AP53EP1SVDS1N9";
-
-    @Value("${mk.yp.appSecret}")
     private final static String appSecret = "qF4nm3nPnyXYcrWcr5jl";
+    private final static String host = "pms-uat.maycur.com";
 
-    private final static String host = "pms-uat.maycur.com";//测试环境
-//    private final static String host = "pms.maycur.com";//生产环境
+    //生产环境
+    /*private final static String appCode = "AP565SLVOI76UA";
+    private final static String appSecret = "sGoMNMSbaw4MWLLbUTtPye2k6trtfIs1";
+    private final static String host = "pms.maycur.com";*/
 
     private final Object $lock = new Object[0];
 
@@ -106,6 +106,17 @@ public class MkYpUtil {
         return data2;
     }
 
+    //员工批量查询接口
+    public static List<Map> getAllEmployee(){
+        Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/openapi/employee/getAllEmployee", MkYpUtil.initTokenHeader(), null, null,(Map) null));
+
+        log.info("Result:{}",result);
+
+        List<Map> data = UtilMap.getList(result, "data");
+
+        return data;
+    }
+
     private static String getSecret(String appCode, String appSecret, long timeMillis){
         log.info("time:{}",timeMillis);
 

+ 0 - 8
mjava-siku/src/main/resources/application-dev.yml

@@ -26,14 +26,6 @@ aliwork:
   systemToken: Y2D66JB1A0B2OMK6OMB29AB8VMP43KJ7UCDKMG46
 
 mk:
-  #每刻报销-测试环境
-  bx:
-    appCode: AP52Y01LHHTAP9
-    appSecret: N4WuERLteAUPaWebnsHy
-  #每刻云票-测试环境
-  yp:
-    appCode: AP53EP1SVDS1N9
-    appSecret: qF4nm3nPnyXYcrWcr5jl
   downloadFilePath: d:\\
   downloadUrl: http://localhost:9037/api/siku/
 

+ 1 - 9
mjava-siku/src/main/resources/application-prod.yml

@@ -4,7 +4,7 @@ server:
     context-path: /api/siku
 
 enable:
-  scheduling: false
+  scheduling: true
 logging:
   config: classpath:logback-spring.xml
   path: /home/server/siku/log/
@@ -26,13 +26,5 @@ aliwork:
   systemToken: Y2D66JB1A0B2OMK6OMB29AB8VMP43KJ7UCDKMG46
 
 mk:
-  #每刻报销-测试环境
-  bx:
-    appCode: AP52Y01LHHTAP9
-    appSecret: N4WuERLteAUPaWebnsHy
-  #每刻云票-测试环境
-  yp:
-    appCode: AP53EP1SVDS1N9
-    appSecret: qF4nm3nPnyXYcrWcr5jl
   downloadFilePath: /home/server/siku/file/
   downloadUrl: https://poc.cloudpure.cn/api/siku/

+ 1 - 1
mjava-siku/src/main/resources/application.yml

@@ -1,6 +1,6 @@
 spring:
   profiles:
-    active: prod
+    active: dev
   servlet:
     multipart:
       max-file-size: 100MB

+ 25 - 1
mjava-siku/src/test/java/com.malk.siku/SkTest.java

@@ -1,9 +1,11 @@
 package com.malk.siku;
 
+import com.malk.siku.service.SikuTaskService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
 
@@ -11,13 +13,18 @@ import org.springframework.test.context.junit4.SpringRunner;
 @SpringBootTest
 @RunWith(SpringRunner.class)
 public class SkTest {
+    @Autowired
+    private SikuTaskService sikuTaskService;
+
     @Test
     public void getSecret(){
         //每刻报销-测试环境
         String appCode="AP52Y01LHHTAP9";
         String appSecret="N4WuERLteAUPaWebnsHy";
 
-
+        //每刻报销-生产环境
+        /*String appCode="AP52RG1SCG8S6L";
+        String appSecret="YFTbD2MviqUwztBTbMWd";*/
 
         //每刻云票-测试环境
         /*String appCode="AP53EP1SVDS1N9";
@@ -30,6 +37,23 @@ public class SkTest {
         log.info("s:{}",s);
     }
 
+    @Test
+    public void ssoGetToken(){
+        //生成token所使用的java代码
+        String ssoSecret = "EC52NRFQYEFIB5:h34BITN5HAtVMt82P9VvTRhFYpCXLgfo";//该秘钥获取路径“设置-安全设置-系统安全策略-SSO”(若无此入口,需项目经理在boss系统开通相关许可)
+        long timestamp = System.currentTimeMillis();
+        String userId = "HZ769";
+        String token = DigestUtils.sha256Hex((ssoSecret + ":" + userId + ":" + timestamp).getBytes());
+
+        System.out.println("timestamp:"+timestamp);
+        System.out.println("token:"+token);
+    }
+
+    @Test
+    public void test(){
+        sikuTaskService.syncLoanManage();
+    }
+
 
 
 

+ 0 - 1
mjava-tonglibo/pom.xml

@@ -22,7 +22,6 @@
             <groupId>commons-codec</groupId>
             <artifactId>commons-codec</artifactId>
         </dependency>
-
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>

+ 37 - 22
mjava-tonglibo/src/main/java/com/malk/tonglibo/controller/machineController.java

@@ -47,44 +47,51 @@ public class machineController {
             log.info("设备数据paramsStr:{}", paramsStr);
             String fixedStr = repairMalformedKFields(paramsStr);
             JSONObject params = JSONObject.parseObject(fixedStr);
-
             log.info("修复后设备数据JSON:{}", params);
-
-            // 解析时间
             LocalDateTime time;
             try {
                 time = LocalDateTime.parse((String) params.get("time"), FORMATTER);
             } catch (Exception e) {
-                log.warn("时间解析失败,使用当前时间。原值:{}", params.get("time"));
+                log.warn("时间解析失败:{}", params.get("time"));
                 time = LocalDateTime.now();
             }
             String timeStr = time.format(OUTPUT_FORMATTER);
-            String deviceId = params.getString("id");
+            String paramId = params.getString("id");
             Pattern kPattern = Pattern.compile("^k\\d+$");
             boolean hasValidData = false;
-            // 遍历所有 k* 字段,放入缓冲队列
             for (Map.Entry<String, Object> entry : params.entrySet()) {
                 String key = entry.getKey();
                 if (kPattern.matcher(key).matches()) {
                     try {
                         Object dataObj = entry.getValue();
                         if (dataObj instanceof List) {
+                            List<?> rawDataList = (List<?>) dataObj;
                             List<String> data = new ArrayList<>();
-                            for (Object item : (List<?>) dataObj) {
-                                if (item instanceof Number) {
-                                    data.add(item.toString());
-                                } else if (item == null) {
-                                    data.add("null");
+                            // 转换为字符串,并判断是否有有效值
+                            boolean fieldHasValidValue = false;
+                            for (Object item : rawDataList) {
+                                String strVal;
+                                if (item == null) {
+                                    strVal = "null";
                                 } else {
-                                    data.add(item.toString());
+                                    strVal = item.toString().trim();
+                                }
+                                data.add(strVal);
+                                // 判断这个值是否是“有效值”
+                                if (isValidDataValue(strVal)) {
+                                    fieldHasValidValue = true;
                                 }
                             }
-                            // 创建原始数据对象,放入缓冲队列
-                            RawDeviceData raw = new RawDeviceData(deviceId, time, timeStr, key, data);
-                            if (dataBuffer.offer(raw)) {
-                                hasValidData = true;
+                            // 只有当前字段至少有一个有效值,才放入缓冲队列
+                            if (fieldHasValidValue) {
+                                RawDeviceData raw = new RawDeviceData(paramId, time, timeStr, key, data);
+                                if (dataBuffer.offer(raw)) {
+                                    hasValidData = true;
+                                } else {
+                                    log.warn("缓冲队列已满,丢弃数据 设备编号={}, paramId={}", key, paramId);
+                                }
                             } else {
-                                log.warn("缓冲队列已满,丢弃数据 key={}, deviceId={}", key, deviceId);
+                                log.debug("字段 {} 的所有值均为无效(全0或空),跳过:{}", key, data);
                             }
                         }
                     } catch (Exception fieldEx) {
@@ -92,12 +99,15 @@ public class machineController {
                     }
                 }
             }
-            // 立即返回成功,不等待数据库写入
+
+            // ===== 最终判断:是否真的有有效数据 =====
             if (hasValidData) {
                 return McR.success("设备数据接收成功");
             } else {
+                log.warn("设备数据无效:所有 k* 字段均为 0 或空,paramId={}, time={}", paramId, timeStr);
                 return McR.errorParam("未解析到有效数据");
             }
+
         } catch (Exception e) {
             log.error("设备数据同步异常:", e);
             return McR.errorParam("设备数据同步异常");
@@ -113,7 +123,7 @@ public class machineController {
         for(int i = 0; i < machineData.size(); i++){
             MachineData machinedata = (MachineData) machineData.get(i);
             Map map =new HashMap();
-            map.put("content", machinedata.getMachineNo());
+            map.put("content", machinedata.getMachineFlag());
             map.put("value", machinedata.getJqyxsh());
             result.add(map);
         }
@@ -127,7 +137,7 @@ public class machineController {
         for(int i = 0; i < data.size(); i++){
             MachineData machinedata = (MachineData) data.get(i);
             Map map =new HashMap();
-            map.put("s", machinedata.getMachineNo());
+            map.put("s", machinedata.getMachineFlag());
             map.put("y", machinedata.getZcn());
             map.put("x", machinedata.getTimestr());
             result.add(map);
@@ -159,10 +169,15 @@ public class machineController {
         // 1. 修复 "k1":] → "k1":[]
         result = result.replaceAll("(\"k\\d+\"\\s*:\\s*)\\]", "$1[]");
         // 2. 修复 "k1":  → "k1":[]
-        //    (即冒号后直接跟逗号或其他字符,中间无内容)
-        //    先找这种结构:"k1": ,  或 "k1": }
         result = result.replaceAll("(\"k\\d+\"\\s*:\\s*)([\\,\\}])", "$1[]$2");
         return result;
     }
 
+    private boolean isValidDataValue(String value) {
+        if (value == null || value.isEmpty() || "null".equalsIgnoreCase(value)) {
+            return false;
+        }
+        return !value.matches("^0+(\\.0+)?$");
+    }
+
 }

+ 7 - 0
mjava-tonglibo/src/main/java/com/malk/tonglibo/entity/MachineData.java

@@ -39,8 +39,15 @@ public class MachineData {
     private String xjsj;
     private String tssj;
     private String zysj;
+    private String dn;
     @TableField("machineNo")
     private String machineNo;
+    @TableField("machineName")
+    private String machineName;
+    @TableField("machineCode")
+    private String machineCode;
+    @TableField("machineFlag")
+    private String machineFlag;
 
     private String timestr;
 

+ 5 - 4
mjava-tonglibo/src/main/java/com/malk/tonglibo/utils/ChangeDetector.java

@@ -20,10 +20,10 @@ public class ChangeDetector {
      * 判断当前数据是否为新状态(MD5 指纹不同)
      */
     public boolean isChanged(MachineData data) {
-        String paramId = data.getParamId();
+        String machineNo = data.getMachineNo();
         String fingerprint = generateFingerprint(data);
 
-        String lastFingerprint = lastFingerprintMap.get(paramId);
+        String lastFingerprint = lastFingerprintMap.get(machineNo);
         if (lastFingerprint == null) {
             return true; // 第一次上报,算变化
         }
@@ -34,8 +34,8 @@ public class ChangeDetector {
     /**
      * 记录当前指纹为最新状态
      */
-    public void recordAsCurrent(String paramId, String fingerprint) {
-        lastFingerprintMap.put(paramId, fingerprint);
+    public void recordAsCurrent(String machineNo, String fingerprint) {
+        lastFingerprintMap.put(machineNo, fingerprint);
     }
 
     String concatFields(MachineData data) {
@@ -62,6 +62,7 @@ public class ChangeDetector {
                 .append(defaultString(data.getXjsj()))
                 .append(defaultString(data.getTssj()))
                 .append(defaultString(data.getZysj()))
+                .append(defaultString(data.getDn()))
                 .toString();
     }
 

+ 81 - 31
mjava-tonglibo/src/main/java/com/malk/tonglibo/utils/DeviceDataPersistTask.java

@@ -1,7 +1,15 @@
 package com.malk.tonglibo.utils;
 
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.aliwork.YDSearch;
+import com.malk.service.aliwork.YDClient;
 import com.malk.tonglibo.Mapper.MachineDataMapper;
+import com.malk.tonglibo.Mapper.MachineDetailMapper;
 import com.malk.tonglibo.Service.IMachineDataService;
+import com.malk.tonglibo.entity.MachineDetail;
 import com.malk.tonglibo.entity.RawDeviceData;
 import com.malk.tonglibo.entity.MachineData;
 import lombok.extern.slf4j.Slf4j;
@@ -26,12 +34,16 @@ public class DeviceDataPersistTask {
     private MachineDataMapper machineDataMapper;
     @Autowired
     private IMachineDataService machineDataService;
+    @Autowired
+    private MachineDetailMapper machineDetailMapper;
 
     @Autowired
     private DataBuffer dataBuffer;
 
     @Autowired
     private ChangeDetector changeDetector;
+    @Autowired
+    private YDClient ydClient;
 
 
     @Scheduled(fixedDelay = 1000) // 每秒执行一次
@@ -39,29 +51,48 @@ public class DeviceDataPersistTask {
         List<RawDeviceData> dataList = dataBuffer.drain(500);
         if (dataList.isEmpty()) return;
 
-        List<MachineData> toInsert = new ArrayList<>();
-        int unchangedCount = 0;
+        // "machineNo + 分钟"
+        Map<String, MachineData> latestPerMinute = new HashMap<>();
 
         for (RawDeviceData item : dataList) {
             MachineData data = convertToMachineData(item);
-            if (data == null) continue;
+            if (data == null) {
+                log.warn("设备数据转换失败,跳过: {}", item);
+                continue;
+            }
+
+            //生成 key:machineNo + 时间分钟
+            String minuteKey = data.getMachineNo() + "_" +
+                    data.getTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
+            // 保留最新的数据
+            MachineData existing = latestPerMinute.get(minuteKey);
+            if (existing == null || data.getTime().isAfter(existing.getTime())) {
+                latestPerMinute.put(minuteKey, data);
+            }
+        }
+
+        //对每分钟最新数据进行 MD5 变化检测
+        List<MachineData> toInsert = new ArrayList<>();
+        int unchangedCount = 0;
 
-            //使用 MD5 判断是否变化
+        for (MachineData data : latestPerMinute.values()) {
             if (changeDetector.isChanged(data)) {
-                String fingerprint = MD5Util.md5(changeDetector.concatFields(data)); // 或在 convert 时生成
+                String fingerprint = MD5Util.md5(changeDetector.concatFields(data));
                 data.setDataFingerprint(fingerprint);
                 toInsert.add(data);
-                changeDetector.recordAsCurrent(data.getParamId(), fingerprint);
+                changeDetector.recordAsCurrent(data.getMachineNo(), fingerprint); // 更新为当前指纹
             } else {
                 unchangedCount++;
             }
         }
 
+        // 批量入库
         if (!toInsert.isEmpty()) {
             machineDataService.saveBatch(toInsert, 100);
-            log.info("入库 {} 条(变化数据),跳过 {} 条未变数据", toInsert.size(), unchangedCount);
+            log.info("入库 {} 条(每设备每分钟最新且变化数据),跳过 {} 条未变数据,原始上报 {} 条",
+                    toInsert.size(), unchangedCount, dataList.size());
         } else if (unchangedCount > 0) {
-            log.debug("跳过 {} 条未变化数据", unchangedCount);
+            log.debug("跳过 {} 条未变化数据(已按分钟合并)", unchangedCount);
         }
     }
 
@@ -81,30 +112,44 @@ public class DeviceDataPersistTask {
 
             // 填充字段(根据索引取值)
             machineData.setJqyxsh(safeGet(data, 0));
-            machineData.setZcn(safeGet(data, 2));
-            machineData.setZqsj(safeGet(data, 4));
-            machineData.setSgdyl(safeGet(data, 6));
-            machineData.setXgdyl(safeGet(data, 8));
-            machineData.setYskqyl1(safeGet(data, 10));
-            machineData.setYskqyl2(safeGet(data, 12));
-            machineData.setZymwd1(safeGet(data, 14));
-            machineData.setZymwd2(safeGet(data, 16));
-            machineData.setZymwd3(safeGet(data, 18));
-            machineData.setZymwd4(safeGet(data, 20));
-            machineData.setSmwd1(safeGet(data, 22));
-            machineData.setSmwd2(safeGet(data, 24));
-            machineData.setSmwd3(safeGet(data, 26));
-            machineData.setSmwd4(safeGet(data, 28));
-            machineData.setXmwd1(safeGet(data, 30));
-            machineData.setXmwd2(safeGet(data, 32));
-            machineData.setXmwd3(safeGet(data, 34));
-            machineData.setXmwd4(safeGet(data, 36));
-            machineData.setXjsj(safeGet(data, 38));
-            machineData.setTssj(safeGet(data, 40));
-            machineData.setZysj(safeGet(data, 42));
+            machineData.setZcn(safeGet(data, 1));
+            machineData.setDn(safeGet(data, 2));
+            machineData.setZqsj(safeGet(data, 3));
+            machineData.setSgdyl(safeGet(data, 4));
+            machineData.setXgdyl(safeGet(data, 5));
+            machineData.setYskqyl1(safeGet(data, 6));
+            machineData.setYskqyl2(safeGet(data, 7));
+            machineData.setZymwd1(safeGet(data, 8));
+            machineData.setZymwd2(safeGet(data, 9));
+            machineData.setZymwd3(safeGet(data, 10));
+            machineData.setZymwd4(safeGet(data, 11));
+            machineData.setSmwd1(safeGet(data, 12));
+            machineData.setSmwd2(safeGet(data, 13));
+            machineData.setSmwd3(safeGet(data, 14));
+            machineData.setSmwd4(safeGet(data, 15));
+            machineData.setXmwd1(safeGet(data, 16));
+            machineData.setXmwd2(safeGet(data, 17));
+            machineData.setXmwd3(safeGet(data, 18));
+            machineData.setXmwd4(safeGet(data, 19));
+            machineData.setXjsj(safeGet(data, 20));
+            machineData.setTssj(safeGet(data, 21));
+            machineData.setZysj(safeGet(data, 22));
+            List<MachineDetail> machineList = machineDetailMapper.selectList(new QueryWrapper<MachineDetail>().eq("machine_no", key));
+            if (machineList != null && !machineList.isEmpty()){
+                MachineDetail yidaParam = machineList.get(0);
+                String machineName = yidaParam.getMachineName();
+                String machineCode = yidaParam.getMachineCode();
+                String machineFlag = yidaParam.getMachineFlag();
+                if (machineName != null) {
+                    machineData.setMachineName(machineName);
+                    machineData.setMachineCode(machineCode);
+                    machineData.setMachineFlag(machineFlag);
+                } else {
+                    log.warn("未在宜搭中找到设备编号 {} 对应的名称,使用默认值", key);
+                }
+            }
 
             return machineData;
-
         } catch (Exception e) {
             log.error("转换数据失败: {}", item, e);
             return null;
@@ -114,7 +159,12 @@ public class DeviceDataPersistTask {
     // 安全获取索引值
     private String safeGet(List<String> list, int index) {
         if (index >= 0 && index < list.size()) {
-            return list.get(index);
+            String value = list.get(index);
+            // 切割掉 . 后面的数据
+            if (value != null) {
+                String[] parts = value.split("\\.");
+                return parts[0]; // 返回点号前面的部分
+            }
         }
         return "";
     }

+ 5 - 4
mjava-tonglibo/src/main/resources/application-dev.yml

@@ -32,13 +32,14 @@ logging:
 # dingtalk
 dingtalk:
   agentId: 3914874648
-  appKey: dingyedbqoqricilvyog
-  appSecret: CAPT0hNRO5y-rHp81fmzMHz4LXYJhzkHqG1kh1L6OdM_LQPANR9IOoLtJrNLPVCc
+  appKey: dinggps3rba7eb9cexqe
+  appSecret: pjiEz7AR8Meov0tui7-lJ00oQRxGDWAnIKxS_uH7HDe9rop7H2ZdmW1tDuqaEH_F
   corpId: dingf11f7d6ff834577b
   aesKey: UqJRA1RTxarywiIWOK76BN8BSLfAN4gTDo6nEco4sqG
   token: CpR7AsWa026FQV5VBNU5YrO5
 
 aliwork:
-  appType: APP_HJJ3X3QN4WEWDHU2BJR2
-  systemToken: 7X866C81QPIHJKBFFM1QW4S8BV1U3U4MFO5RLY1
+  appType: APP_C83FAK1HS55UIQLP1MBX
+  systemToken: K4666XA1ZQ5O2PYSAKA7M4ZQAFPX3KYNUEK0MZT9
+
 

+ 4 - 4
mjava-tonglibo/src/main/resources/application-prod.yml

@@ -28,13 +28,13 @@ mybatis-plus:
 # dingtalk
 dingtalk:
   agentId: 3914874648
-  appKey: dingyedbqoqricilvyog
-  appSecret: CAPT0hNRO5y-rHp81fmzMHz4LXYJhzkHqG1kh1L6OdM_LQPANR9IOoLtJrNLPVCc
+  appKey: dinggps3rba7eb9cexqe
+  appSecret: pjiEz7AR8Meov0tui7-lJ00oQRxGDWAnIKxS_uH7HDe9rop7H2ZdmW1tDuqaEH_F
   corpId: dingf11f7d6ff834577b
   aesKey: UqJRA1RTxarywiIWOK76BN8BSLfAN4gTDo6nEco4sqG
   token: CpR7AsWa026FQV5VBNU5YrO5
 
 aliwork:
-  appType: APP_HJJ3X3QN4WEWDHU2BJR2
-  systemToken: 7X866C81QPIHJKBFFM1QW4S8BV1U3U4MFO5RLY1
+  appType: APP_C83FAK1HS55UIQLP1MBX
+  systemToken: K4666XA1ZQ5O2PYSAKA7M4ZQAFPX3KYNUEK0MZT9
 

+ 27 - 23
mjava-tonglibo/src/main/resources/mapper/MachineDataMapper.xml

@@ -9,6 +9,7 @@
         SELECT
             paramId,
             machineNo,
+            machineFlag,
             jqyxsh,
             zcn,
             timeStr,
@@ -17,6 +18,7 @@
                  SELECT
                      paramId,
                      machineNo,
+                     machineFlag,
                      zcn,
                      timeStr,
                      jqyxsh,
@@ -57,12 +59,14 @@
         SELECT
             date,
             machineNo,
+            machineFlag,
             zcn,
             timeStr
         FROM (
             SELECT
             DATE(time) AS date,
             machineNo AS machineNo,
+            machineFlag,
             zcn,
             timeStr,
             ROW_NUMBER() OVER (PARTITION BY DATE(time), machineNo ORDER BY time ASC) AS rn
@@ -76,34 +80,34 @@
     </select>
 
     <select id="selectDailyShiftOutput" resultType="map">
-        SELECT
-        CASE
-        WHEN HOUR(time) < 8 THEN DATE_SUB(DATE(time), INTERVAL 1 DAY)
-        ELSE DATE(time)
-        END AS date,
+<!--        SELECT-->
+<!--        CASE-->
+<!--        WHEN HOUR(time) < 8 THEN DATE_SUB(DATE(time), INTERVAL 1 DAY)-->
+<!--        ELSE DATE(time)-->
+<!--        END AS date,-->
 
-        CASE
-        WHEN HOUR(time) >= 8 AND HOUR(time) < 16 THEN '早班'
-        WHEN HOUR(time) >= 16 THEN '中班'
-        ELSE '晚班'
-        END AS shift,
+<!--        CASE-->
+<!--        WHEN HOUR(time) >= 8 AND HOUR(time) < 16 THEN '早班'-->
+<!--        WHEN HOUR(time) >= 16 THEN '中班'-->
+<!--        ELSE '晚班'-->
+<!--        END AS shift,-->
 
-        SUM(CAST(zcn AS DECIMAL(10,2))) AS output
+<!--        SUM(CAST(zcn AS DECIMAL(10,2))) AS output-->
 
-        FROM T_TLB_MACHINEDATA
-        WHERE zcn REGEXP '^[0-9]+(\\.[0-9]+)?$'
-        AND time >= #{startDate}
-        AND time &lt; #{endDate}
+<!--        FROM T_TLB_MACHINEDATA-->
+<!--        WHERE zcn REGEXP '^[0-9]+(\\.[0-9]+)?$'-->
+<!--        AND time >= #{startDate}-->
+<!--        AND time &lt; #{endDate}-->
 
-        GROUP BY
-        CASE WHEN HOUR(time) < 8 THEN DATE_SUB(DATE(time), INTERVAL 1 DAY) ELSE DATE(time) END,
-        CASE
-        WHEN HOUR(time) >= 8 AND HOUR(time) < 16 THEN '早班'
-        WHEN HOUR(time) >= 16 THEN '中班'
-        ELSE '晚班'
-        END
+<!--        GROUP BY-->
+<!--        CASE WHEN HOUR(time) < 8 THEN DATE_SUB(DATE(time), INTERVAL 1 DAY) ELSE DATE(time) END,-->
+<!--        CASE-->
+<!--        WHEN HOUR(time) >= 8 AND HOUR(time) < 16 THEN '早班'-->
+<!--        WHEN HOUR(time) >= 16 THEN '中班'-->
+<!--        ELSE '晚班'-->
+<!--        END-->
 
-        ORDER BY date, FIELD(shift, '早班', '中班', '晚班')
+<!--        ORDER BY date, FIELD(shift, '早班', '中班', '晚班')-->
     </select>
 
 </mapper>

+ 19 - 0
mjava-zhiwei/src/main/java/com/malk/zhiwei/controller/ZwErpController.java

@@ -6,6 +6,10 @@ import com.malk.server.aliwork.YDParam;
 import com.malk.server.common.McException;
 import com.malk.server.common.McR;
 import com.malk.service.aliwork.YDClient;
+import com.malk.utils.UtilMap;
+import com.malk.utils.UtilServlet;
+import com.malk.zhiwei.service.ZwService;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -13,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.servlet.http.HttpServletRequest;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -28,6 +33,8 @@ public class ZwErpController {
 
     @Autowired
     private YDClient ydClient;
+    @Autowired
+    private ZwService zwService;
 
 
     @PostMapping("/deliver/save")
@@ -57,4 +64,16 @@ public class ZwErpController {
         }
 
     }
+
+    @SneakyThrows
+    @PostMapping("/customer/save")
+    McR savecustomer(HttpServletRequest request){
+        Map<String, ?> data = UtilServlet.getParamMap(request);
+        log.info("客户信息保存, {}", data);
+        McException.assertParamException_Null(data, "instanceId");
+        return McR.success(zwService.savecustomer(UtilMap.getString(data,"instanceId")));
+    }
+
+
+
 }

+ 34 - 1
mjava-zhiwei/src/main/java/com/malk/zhiwei/entity/CustomerModel.java

@@ -62,11 +62,44 @@ public class CustomerModel extends Model{
 
     private FNumber FCreateOrgId;//创建组织 (必填项)
 
+    private String F_UNW_Text_6mb;//业务员(必填项)
+
+    private FNumber F_UNW_Assistant_qov;//终端(必填项)
+
+    private FNumber F_UNW_Assistant_9zp;//事业部(必填项)
+
+    private FNumber F_UNW_Assistant_mo2;//行业(必填项)
+
+    private String FBIZLOCATION;// 地点名称
+
+    private String FBizAddress;//详细地址
+
+    private String FTContact;//联系人
+
+    private String FMOBILE;//移动电话
+
+
+
     public CustomerModel (){}
 
-    public CustomerModel(String name){
+    public CustomerModel(String name,FNumber sktj,FNumber hy,FNumber syb,FNumber zd,String ywy,String nsdjh,FNumber xsbm,
+        FNumber xsy){
         this.FName=name;
         this.FCreateOrgId = new FNumber("100");
         this.FTRADINGCURRID = new FNumber("PRE001");
+
+        this.F_UNW_Text_6mb = ywy;//业务员
+        this.F_UNW_Assistant_qov = zd;//终端
+        this.F_UNW_Assistant_9zp = syb;//事业部
+        this.F_UNW_Assistant_mo2 = hy;//行业
+        this.FRECCONDITIONID = sktj;//收款条件
+        this.FTAXREGISTERCODE = nsdjh;//纳税登记号
+        this.FSALDEPTID = xsbm;//销售部门
+        this.FSELLER = xsy;//销售员
+
+//        this.FBIZLOCATION = FBIZLOCATION;
+//        this.FBizAddress = FBizAddress;
+//        this.FTContact = FTContact;
+//        this.FMOBILE = FMOBILE;
     }
 }

+ 1 - 1
mjava-zhiwei/src/main/java/com/malk/zhiwei/entity/FBillHead.java

@@ -1,7 +1,7 @@
 package com.malk.zhiwei.entity;
 
 import com.malk.utils.UtilMap;
-import com.malk.xiding.entity.Model;
+import com.malk.zhiwei.entity.Model;
 import lombok.Data;
 
 import java.util.Map;

+ 1 - 1
mjava-zhiwei/src/main/java/com/malk/zhiwei/entity/SaleOrderModel.java

@@ -1,6 +1,6 @@
 package com.malk.zhiwei.entity;
 
-import com.malk.xiding.entity.SaleOrderEntry;
+import com.malk.zhiwei.entity.SaleOrderEntry;
 import lombok.Data;
 
 import java.util.List;

+ 68 - 0
mjava-zhiwei/src/main/java/com/malk/zhiwei/schedule/ScheduleTask.java

@@ -2,12 +2,15 @@ package com.malk.zhiwei.schedule;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.kingdee.bos.webapi.sdk.K3CloudApi;
 import com.malk.server.aliwork.YDConf;
 import com.malk.server.aliwork.YDParam;
 import com.malk.service.aliwork.YDClient;
 import com.malk.utils.PublicUtil;
 import com.malk.utils.UtilMap;
 import com.malk.zhiwei.service.ZwService;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -15,6 +18,8 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import java.util.HashMap;
 import java.util.List;
@@ -27,6 +32,7 @@ import java.util.Map;
 @Configuration
 @EnableScheduling
 @ConditionalOnProperty(name = {"enable.scheduling"})
+@RestController
 
 public class ScheduleTask {
 
@@ -94,5 +100,67 @@ public class ScheduleTask {
                 .build(), YDConf.FORM_OPERATION.update);
     }
 
+    //产品信息同步
+    @Scheduled(cron = "0 0 1 * * ?")
+    @PostMapping("/product")
+    public void product() throws JsonProcessingException {
+        zwService.product();
+    }
+
+    //销售订单同步
+    @SneakyThrows
+    @Scheduled(cron = "0 15 1 * * ?")
+    @PostMapping("/purchaseOrder")
+    public void purchaseOrder() throws JsonProcessingException {
+        zwService.purchaseOrder();
+    }
+
+    //出库单(发货通知单)同步
+    @SneakyThrows
+    @Scheduled(cron = "0 30 1 * * ?")
+    @PostMapping("/deliveryOrder")
+    public void deliveryOrder(){
+        zwService.deliveryOrder();
+    }
+
+    //退货单同步
+    @SneakyThrows
+    @Scheduled(cron = "0 45 1 * * ?")
+    @PostMapping("/returnForm")
+    public void returnForm(){
+        zwService.returnForm();
+    }
+
+    //补货单同步
+    @SneakyThrows
+    @Scheduled(cron = "0 0 2 * * ?")
+    @PostMapping("/replenishmentOrder")
+    public void replenishmentOrder(){
+        zwService.replenishmentOrder();
+    }
+
+    //开票单同步
+    @SneakyThrows
+    @Scheduled(cron = "0 15 2 * * ?")
+    @PostMapping("/invoice")
+    public void invoice(){
+        zwService.invoice();
+    }
+
+    //应收单同步
+    @SneakyThrows
+    @Scheduled(cron = "0 30 2 * * ?")
+    @PostMapping("/receivableNote")
+    public void receivableNote(){
+        zwService.receivableNote();
+    }
+
+    //客户同步
+    @SneakyThrows
+//    @Scheduled(cron ="0 0 3 * * ?")
+    @PostMapping("/customer")
+    public void customer(){
+        zwService.customer();
+    }
 
 }

+ 30 - 0
mjava-zhiwei/src/main/java/com/malk/zhiwei/service/ZwService.java

@@ -1,6 +1,9 @@
 package com.malk.zhiwei.service;
 
 import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.malk.server.common.McR;
 
 import java.util.Map;
 
@@ -14,4 +17,31 @@ public interface ZwService {
 
     void syncProduct(String id,String erpPilot);
 
+    //客户保存接口
+    McR savecustomer(String instanceId) throws JsonProcessingException;
+
+    //同步产品信息
+    void product() throws JsonProcessingException;
+
+    //同步销售订单
+    void purchaseOrder() throws JsonProcessingException;
+
+    //出库单(发货通知单)
+    void deliveryOrder() throws JsonProcessingException;
+
+    //退货单
+    void returnForm() throws JsonProcessingException;
+
+    //补货单
+    void replenishmentOrder() throws JsonProcessingException;
+
+    //开票单
+    void invoice() throws JsonProcessingException;
+
+    //应收单
+    void receivableNote() throws JsonProcessingException;
+
+    //同步客户
+    void customer() throws JsonProcessingException;
+
 }

+ 826 - 2
mjava-zhiwei/src/main/java/com/malk/zhiwei/service/impl/ZwServiceImpl.java

@@ -1,26 +1,52 @@
 package com.malk.zhiwei.service.impl;
 
 import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.kingdee.bos.webapi.entity.IdentifyInfo;
+import com.kingdee.bos.webapi.entity.RepoRet;
+import com.kingdee.bos.webapi.sdk.K3CloudApi;
 import com.malk.server.aliwork.YDConf;
 import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McR;
+import com.malk.server.common.VenR;
+import com.malk.server.dingtalk.DDConf;
+import com.malk.server.dingtalk.DDR;
 import com.malk.service.aliwork.YDClient;
-import com.malk.service.aliwork.YDService;
+import com.malk.service.dingtalk.DDClient;
 import com.malk.utils.PublicUtil;
+import com.malk.utils.UtilHttp;
 import com.malk.utils.UtilMap;
+import com.malk.zhiwei.config.KDWebApiConf;
+import com.malk.zhiwei.entity.BillQuery;
+import com.malk.zhiwei.entity.CustomerModel;
+import com.malk.zhiwei.entity.FNumber;
 import com.malk.zhiwei.service.ZwService;
+import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import javax.rmi.CORBA.Util;
 import java.util.*;
+import java.util.stream.Collectors;
 
 @Service
 @Slf4j
 public class ZwServiceImpl implements ZwService {
 
+    @Autowired
+    private KDWebApiConf kdWebApiConf;
+    @Autowired
+    private YDConf ydConf;
+    @Autowired
+    private DDConf ddConf;
+    @Autowired
+    private DDClient ddClient;
+
     private static String ERP_URL="http://10.0.0.208:80";
     private static String ERP_NAME="064";
     private static String ERP_PASSWORD="";
@@ -190,4 +216,802 @@ public class ZwServiceImpl implements ZwService {
             }
         }
     }
+
+    @SneakyThrows
+    @Override
+    public McR savecustomer(String instanceId) throws JsonProcessingException {
+        log.info("客户宜搭实例id:{}",instanceId);
+        Map data = (Map) ydClient.queryData(YDParam.builder().formInstId(instanceId)
+                .appType(ydConf.getAppType()).systemToken(ydConf.getSystemToken())
+                .userId(ddConf.getOperator()).build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+
+        FNumber zd = new FNumber(data.get("selectField_mnft99ue").toString());//终端
+        FNumber syb = new FNumber(data.get("selectField_mnft99ud").toString());//事业部
+        FNumber hy = new FNumber(data.get("textField_mnfujcak").toString());//行业
+        FNumber sktj = new FNumber(data.get("textField_mnfujcaf").toString());//收款条件
+        FNumber xsbm = new FNumber(data.get("textField_mnfujcac").toString());//销售部门
+        FNumber xsy = new FNumber(data.get("textField_mnfujcad").toString());//销售员
+        String kh = data.get("textField_lqanqe6j").toString();// 客户
+        Object empObj = data.get("employeeField_lqanqe6n");
+        String ywy = "";//业务员
+        if (empObj instanceof JSONArray) {
+            JSONArray empArray = (JSONArray) empObj;
+            if (!empArray.isEmpty()) {
+                ywy = empArray.getString(0);
+            }
+        } else if (empObj != null) {
+            ywy = empObj.toString();
+        }
+        String nsdjhc = data.get("textField_llujklkq").toString();//纳税登记号
+        CustomerModel customerModel = new CustomerModel(kh,sktj,hy,syb,zd,ywy,nsdjhc,xsbm,xsy);
+        return saveToAudit("BD_Customer", customerModel);
+    }
+
+    @SneakyThrows
+    @Override
+    public void product() {
+        K3CloudApi client = new K3CloudApi(initIden());
+        int startRow = 0;
+        int limit = 2000;
+        BillQuery billQuery = new BillQuery();
+        billQuery.setFormId("BD_MATERIAL");//产品信息
+        //编码 名称 规格型号 旧物料编码 物料分组 物料属性 基本单位 长 宽 高 体积 面积 密度 标准工时
+        billQuery.setFieldKeys("FCreateOrgId.FNumber,FApproveDate,FNumber,FName,FSpecification,FOldNumber,FMaterialGroup,FErpClsID,FBaseUnitId,FLENGTH,FWIDTH,FHEIGHT,FVOLUME,F_UNW_Qty_r03,F_UNW_Qty_6yt,FPerUnitStandHour");
+        List<Map> filterString = new ArrayList<>();
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",3,"","","0"));//审核日期在今天之前N天以后
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FCreateOrgId.FNumber","67","101","","","0"));//创建组织为101 研发中心
+        billQuery.setFilterString(filterString);
+        billQuery.setLimit(limit);
+        billQuery.setStartRow(startRow);
+        String result=client.billQuery(JSONObject.toJSONString(billQuery));
+        JSONArray jsonArray = JSONArray.parseArray(result);
+        // 遍历每条物料记录
+        for (int i = 0; i < jsonArray.size(); i++) {
+            JSONObject item = jsonArray.getJSONObject(i);
+
+            // 取出各个字段(注意类型转换)
+            String number = item.getString("FNumber");
+            String name = item.getString("FName");
+            String spec = item.getString("FSpecification");
+            String oldNumber = item.getString("FOldNumber");
+            Integer materialGroup = item.getInteger("FMaterialGroup");
+            String erpClsId = item.getString("FErpClsID");
+            Integer baseUnitId = item.getInteger("FBaseUnitId");
+            Double length = item.getDouble("FLENGTH");
+            Double width = item.getDouble("FWIDTH");
+            Double height = item.getDouble("FHEIGHT");
+            Double volume = item.getDouble("FVOLUME");
+            Double area = item.getDouble("F_UNW_Qty_r03");
+            Double density = item.getDouble("F_UNW_Qty_6yt");
+            Double standHour = item.getDouble("FPerUnitStandHour");
+            //TODO:向宜搭插入数据
+            String sc = "textField_l43jpnsf, textField_mcijetil, textField_l43jpnsh, textField_mnhe1ryw, textField_mnhe1rz1, textField_mnhe1rz2, textField_mnhe1rz7, textField_mnhe1rzm," +
+                    " textField_mnhe1rzg, textField_mnhe1rzh, textField_mnhe1rzi, textField_mnhe1rzj, textField_mnhe1rzk, textField_mnhe1rzl";//名称 编码 规格 旧编码 物料分组 物料属性 基本单位 标准工时 长 宽 高 体积 面积 密度
+            List<Map> conditions = Arrays.asList(  YDConf.searchCondition_TextFiled("textField_mcijetil", number, "eq"));
+            Map formData = UtilMap.map(sc,name,number,spec,oldNumber,materialGroup,erpClsId,baseUnitId,length,width,height,volume,area,density,standHour);
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-4A7B1A62CCFC4D758AB98ADE3F97D40COYO2")
+                    .searchCondition(JSONObject.toJSONString(conditions))
+                    .formDataJson(JSONObject.toJSONString(formData))
+                    .build(),YDConf.FORM_OPERATION.upsert);
+
+        }
+        log.info("产品信息已同步");
+    }
+
+    @SneakyThrows
+    @Override
+    public void purchaseOrder(){
+        K3CloudApi client = new K3CloudApi(initIden());
+        int startRow = 0;
+        int limit = 2000;
+        BillQuery billQuery = new BillQuery();
+        billQuery.setFormId("SAL_SaleOrder");//销售订单
+        //[主表] FSaleOrgId销售组织 FSaleDeptId销售部门 FBillNo单据编号  FCustId客户 F_UNW_Text_ct1客户订单号 FSettleCurrId结算币别 FSalerId销售员 FDate日期 FRecConditionId收款条件
+        //[明细表] FMaterialId物料编码 FMaterialName物料名称 FMaterialModel规格型号 FMapId客户物料编码 F_UNW_BaseProperty_uow客户物料规格 FUnitID销售单位 FQty销售数量 FPriceUnitQty计价数量 FPrice单价 FTaxPrice含税单价 FEntryTaxRate税率 FEntryTaxAmount税额 FAmount金额 FAllAmount价税合计 FDeliveryDate要货日期 FSettleOrgIds结算组织 FIsFree是否赠品
+        billQuery.setFieldKeys("FSaleOrgId.FName,FSaleDeptId.FName,FBillNo,FCustId.FName,F_UNW_Text_ct1,FSettleCurrId.FName,FSalerId.FName,FDate,FRecConditionId.FName,FMaterialId.FNumber,FMaterialName,FMaterialModel,FMapId.FNumber,F_UNW_BaseProperty_uow,FUnitID.FName,FQty,FPriceUnitQty,FPrice,FTaxPrice,FEntryTaxRate,FEntryTaxAmount,FAmount,FAllAmount,FDeliveryDate,FSettleOrgIds.FName,FIsFree");
+        List<Map> filterString = new ArrayList<>();
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",1,"","","0"));//审核日期在今天之前N天以后
+        billQuery.setFilterString(filterString);
+        billQuery.setLimit(limit);
+        billQuery.setStartRow(startRow);
+        String result=client.billQuery(JSONObject.toJSONString(billQuery));
+        JSONArray jsonArray = JSONArray.parseArray(result);
+
+        // 按 FBillNo 分组
+        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
+        for (int i = 0; i < jsonArray.size(); i++) {
+            JSONObject item = jsonArray.getJSONObject(i);
+            String billNo = item.getString("FBillNo");
+            groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
+        }
+
+        // 组装最终结果
+        List<Map<String, Object>> orderList = new ArrayList<>();
+        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
+            List<JSONObject> rows = entry.getValue();
+            JSONObject firstRow = rows.get(0);
+
+            // 主表 Map
+            Map<String, Object> orderMap = new LinkedHashMap<>();
+            orderMap.put("textField_mniksrqa", firstRow.getString("FBillNo"));//单据编号
+            orderMap.put("textField_mniksrq4", firstRow.getString("FSaleOrgId.FName")); // 销售组织
+            orderMap.put("textField_mniksrq5", firstRow.getString("FSaleDeptId.FName")); // 销售组织
+            orderMap.put("textField_mniksrqb", firstRow.getString("FCustId.FName")); // 客户
+            orderMap.put("textField_mniksrqe", firstRow.getString("F_UNW_Text_ct1")); // 客户订单号
+            orderMap.put("textField_mniksrqf", firstRow.getString("FSettleCurrId.FName")); // 结算币别
+            orderMap.put("textField_mniksrqk", firstRow.getString("FSalerId.FName")); // 销售员
+            String fDateRaw = firstRow.getString("FDate");
+            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
+            orderMap.put("textField_mniksrql", formattedDate); // 日期
+            orderMap.put("textField_mniksrqm", firstRow.getString("FRecConditionId.FName")); // 收款条件
+
+
+            // 明细数组
+            List<Map<String, Object>> details = new ArrayList<>();
+            for (JSONObject row : rows) {
+                Map<String, Object> detailMap = new LinkedHashMap<>();
+                detailMap.put("textField_mniksrqo", row.getString("FMaterialId.FNumber"));//物料编码
+                detailMap.put("textField_mniksrqp", row.getString("FMaterialName"));//物料名称
+                detailMap.put("textField_mniksrqq", row.getString("FMaterialModel"));//规格型号
+                detailMap.put("textField_mniksrqr", row.getString("FMapId.FNumber"));//客户物料编码
+                detailMap.put("textField_mniksrqs", row.getString("F_UNW_BaseProperty_uow"));//客户物料规格
+                detailMap.put("textField_mniksrqt", row.getString("FUnitID.FName"));//销售单位
+                detailMap.put("numberField_mniksrqv", row.getString("FQty"));//销售数量
+                detailMap.put("numberField_mniksrqw", row.getString("FPriceUnitQty"));//计价数量
+                detailMap.put("numberField_mniksrqx", row.getString("FPrice"));//单价
+                detailMap.put("numberField_mniksrqy", row.getString("FTaxPrice"));//含税单价
+                detailMap.put("numberField_mniksrqz", row.getString("FEntryTaxRate"));//税率
+                detailMap.put("numberField_mniksrr0", row.getString("FEntryTaxAmount"));//税额
+                detailMap.put("numberField_mniksrr1", row.getString("FAmount"));//金额
+                detailMap.put("numberField_mniksrr2", row.getString("FAllAmount"));//价税合计
+                String deliveryRaw = row.getString("FDeliveryDate");
+                String formattedDelivery = (deliveryRaw != null && deliveryRaw.contains("T")) ? deliveryRaw.split("T")[0] : deliveryRaw;
+                detailMap.put("textField_mniksrr3", formattedDelivery);//要货日期
+                detailMap.put("textField_mniksrr4", row.getString("FSettleOrgIds.FName"));//结算组织
+                detailMap.put("radioField_mniksrr6", row.getString("FAmount").equals("true") ? "是" : "否");//是否赠品
+                details.add(detailMap);
+            }
+            orderMap.put("tableField_mniksrqn", details);
+
+            /*写入宜搭*/
+            List<Map> conditions = Arrays.asList(  YDConf.searchCondition_TextFiled("textField_mniksrqa", firstRow.getString("FBillNo"), "eq"));
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-7B112A3733EC412FB27D56D8AC242E5BHIL4")
+                    .searchCondition(JSONObject.toJSONString(conditions))
+                    .formDataJson(JSONObject.toJSONString(orderMap))
+                    .build(), YDConf.FORM_OPERATION.upsert).toString();
+            orderList.add(orderMap);
+        }
+
+        log.info("销售订单已同步");
+    }
+
+    @SneakyThrows
+    @Override
+    public void deliveryOrder() throws JsonProcessingException {
+        K3CloudApi client = new K3CloudApi(initIden());
+        int startRow = 0;
+        int limit = 2000;
+        BillQuery billQuery = new BillQuery();
+        billQuery.setFormId("SAL_DELIVERYNOTICE");//发货通知单
+        //[主表]  FBillNo单据编号 FDate日期 FSettleCurrId结算币别  FSaleOrgId销售组织 FSaleDeptId销售部门   FSalesManID销售员   F_UNW_Base_tr7发货客户  F_UNW_CheckBox_xjs是否委外
+        //[明细表] FCustMatName客户物料名称  FCustMatID客户物料编码  FMaterialID物料编码  F_UNW_BaseProperty_3tm客户物料规格型号  FMaterialName物料名称  FMateriaModel型号规格  FUnitID销售单位  FQty销售数量  FIsFree是否赠品  FDeliveryDate要货日期  FDeliveryLoc交货地点 F_UNW_Text_8dq客户订单号
+        billQuery.setFieldKeys("FBillNo,FDate,FSettleCurrId.FName,FSaleOrgId.FName,FSaleDeptId.FName,FSalesManID.FName,F_UNW_Base_tr7.FName,F_UNW_CheckBox_xjs,FCustMatName,FCustMatID.FNumber,FMaterialID.FNumber,F_UNW_BaseProperty_3tm,FMaterialName,FMateriaModel,FUnitID.FName,FQty,FIsFree,FDeliveryDate,FDeliveryLoc.FName,F_UNW_Text_8dq");
+        List<Map> filterString = new ArrayList<>();
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",1,"","","0"));//审核日期在今天之前N天以后
+        billQuery.setFilterString(filterString);
+        billQuery.setLimit(limit);
+        billQuery.setStartRow(startRow);
+        String result=client.billQuery(JSONObject.toJSONString(billQuery));
+        JSONArray jsonArray = JSONArray.parseArray(result);
+
+        // 按 FBillNo 分组
+        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
+        for (int i = 0; i < jsonArray.size(); i++) {
+            JSONObject item = jsonArray.getJSONObject(i);
+            String billNo = item.getString("FBillNo");
+            groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
+        }
+
+        // 组装最终结果
+        List<Map<String, Object>> orderList = new ArrayList<>();
+        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
+            List<JSONObject> rows = entry.getValue();
+            JSONObject firstRow = rows.get(0);
+
+            // 主表 Map
+            Map<String, Object> orderMap = new LinkedHashMap<>();
+            orderMap.put("textField_mnj0cqqp", firstRow.getString("FBillNo"));//单据编号
+            String fDateRaw = firstRow.getString("FDate");
+            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
+            orderMap.put("textField_mnj0cqqq", formattedDate); // 日期
+            orderMap.put("textField_mnj0cqqr", firstRow.getString("FSettleCurrId.FName")); // 结算币别
+            orderMap.put("textField_mnj0cqqw", firstRow.getString("FSaleOrgId.FName")); // 销售组织
+            orderMap.put("textField_mnj0cqqx", firstRow.getString("FSaleDeptId.FName")); // 销售部门
+            orderMap.put("textField_mnj0cqqy", firstRow.getString("FSalesManID.FName")); // 销售员
+            orderMap.put("textField_mnj0cqr3", firstRow.getString("F_UNW_Base_tr7.FName")); // 发货客户
+            orderMap.put("radioField_mnj0cqr4", firstRow.getString("F_UNW_CheckBox_xjs").equals("true") ? "是" : "否" ); // 是否委外
+
+
+            // 明细数组
+            List<Map<String, Object>> details = new ArrayList<>();
+            for (JSONObject row : rows) {
+                Map<String, Object> detailMap = new LinkedHashMap<>();
+                detailMap.put("textField_mnj0cqr6", row.getString("FCustMatName"));//客户物料名称
+                detailMap.put("textField_mnj0cqr7", row.getString("FCustMatID.FNumber"));//客户物料编码
+                detailMap.put("textField_mnj0cqr8", row.getString("FMaterialID.FNumber"));//物料编码
+                detailMap.put("textField_mnj0cqr9", row.getString("F_UNW_BaseProperty_3tm"));//客户物料规格型号
+                detailMap.put("textField_mnj0cqra", row.getString("FMaterialName"));//物料名称
+                detailMap.put("textField_mnj0cqrb", row.getString("FMateriaModel"));//规格型号
+                detailMap.put("textField_mnj0cqrc", row.getString("FUnitID.FName"));//销售单位
+                detailMap.put("numberField_mnj0cqrd", row.getString("FQty"));//销售数量
+                detailMap.put("radioField_mnj0cqre", row.getString("FIsFree").equals("true") ? "是" : "否");//是否赠品
+                String rawDeliveryDate = row.getString("FDeliveryDate");
+                String formattedDeliveryDate = rawDeliveryDate != null ? rawDeliveryDate.replace("T", " ") : null;
+                detailMap.put("textField_mnj0cqrf", formattedDeliveryDate);//要货日期
+                detailMap.put("textField_mnj0cqrg", row.getString("FDeliveryLoc.FName"));//交货地点
+                detailMap.put("textField_mnj0cqrh", row.getString("F_UNW_Text_8dq"));//客户订单号
+                details.add(detailMap);
+            }
+            orderMap.put("tableField_mnj0cqr5", details);
+
+            /*写入宜搭*/
+            List<Map> conditions = Arrays.asList(  YDConf.searchCondition_TextFiled("textField_mnj0cqqp", firstRow.getString("FBillNo"), "eq"));
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-50CEB72455534364BF9A97C8A49A3A46TBLI")
+                    .searchCondition(JSONObject.toJSONString(conditions))
+                    .formDataJson(JSONObject.toJSONString(orderMap))
+                    .build(), YDConf.FORM_OPERATION.upsert).toString();
+            orderList.add(orderMap);
+        }
+
+        log.info("发货通知单已同步");
+    }
+
+    @SneakyThrows
+    @Override
+    public void returnForm() throws JsonProcessingException {
+        K3CloudApi client = new K3CloudApi(initIden());
+        int startRow = 0;
+        int limit = 2000;
+        BillQuery billQuery = new BillQuery();
+        billQuery.setFormId("SAL_RETURNSTOCK");//退货单
+        //[主表]  FBillNo单据编号 FDate日期 FRetcustId退货客户  FSettleCurrId结算币别  FSaleOrgId销售组织 FSaledeptid销售部门   FSalesManId销售员
+        //[明细表] FMapId客户物料编码  FMapName客户物料名称  FMaterialId物料编码  FMaterialName物料名称  FMaterialModel型号规格  FF100001厚度  FSalUnitID销售单位  FSalUnitQty销售数量  FIsFree是否赠品  FDeliveryDate退货日期  FReturnType退货类型  FPrice单价 FTaxPrice含税单价  FNote备注
+        billQuery.setFieldKeys("FBillNo,FDate,FRetcustId.FName,FSettleCurrId.FName,FSaleOrgId.FName,FSaledeptid.FName,FSalesManId.FName,FMapId.FNumber,FMapName,FMaterialId.FNumber,FMaterialName,FMaterialModel,FAuxpropId.FF100001,FSalUnitID.FName,FSalUnitQty,FIsFree,FDeliveryDate,FReturnType.FDataValue,FPrice,FTaxPrice,FNote");
+        List<Map> filterString = new ArrayList<>();
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",30,"","","0"));//审核日期在今天之前N天以后
+        billQuery.setFilterString(filterString);
+        billQuery.setLimit(limit);
+        billQuery.setStartRow(startRow);
+        String result=client.billQuery(JSONObject.toJSONString(billQuery));
+        JSONArray jsonArray = JSONArray.parseArray(result);
+
+        // 按 FBillNo 分组
+        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
+        for (int i = 0; i < jsonArray.size(); i++) {
+            JSONObject item = jsonArray.getJSONObject(i);
+            String billNo = item.getString("FBillNo");
+            groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
+        }
+
+        // 组装最终结果
+        List<Map<String, Object>> orderList = new ArrayList<>();
+        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
+            List<JSONObject> rows = entry.getValue();
+            JSONObject firstRow = rows.get(0);
+
+            // 主表 Map
+            Map<String, Object> orderMap = new LinkedHashMap<>();
+            orderMap.put("textField_mnmru1xp", firstRow.getString("FBillNo"));//单据编号
+            String fDateRaw = firstRow.getString("FDate");
+            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
+            orderMap.put("textField_mnmru1xq", formattedDate); // 日期
+            orderMap.put("textField_mnmru1xr", firstRow.getString("FRetcustId.FName")); // 退货客户
+            orderMap.put("textField_mnmru1y0", firstRow.getString("FSettleCurrId.FName")); // 结算币别
+            orderMap.put("textField_mnmru1y1", firstRow.getString("FSaleOrgId.FName")); // 销售组织
+            orderMap.put("textField_mnmru1y2", firstRow.getString("FSaledeptid.FName")); // 销售部门
+            orderMap.put("textField_mnmru1y3", firstRow.getString("FSalesManId.FName")); // 销售员
+
+
+            // 明细数组
+            List<Map<String, Object>> details = new ArrayList<>();
+            for (JSONObject row : rows) {
+                Map<String, Object> detailMap = new LinkedHashMap<>();
+                detailMap.put("textField_mnmru1y9", row.getString("FMapId.FNumber"));//客户物料编码
+                detailMap.put("textField_mnmru1ya", row.getString("FMapName"));//客户物料名称
+                detailMap.put("textField_mnmru1yb", row.getString("FMaterialId.FNumber"));//物料编码
+                detailMap.put("textField_mnmru1yc", row.getString("FMaterialName"));//物料名称
+                detailMap.put("textField_mnmru1yd", row.getString("FMaterialModel"));//规格型号
+                detailMap.put("textField_mnmru1ye", row.getString("FAuxpropId.FF100001"));//厚度
+                detailMap.put("textField_mnmru1yf", row.getString("FSalUnitID.FName"));//销售单位
+                detailMap.put("numberField_mnmru1yg", row.getString("FSalUnitQty"));//销售数量
+                detailMap.put("radioField_mnmru1yh", row.getString("FIsFree").equals("true") ? "是" : "否");//是否赠品
+                String rawDeliveryDate = row.getString("FDeliveryDate");
+                String formattedDeliveryDate = rawDeliveryDate != null ? rawDeliveryDate.replace("T", " ") : null;
+                detailMap.put("textField_mnmru1yi", formattedDeliveryDate);//退货日期
+                detailMap.put("textField_mnmru1yj", row.getString("FReturnType.FDataValue"));//退货类型
+                detailMap.put("numberField_mnmru1yk", row.getString("FPrice"));//单价
+                detailMap.put("numberField_mnmru1yl", row.getString("FTaxPrice"));//含税单价
+                detailMap.put("textField_mnmru1ym", row.getString("FNote"));//备注
+                details.add(detailMap);
+            }
+            orderMap.put("tableField_mnmru1y8", details);
+
+            /*写入宜搭*/
+            List<Map> conditions = Arrays.asList(  YDConf.searchCondition_TextFiled("textField_mnmru1xp", firstRow.getString("FBillNo"), "eq"));
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-48ADB8AA7FEF4821929BFE8FE5B623E42OKY")
+                    .searchCondition(JSONObject.toJSONString(conditions))
+                    .formDataJson(JSONObject.toJSONString(orderMap))
+                    .build(), YDConf.FORM_OPERATION.upsert).toString();
+            orderList.add(orderMap);
+        }
+
+        log.info("退货单已同步");
+    }
+
+    @SneakyThrows
+    @Override
+    public void replenishmentOrder() throws JsonProcessingException {
+        K3CloudApi client = new K3CloudApi(initIden());
+        int startRow = 0;
+        int limit = 2000;
+        BillQuery billQuery = new BillQuery();
+        billQuery.setFormId("SAL_SaleOrder"); // 销售订单
+        // 字段查询与销售订单一致,包含 FIsFree
+        billQuery.setFieldKeys("FSaleOrgId.FName,FSaleDeptId.FName,FBillNo,FCustId.FName,F_UNW_Text_ct1,FSettleCurrId.FName,FSalerId.FName,FDate,FRecConditionId.FName,FMaterialId.FNumber,FMaterialName,FMaterialModel,FMapId.FNumber,F_UNW_BaseProperty_uow,FUnitID.FName,FQty,FPriceUnitQty,FPrice,FTaxPrice,FEntryTaxRate,FEntryTaxAmount,FAmount,FAllAmount,FDeliveryDate,FSettleOrgIds.FName,FIsFree");
+        List<Map> filterString = new ArrayList<>();
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic", "FApproveDate", "265", 1, "", "", "0"));
+        billQuery.setFilterString(filterString);
+        billQuery.setLimit(limit);
+        billQuery.setStartRow(startRow);
+        String result = client.billQuery(JSONObject.toJSONString(billQuery));
+        JSONArray jsonArray = JSONArray.parseArray(result);
+
+        // 按 FBillNo 分组,并过滤出赠品明细
+        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
+        for (int i = 0; i < jsonArray.size(); i++) {
+            JSONObject item = jsonArray.getJSONObject(i);
+            // 判断是否赠品:注意金蝶返回的 FIsFree 可能是布尔值或字符串 "true"/"false"
+            boolean isFree = false;
+            Object freeObj = item.get("FIsFree");
+            if (freeObj instanceof Boolean) {
+                isFree = (Boolean) freeObj;
+            } else if (freeObj instanceof String) {
+                isFree = "true".equalsIgnoreCase((String) freeObj);
+            }
+            // 只处理赠品行
+            if (isFree) {
+                String billNo = item.getString("FBillNo");
+                groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
+            }
+        }
+
+        // 组装最终结果(仅包含有赠品行明细的订单)
+        List<Map<String, Object>> orderList = new ArrayList<>();
+        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
+            List<JSONObject> rows = entry.getValue();
+            JSONObject firstRow = rows.get(0); // 取该订单的第一条赠品行(主表字段相同)
+
+            // 主表 Map
+            Map<String, Object> orderMap = new LinkedHashMap<>();
+            orderMap.put("textField_mniksrqa", firstRow.getString("FBillNo")); // 单据编号
+            orderMap.put("textField_mniksrq4", firstRow.getString("FSaleOrgId.FName")); // 销售组织
+            orderMap.put("textField_mniksrq5", firstRow.getString("FSaleDeptId.FName")); // 销售部门
+            orderMap.put("textField_mniksrqb", firstRow.getString("FCustId.FName")); // 客户
+            orderMap.put("textField_mniksrqe", firstRow.getString("F_UNW_Text_ct1")); // 客户订单号
+            orderMap.put("textField_mniksrqf", firstRow.getString("FSettleCurrId.FName")); // 结算币别
+            orderMap.put("textField_mniksrqk", firstRow.getString("FSalerId.FName")); // 销售员
+            String fDateRaw = firstRow.getString("FDate");
+            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
+            orderMap.put("textField_mniksrql", formattedDate); // 日期
+            orderMap.put("textField_mniksrqm", firstRow.getString("FRecConditionId.FName")); // 收款条件
+
+            // 明细数组(仅包含赠品行)
+            List<Map<String, Object>> details = new ArrayList<>();
+            for (JSONObject row : rows) {
+                Map<String, Object> detailMap = new LinkedHashMap<>();
+                detailMap.put("textField_mniksrqo", row.getString("FMaterialId.FNumber")); // 物料编码
+                detailMap.put("textField_mniksrqp", row.getString("FMaterialName")); // 物料名称
+                detailMap.put("textField_mniksrqq", row.getString("FMaterialModel")); // 规格型号
+                detailMap.put("textField_mniksrqr", row.getString("FMapId.FNumber")); // 客户物料编码
+                detailMap.put("textField_mniksrqs", row.getString("F_UNW_BaseProperty_uow")); // 客户物料规格
+                detailMap.put("textField_mniksrqt", row.getString("FUnitID.FName")); // 销售单位
+                detailMap.put("numberField_mniksrqv", row.getString("FQty")); // 销售数量
+                detailMap.put("numberField_mniksrqw", row.getString("FPriceUnitQty")); // 计价数量
+                detailMap.put("numberField_mniksrqx", row.getString("FPrice")); // 单价
+                detailMap.put("numberField_mniksrqy", row.getString("FTaxPrice")); // 含税单价
+                detailMap.put("numberField_mniksrqz", row.getString("FEntryTaxRate")); // 税率
+                detailMap.put("numberField_mniksrr0", row.getString("FEntryTaxAmount")); // 税额
+                detailMap.put("numberField_mniksrr1", row.getString("FAmount")); // 金额
+                detailMap.put("numberField_mniksrr2", row.getString("FAllAmount")); // 价税合计
+                String deliveryRaw = row.getString("FDeliveryDate");
+                String formattedDelivery = (deliveryRaw != null && deliveryRaw.contains("T")) ? deliveryRaw.split("T")[0] : deliveryRaw;
+                detailMap.put("textField_mniksrr3", formattedDelivery); // 要货日期
+                detailMap.put("textField_mniksrr4", row.getString("FSettleOrgIds.FName")); // 结算组织
+                // 赠品标记:这里明细一定是赠品,直接设为"是"
+                detailMap.put("radioField_mniksrr6", "是");
+                details.add(detailMap);
+            }
+            orderMap.put("tableField_mniksrqn", details);
+
+            // 写入宜搭补货单表单
+            List<Map> conditions = Arrays.asList(
+                    YDConf.searchCondition_TextFiled("textField_mniksrqa", firstRow.getString("FBillNo"), "eq")
+            );
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-837E203B7DCA4B09A9618AA8F584CC45UDFX")
+                    .searchCondition(JSONObject.toJSONString(conditions))
+                    .formDataJson(JSONObject.toJSONString(orderMap))
+                    .build(), YDConf.FORM_OPERATION.upsert).toString();
+            orderList.add(orderMap);
+        }
+
+        log.info("补货单已同步,共 {} 个订单包含赠品明细", orderList.size());
+    }
+
+    @SneakyThrows
+    @Override
+    public void invoice() throws JsonProcessingException {
+        K3CloudApi client = new K3CloudApi(initIden());
+        int startRow = 0;
+        int limit = 2000;
+        BillQuery billQuery = new BillQuery();
+        billQuery.setFormId("AR_receivable");//开票单
+        //[主表]  FBillTypeID单据类型  FCUSTOMERID客户  FSALEERID销售员  FSetAccountType立账类型  FBillNo单据编号  FCURRENCYID币别  FSETTLEORGID结算组织  FDATE业务日期  FENDDATE_H到期日  FDocumentStatus单据状态  FPayConditon收款条件  FSALEDEPTID销售部门  F_UNW_Text_u4s发票号
+        //[明细表] FMATERIALID 物料编码  FCustMatID客户物料编码  FCustMatName客户物料名称  F_UNW_BaseProperty_lad规格型号 FMaterialName物料名称  FPRICEUNITID计价单位  FPriceQty计价数量  FEntryTaxRate税率  FF100001厚度  FBASICUNITQTY计价基本数量  FLot批号  FORDERNUMBER销售订单号  FORDERENTRYSEQ销售订单行号  FSalQty销售数量  FSalUnitId销售单位  FIsFree是否赠品
+        billQuery.setFieldKeys("FBillTypeID.FName,FCUSTOMERID.FName,FSALEERID.FName,FSetAccountType,FBillNo,FCURRENCYID.FName,FSETTLEORGID.FName,FDATE,FENDDATE_H,FDocumentStatus,FPayConditon.FName,FSALEDEPTID.FName,F_UNW_Text_u4s,FMATERIALID.FNumber,FCustMatID.FNumber,FCustMatName,F_UNW_BaseProperty_lad,FMaterialName,FPRICEUNITID.FName,FPriceQty,FEntryTaxRate,FAuxpropId.FF100001,FBASICUNITQTY,FLot.FNumber,FORDERNUMBER,FORDERENTRYSEQ,FSalQty,FSalUnitId.FName,FIsFree");
+        List<Map> filterString = new ArrayList<>();
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",1,"","","0"));//审核日期在今天之前N天以后
+        billQuery.setFilterString(filterString);
+        billQuery.setLimit(limit);
+        billQuery.setStartRow(startRow);
+        String result=client.billQuery(JSONObject.toJSONString(billQuery));
+        JSONArray jsonArray = JSONArray.parseArray(result);
+
+        // 按 FBillNo 分组
+        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
+        for (int i = 0; i < jsonArray.size(); i++) {
+            JSONObject item = jsonArray.getJSONObject(i);
+            String billNo = item.getString("FBillNo");
+            groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
+        }
+
+        // 组装最终结果
+        List<Map<String, Object>> orderList = new ArrayList<>();
+        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
+            List<JSONObject> rows = entry.getValue();
+            JSONObject firstRow = rows.get(0);
+
+            // ========== 新增:检查发票号,无发票号则跳过 ==========
+            String invoiceNo = firstRow.getString("F_UNW_Text_u4s");
+            if (invoiceNo == null || invoiceNo.trim().isEmpty()) {
+                log.info("单据编号 {} 无发票号,跳过同步", firstRow.getString("FBillNo"));
+                continue;
+            }
+            // =================================================
+
+            // 主表 Map
+            Map<String, Object> orderMap = new LinkedHashMap<>();
+            orderMap.put("textField_mno1zcb2", firstRow.getString("FBillTypeID.FName"));//单据类型
+            orderMap.put("textField_mno1zcb3", firstRow.getString("FCUSTOMERID.FName")); // 客户
+            orderMap.put("textField_mno1zcb4", firstRow.getString("FSALEERID.FName")); // 销售员
+            String FSetAccountType = "";
+            switch (firstRow.getString("FSetAccountType")){
+                case "1":
+                    FSetAccountType = "业务应收";break;
+                case "2":
+                    FSetAccountType = "暂估应收";break;
+                case "3":
+                    FSetAccountType = "财务应收";break;
+            }
+            orderMap.put("textField_mno1zcb5", FSetAccountType); // 立账类型
+            orderMap.put("textField_mno1zcbb", firstRow.getString("FBillNo")); // 单据编号
+            orderMap.put("textField_mno1zcbc", firstRow.getString("FCURRENCYID.FName")); // 币别
+            orderMap.put("textField_mno1zcbd", firstRow.getString("FSETTLEORGID.FName")); // 结算组织
+            String fDateRaw = firstRow.getString("FDATE");
+            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
+            orderMap.put("textField_mno1zcbe", formattedDate); // 业务日期
+            String fDateRaw_A = firstRow.getString("FENDDATE_H");
+            String formattedDate_A = (fDateRaw_A != null && fDateRaw_A.contains("T")) ? fDateRaw_A.split("T")[0] : fDateRaw_A;
+            orderMap.put("textField_mno1zcbk", formattedDate_A); // 到期日
+            orderMap.put("textField_mno1zcbl", firstRow.getString("FPayConditon.FName")); // 收款条件
+            String FDocumentStatus = "";
+            switch (firstRow.getString("FDocumentStatus")){
+                case "A":
+                    FDocumentStatus = "创建";break;
+                case "B":
+                    FDocumentStatus = "审核中";break;
+                case "C":
+                    FDocumentStatus = "已审核";break;
+                case "D":
+                    FDocumentStatus = "重新审核";break;
+                case "Z":
+                    FDocumentStatus = "暂存";break;
+            }
+            orderMap.put("textField_mno1zcbm", FDocumentStatus); // 单据状态
+            orderMap.put("textField_mno1zcbn", firstRow.getString("FSALEDEPTID.FName")); // 销售部门
+            orderMap.put("textField_mno1zcbt", invoiceNo); // 发票号(已确保非空)
+
+            // 明细数组
+            List<Map<String, Object>> details = new ArrayList<>();
+            for (JSONObject row : rows) {
+                Map<String, Object> detailMap = new LinkedHashMap<>();
+                detailMap.put("textField_mno1zcbv", row.getString("FMATERIALID.FNumber"));//物料编码
+                detailMap.put("textField_mno1zcbw", row.getString("FCustMatID.FNumber"));//客户物料编码
+                detailMap.put("textField_mno1zcbx", row.getString("FCustMatName"));//客户物料名称
+                detailMap.put("textField_mno1zcby", row.getString("F_UNW_BaseProperty_lad"));//规格型号
+                detailMap.put("textField_mno1zcbz", row.getString("FMaterialName"));//物料名称
+                detailMap.put("textField_mno1zcc0", row.getString("FPRICEUNITID.FName"));//计价单位
+                detailMap.put("numberField_mno1zcc2", row.getString("FPriceQty"));//计价数量
+                detailMap.put("numberField_mno1zcc3", row.getString("FEntryTaxRate"));//税率(%)
+                detailMap.put("textField_mno1zcc5", row.getString("FAuxpropId.FF100001"));//厚度
+                detailMap.put("numberField_mno1zcc6", row.getString("FBASICUNITQTY"));//计价基本数量
+                detailMap.put("textField_mno1zcc7", row.getString("FLot.FNumber"));//批号
+                detailMap.put("textField_mno1zcc8", row.getString("FORDERNUMBER"));//销售订单号
+                detailMap.put("textField_mno1zcc9", row.getString("FORDERENTRYSEQ"));//销售订单行号
+                detailMap.put("numberField_mno1zcca", row.getString("FSalQty"));//销售数量
+                detailMap.put("textField_mno1zccb", row.getString("FSalUnitId.FName"));//销售单位
+                detailMap.put("radioField_mno1zccc", row.getString("FIsFree").equals("true") ? "是" : "否");//是否赠品
+                details.add(detailMap);
+            }
+            orderMap.put("tableField_mno1zcbu", details);
+
+            /*写入宜搭*/
+            List<Map> conditions = Arrays.asList(YDConf.searchCondition_TextFiled("textField_mno1zcbb", firstRow.getString("FBillNo"), "eq"));
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-CEF87B7F64004AE1A1D9A2A3A8EC4986O1VK")
+                    .searchCondition(JSONObject.toJSONString(conditions))
+                    .formDataJson(JSONObject.toJSONString(orderMap))
+                    .build(), YDConf.FORM_OPERATION.upsert).toString();
+            orderList.add(orderMap);
+        }
+
+        log.info("开票单已同步");
+    }
+
+    @SneakyThrows
+    @Override
+    public void receivableNote() throws JsonProcessingException {
+        K3CloudApi client = new K3CloudApi(initIden());
+        int startRow = 0;
+        int limit = 2000;
+        BillQuery billQuery = new BillQuery();
+        billQuery.setFormId("AR_receivable"); // 应收单
+        billQuery.setFieldKeys("FBillTypeID.FName,FCUSTOMERID.FName,FSALEERID.FName,FSetAccountType,FBillNo,FCURRENCYID.FName,FSETTLEORGID.FName,FDATE,FENDDATE_H,FDocumentStatus,FPayConditon.FName,FSALEDEPTID.FName,F_UNW_Text_u4s,FMATERIALID.FNumber,FCustMatID.FNumber,FCustMatName,F_UNW_BaseProperty_lad,FMaterialName,FPRICEUNITID.FName,FPriceQty,FEntryTaxRate,FAuxpropId.FF100001,FBASICUNITQTY,FLot.FNumber,FORDERNUMBER,FORDERENTRYSEQ,FSalQty,FSalUnitId.FName,FIsFree");
+        List<Map> filterString = new ArrayList<>();
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",1,"","","0")); // 审核日期条件
+        billQuery.setFilterString(filterString);
+        billQuery.setLimit(limit);
+        billQuery.setStartRow(startRow);
+        String result = client.billQuery(JSONObject.toJSONString(billQuery));
+        JSONArray jsonArray = JSONArray.parseArray(result);
+
+        // 按 FBillNo 分组
+        Map<String, List<JSONObject>> groupMap = new LinkedHashMap<>();
+        for (int i = 0; i < jsonArray.size(); i++) {
+            JSONObject item = jsonArray.getJSONObject(i);
+            String billNo = item.getString("FBillNo");
+            groupMap.computeIfAbsent(billNo, k -> new ArrayList<>()).add(item);
+        }
+
+        // 组装并同步到宜搭(应收单表单)
+        List<Map<String, Object>> orderList = new ArrayList<>();
+        for (Map.Entry<String, List<JSONObject>> entry : groupMap.entrySet()) {
+            List<JSONObject> rows = entry.getValue();
+            JSONObject firstRow = rows.get(0);
+
+            // 二次确认:发票号必须为空(有发票号的跳过)
+            String invoiceNo = firstRow.getString("F_UNW_Text_u4s");
+            if (invoiceNo != null && !invoiceNo.trim().isEmpty()) {
+                log.info("单据编号 {} 含有发票号,不符合应收单同步条件(需要无发票号),跳过", firstRow.getString("FBillNo"));
+                continue;
+            }
+
+            // 组装主表数据
+            Map<String, Object> orderMap = new LinkedHashMap<>();
+            orderMap.put("textField_mno1zcb2", firstRow.getString("FBillTypeID.FName"));      // 单据类型
+            orderMap.put("textField_mno1zcb3", firstRow.getString("FCUSTOMERID.FName"));     // 客户
+            orderMap.put("textField_mno1zcb4", firstRow.getString("FSALEERID.FName"));          // 销售员
+            // 立账类型转换
+            String FSetAccountType = "";
+            switch (firstRow.getString("FSetAccountType")){
+                case "1": FSetAccountType = "业务应收"; break;
+                case "2": FSetAccountType = "暂估应收"; break;
+                case "3": FSetAccountType = "财务应收"; break;
+            }
+            orderMap.put("textField_mno1zcb5", FSetAccountType);//立账类型
+            orderMap.put("textField_mno1zcbb", firstRow.getString("FBillNo"));                 // 单据编号
+            orderMap.put("textField_mno1zcbc", firstRow.getString("FCURRENCYID.FName"));     // 币别
+            orderMap.put("textField_mno1zcbd", firstRow.getString("FSETTLEORGID.FName"));   // 结算组织
+            String fDateRaw = firstRow.getString("FDATE");
+            String formattedDate = (fDateRaw != null && fDateRaw.contains("T")) ? fDateRaw.split("T")[0] : fDateRaw;
+            orderMap.put("textField_mno1zcbe", formattedDate);                                   // 业务日期
+            String fDateRaw_A = firstRow.getString("FENDDATE_H");
+            String formattedDate_A = (fDateRaw_A != null && fDateRaw_A.contains("T")) ? fDateRaw_A.split("T")[0] : fDateRaw_A;
+            orderMap.put("textField_mno1zcbk", formattedDate_A);                             // 到期日
+            orderMap.put("textField_mno1zcbl", firstRow.getString("FPayConditon.FName"));// 收款条件
+            // 单据状态转换
+            String FDocumentStatus = "";
+            switch (firstRow.getString("FDocumentStatus")){
+                case "A": FDocumentStatus = "创建"; break;
+                case "B": FDocumentStatus = "审核中"; break;
+                case "C": FDocumentStatus = "已审核"; break;
+                case "D": FDocumentStatus = "重新审核"; break;
+                case "Z": FDocumentStatus = "暂存"; break;
+            }
+            orderMap.put("textField_mno1zcbm", FDocumentStatus);//单据状态
+            orderMap.put("textField_mno1zcbn", firstRow.getString("FSALEDEPTID.FName"));     // 销售部门
+            orderMap.put("textField_mno1zcbt", "");                                 // 留空
+
+            // 明细数组(字段映射请对应应收单明细表)
+            List<Map<String, Object>> details = new ArrayList<>();
+            for (JSONObject row : rows) {
+                Map<String, Object> detailMap = new LinkedHashMap<>();
+                detailMap.put("textField_mno1zcbv", row.getString("FMATERIALID.FNumber"));//物料编码
+                detailMap.put("textField_mno1zcbw", row.getString("FCustMatID.FNumber"));//客户物料编码
+                detailMap.put("textField_mno1zcbx", row.getString("FCustMatName"));//客户物料名称
+                detailMap.put("textField_mno1zcby", row.getString("F_UNW_BaseProperty_lad"));//规格型号
+                detailMap.put("textField_mno1zcbz", row.getString("FMaterialName"));//物料名称
+                detailMap.put("textField_mno1zcc0", row.getString("FPRICEUNITID.FName"));//计价单位
+                detailMap.put("numberField_mno1zcc2", row.getString("FPriceQty"));//计价数量
+                detailMap.put("numberField_mno1zcc3", row.getString("FEntryTaxRate"));//税率(%)
+                detailMap.put("textField_mno1zcc5", row.getString("FAuxpropId.FF100001"));//厚度
+                detailMap.put("numberField_mno1zcc6", row.getString("FBASICUNITQTY"));//计价基本数量
+                detailMap.put("textField_mno1zcc7", row.getString("FLot.FNumber"));//批号
+                detailMap.put("textField_mno1zcc8", row.getString("FORDERNUMBER"));//销售订单号
+                detailMap.put("textField_mno1zcc9", row.getString("FORDERENTRYSEQ"));//销售订单行号
+                detailMap.put("numberField_mno1zcca", row.getString("FSalQty"));//销售数量
+                detailMap.put("textField_mno1zccb", row.getString("FSalUnitId.FName"));//销售单位
+                detailMap.put("radioField_mno1zccc", row.getString("FIsFree").equals("true") ? "是" : "否");//是否赠品
+                details.add(detailMap);
+            }
+            orderMap.put("tableField_mno1zcbu", details);
+
+            // 写入宜搭
+            List<Map> conditions = Arrays.asList(
+                    YDConf.searchCondition_TextFiled("textField_mno1zcbb", firstRow.getString("FBillNo"), "eq")
+            );
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-5A0062877EC246959CE85BC7418D1204229L")
+                    .searchCondition(JSONObject.toJSONString(conditions))
+                    .formDataJson(JSONObject.toJSONString(orderMap))
+                    .build(), YDConf.FORM_OPERATION.upsert).toString();
+            orderList.add(orderMap);
+        }
+
+        log.info("应收单(无发票号)已同步,共处理 {} 张单据", orderList.size());
+    }
+
+    @SneakyThrows
+    @Override
+    public void customer() throws JsonProcessingException {
+        K3CloudApi client = new K3CloudApi(initIden());
+        int startRow = 0;
+        int limit = 2000;
+        BillQuery billQuery = new BillQuery();
+        billQuery.setFormId("BD_Customer");//客户
+        //客户编码 客户名称 业务员 销售员 销售部门 收款条件 行业 事业部 终端 纳税人登记号
+        billQuery.setFieldKeys("FNumber,FName,F_UNW_Text_6mb,FSELLER.FName,FSALDEPTID.FName,FRECCONDITIONID.FName,F_UNW_Assistant_mo2.FDataValue,F_UNW_Assistant_9zp.FNumber,F_UNW_Assistant_qov.FNumber,FTAXREGISTERCODE");
+        List<Map> filterString = new ArrayList<>();
+//        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",3,"","","0"));//审核日期在今天之前N天以后
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FCreateOrgId.FNumber","67","100","","","0"));//创建组织为100 宁波致微新材料科技有限公司
+        billQuery.setFilterString(filterString);
+        billQuery.setLimit(limit);
+        billQuery.setStartRow(startRow);
+        String result=client.billQuery(JSONObject.toJSONString(billQuery));
+        JSONArray jsonArray = JSONArray.parseArray(result);
+        // 遍历每条物料记录
+        for (int i = 0; i < jsonArray.size(); i++) {
+            JSONObject item = jsonArray.getJSONObject(i);
+
+            // 取出各个字段(注意类型转换)
+            String bm = item.getString("FNumber");//客户编码
+            String khmc = item.getString("FName");//客户名称
+
+            String ywy = item.getString("F_UNW_Text_6mb");//业务员
+            Map body = new HashMap();
+            body.put("queryWord",ywy);
+            body.put("offset",0);
+            body.put("size",10);
+            body.put("fullMatchField",1);
+            String doPost = UtilHttp.doPost("https://api.dingtalk.com/v1.0/contact/users/search", ddClient.initTokenHeader(), null, body);
+            JSONObject resp = JSON.parseObject(doPost);
+            JSONArray ywy_array = resp != null ? resp.getJSONArray("list") : null;
+
+            String xsbm = item.getString("FSALDEPTID.FName");//销售部门
+            Map body_A = new HashMap();
+            body_A.put("queryWord",xsbm);
+            body_A.put("offset",0);
+            body_A.put("size",10);
+            // 获取部门搜索结果
+            String doPost_A = UtilHttp.doPost("https://api.dingtalk.com/v1.0/contact/departments/search", ddClient.initTokenHeader(), null, body_A);
+            JSONObject respA = JSON.parseObject(doPost_A);
+            JSONArray aaary = respA != null ? respA.getJSONArray("list") : null;
+            List<String> xsbm_array = new ArrayList<>();
+            if (aaary != null && !aaary.isEmpty()) {
+                xsbm_array = aaary.stream()
+                        .map(Object::toString)
+                        .collect(Collectors.toList());
+            }
+// 如果未查到部门,xsbm_array 保持为空列表
+
+            String sktj = item.getString("FRECCONDITIONID.FName");//收款条件
+            String hy = item.getString("F_UNW_Assistant_mo2.FDataValue");//行业
+            String syb = item.getString("F_UNW_Assistant_9zp.FNumber");//事业部
+            String zd = item.getString("F_UNW_Assistant_qov.FNumber");//终端
+            String sh = item.getString("FTAXREGISTERCODE");//纳税登记号
+            //TODO:向宜搭插入数据
+//            String sc = "textField_mnr290ot, employeeField_lqanqe6n_id, employeeField_lqanqe6n_id, departmentSelectField_lympbaya, selectField_mnft99uc, selectField_lqanqe6t, selectField_mnft99ud, selectField_mnft99ue,textField_mn2k7pjl,textField_llujklkq";
+            String sc = "textField_mnr290ot, textField_lqanqe6j, employeeField_lqanqe6n, departmentSelectField_lympbaya, selectField_lqanqe6t, selectField_mnft99uc, selectField_mnft99ud, selectField_mnft99ue, textField_mn2k7pjl, textField_llujklkq";
+            List<Map> conditions = Arrays.asList( YDConf.searchCondition_TextFiled("textField_lqanqe6j", khmc, "eq"));//根据客户名称
+            Map formData = UtilMap.map(sc,bm,khmc,ywy_array,xsbm_array,hy,sktj,syb,zd,sh,sh);
+            ydClient.operateData(YDParam.builder()
+                    .formUuid("FORM-A4C9F5F35B48419A9C607D3408ECAB02A7FL")
+                    .searchCondition(JSONObject.toJSONString(conditions))
+                    .formDataJson(JSONObject.toJSONString(formData))
+                    .build(),YDConf.FORM_OPERATION.upsert);
+
+        }
+        log.info("客户已同步");
+    }
+
+
+    private McR saveToAudit(String formid, Object object) throws Exception {
+        JSONObject resultObj = new JSONObject();
+        K3CloudApi client = new K3CloudApi(initIden());
+        String result=client.save(formid,JSONObject.toJSONString(UtilMap.map("Model",object)));
+        resultObj.put("save",result);
+        Gson gson = new Gson();
+        RepoRet sRet = gson.fromJson(result, RepoRet.class);
+        if (sRet.isSuccessfully()) {
+            JsonObject jsonData = new JsonObject();
+            jsonData.addProperty("Ids", sRet.getResult().getId());
+            String result2=client.submit(formid, jsonData.toString());
+            resultObj.put("save",result2);
+            RepoRet sRet2 = gson.fromJson(result, RepoRet.class);
+            if (sRet2.isSuccessfully()) {
+                JsonObject jsonData3 = new JsonObject();
+                jsonData3.addProperty("Ids", sRet2.getResult().getId());
+                String result3 = client.audit(formid, jsonData3.toString());
+                RepoRet repoRet3 = gson.fromJson(result3, RepoRet.class);
+                if (repoRet3.getResult().getResponseStatus().isIsSuccess()) {
+                    log.info("审批通过,新增完成");
+                    return McR.success(resultObj);
+                }
+            }
+        }
+        return McR.error("203",JSONObject.toJSONString(resultObj));
+    }
+
+
+    private IdentifyInfo initIden(){
+        //注意 1:此处不再使用参数形式传入用户名及密码等敏感信息,改为在登录配置文件中设置。
+        //注意 2:必须先配置第三方系统登录授权信息后,再进行业务操作,详情参考各语言版本SDK介绍中的登录配置文件说明。
+        //读取配置,初始化SDK
+        IdentifyInfo iden = new IdentifyInfo();
+        iden.setUserName(kdWebApiConf.getXKDApiUserName());
+        iden.setAppId(kdWebApiConf.getXKDApiAppID());
+        iden.setdCID(kdWebApiConf.getXKDApiAcctID());
+        iden.setAppSecret(kdWebApiConf.getXKDApiAppSec());
+        iden.setServerUrl(kdWebApiConf.getXKDApiServerUrl());
+
+        return iden;
+    }
+
+
+    /*TODO:钉钉获取应用token*/
+    public McR Accesstoken() throws JsonProcessingException{
+        HashMap body = new HashMap();
+        body.put("appKey","dinga81qkwb0sqxqnviw");
+        body.put("appSecret","IvePeLbMMxAzIr228RaGcOxgSSOuJ0trbenX3BbahjeLFA2YeaFv0W9F_6Ar5G0P");
+        String doGet = UtilHttp.doPost("https://oapi.dingtalk.com/v1.0/oauth2/accessToken", null, null,body);
+        JSONObject jsonObject = JSONObject.parseObject(doGet);
+        String accessToken = jsonObject.getString("access_token");
+        log.info("accessToken:{}",accessToken);
+        return McR.success(accessToken);
+    }
+
 }

+ 1 - 1
mjava-zhiwei/src/main/resources/application-dev.yml

@@ -7,7 +7,7 @@ enable:
   scheduling: true
 logging:
   config: classpath:logback-spring.xml
-  path: /home/server/zhiwei/log/
+  path: ./log/
   level:
     com.malk.*: debug
 

+ 46 - 0
mjava-zhiwei/src/main/resources/application-prod.yml

@@ -0,0 +1,46 @@
+server:
+  port: 9001
+  servlet:
+    context-path: /zhiwei
+
+enable:
+  scheduling: true
+logging:
+  config: classpath:logback-spring.xml
+  path: ./log/
+  level:
+    com.malk.*: debug
+
+# dingtalk
+dingtalk:
+  agentId: 4457395865
+  appKey: ding2ru5r5d2vtaqf67m
+  appSecret: nuxuhb23-XX26_P5fP8Kbv43R3SzCiEhxkt4hQ_p44XA8r6hR3UkgLrTeXxRH_RA
+  corpId:
+  aesKey:
+  token:
+
+# aliwork
+aliwork:
+  appType: APP_G0JV4FGIR0EOSBD0K7XV
+  systemToken: F2766O91DH8WNHHUD63KBDP3B5GE234U4ZSBMBS1
+
+kingdee:
+  # 第三方系统登录授权的账套ID
+  X-KDApi-AcctID: 69264a17165c35
+  # 第三方系统登录授权的用户
+  X-KDApi-UserName: thirdpart
+  # 第三方系统登录授权的应用ID
+  X-KDApi-AppID: 337911_329JQ8FO3ID86X9sxYTLUz0K1NT8WCoJ
+  # 第三方系统登录授权的应用密钥
+  X-KDApi-AppSec: a68e6297abce4c9d8836dfce12512b39
+  # 服务Url地址(公有云统一走网关sdk底层已处理,无需传X-KDApi-ServerUrl,下面这行需要注释)
+  X-KDApi-ServerUrl: http://211.91.58.31:8081/k3cloud/
+  # 账套语系,默认2052
+  # X-KDApi-LCID: 2052
+  # 组织编码,启用多组织时配置对应的组织编码才有效
+  # X-KDApi-OrgNum: 100
+  # 允许的最大连接延时,单位为秒
+  # X-KDApi-ConnectTimeout: 120
+  # 允许的最大读取延时,单位为秒
+  # X-KDApi-RequestTimeout: 120

+ 1 - 1
mjava-zhiwei/src/main/resources/application.yml

@@ -1,6 +1,6 @@
 spring:
   profiles:
-    active: dev
+    active: prod
   servlet:
     multipart:
       max-file-size: 100MB

+ 21 - 3
mjava-zhiwei/src/test/java/com/malk/zhiwei/JdTest.java

@@ -12,8 +12,11 @@ import com.malk.server.aliwork.YDConf;
 import com.malk.server.aliwork.YDParam;
 import com.malk.server.aliwork.YDSearch;
 import com.malk.server.common.McR;
+import com.malk.server.dingtalk.DDR;
 import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
 import com.malk.utils.PublicUtil;
+import com.malk.utils.UtilHttp;
 import com.malk.utils.UtilMap;
 import com.malk.zhiwei.config.KDWebApiConf;
 import com.malk.zhiwei.entity.*;
@@ -33,6 +36,8 @@ public class JdTest {
 
     @Autowired
     private KDWebApiConf kdWebApiConf;
+    @Autowired
+    private DDClient ddClient;
 
     @Autowired
     private YDClient ydClient;
@@ -86,7 +91,13 @@ public class JdTest {
 
     @Test
     public void saveCust() throws Exception {
-        CustomerModel customerModel = new CustomerModel("测试客户");
+        FNumber zd = new FNumber("其他");//终端
+        FNumber syb = new FNumber("MPP");//事业部
+        FNumber hy = new FNumber("001");//行业
+        FNumber sktj = new FNumber("008");//收款条件
+        FNumber xsbm = new FNumber("BM000027");//销售部门
+        FNumber xsy = new FNumber("0016_GW000014_1");//销售员
+        CustomerModel customerModel = new CustomerModel("测试客户3",sktj,hy,syb,zd,"李英","1234",xsbm,xsy);
         System.out.println(saveToAudit("BD_Customer", customerModel));
     }
 
@@ -129,7 +140,7 @@ public class JdTest {
 //            billQuery.setFieldKeys("FBillNo,FBillTypeID.FName,FPAYUNITTYPE,FDate,FPAYUNIT.FName,FCURRENCYID.FName,FRECEIVEAMOUNTFOR_H,FREALRECAMOUNTFOR,FSALEERID.FName,FSETTLETYPEID,FSETTLETYPEID.FName,FPURPOSEID.FName,FACCOUNTID.FNumber,FACCOUNTID.FName,FRECTOTALAMOUNTFOR,FREALRECAMOUNTFOR_D,FCOMMENT");
             List<Map> filterString = new ArrayList<>();
             //审核日期为昨天至今天
-            filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",4,"","","0"));//审核日期在今天之前N天以后
+            filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","265",1,"","","0"));//审核日期在今天之前N天以后
 //        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FApproveDate","420","2025-10-20 00:00:00","","","0"));//审核日期年=XX
 //        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FNumber","67","35","","","0"));//物料编码等于XX
             billQuery.setFilterString(filterString);
@@ -186,9 +197,16 @@ public class JdTest {
 
     @Test
     public void queryOrder2(){
-
+        Map body = new HashMap();
+        body.put("queryWord","李英");
+        body.put("offset",0);
+        body.put("size",10);
+        body.put("fullMatchField",1);
+        DDR ddr  = (DDR) UtilHttp.doPost("https://api.dingtalk.com/v1.0/contact/users/search", ddClient.initTokenHeader(), new HashMap<>(), body, DDR.class);
+        System.out.println(ddr);
     }
 
 
 
+
 }

+ 24 - 0
mjava-zhongche/pom.xml

@@ -46,4 +46,28 @@
             <scope>provided</scope>
         </dependency>
     </dependencies>
+
+    <build>
+        <finalName>zhongche</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <executable>true</executable>
+                    <includeSystemScope>true</includeSystemScope>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
 </project>

+ 29 - 0
mjava-zhongche/src/main/java/com/malk/zhongche/controller/ZhongcheController.java

@@ -0,0 +1,29 @@
+package com.malk.zhongche.controller;
+
+import com.malk.server.common.McR;
+import com.malk.zhongche.service.ZhongcheService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+@RestController
+public class ZhongcheController {
+    @Autowired
+    private ZhongcheService zhongcheService;
+
+    //获取任务信息
+    @GetMapping("/getTaskInfo")
+    public McR getTaskInfo(String taskId,String projectId){
+        return zhongcheService.getTaskInfo(taskId,projectId);
+    }
+
+    //更新任务延期信息
+    @PostMapping("/updateTaskDelayInfo")
+    public McR updateTaskDelayInfo(@RequestBody Map map){
+        return zhongcheService.updateTaskDelayInfo(map);
+    }
+}

+ 12 - 0
mjava-zhongche/src/main/java/com/malk/zhongche/service/ZhongcheService.java

@@ -0,0 +1,12 @@
+package com.malk.zhongche.service;
+
+import com.malk.server.common.McR;
+
+import java.util.Map;
+
+public interface ZhongcheService {
+    McR getTaskInfo(String taskId,String projectId);
+
+    McR updateTaskDelayInfo(Map map);
+
+}

+ 238 - 0
mjava-zhongche/src/main/java/com/malk/zhongche/service/impl/ZhongcheServiceImpl.java

@@ -0,0 +1,238 @@
+package com.malk.zhongche.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McR;
+import com.malk.server.teambition.TBConf;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.service.teambition.TBClient;
+import com.malk.utils.UtilMap;
+import com.malk.zhongche.service.ZhongcheService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+@Slf4j
+@Service
+public class ZhongcheServiceImpl implements ZhongcheService {
+    @Autowired
+    private TBClient tbClient;
+
+    @Autowired
+    private YDClient ydClient;
+
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+
+    @Autowired
+    private DDClient ddClient;
+
+    @Autowired
+    private TBConf tbConf;
+
+    @Override
+    public McR getTaskInfo(String taskId,String projectId) {
+        Map taskInfo = tbClient.queryTaskDetail(taskId,null,null).get(0);
+
+        log.info("taskInfo:{}", JSONObject.toJSONString(taskInfo));
+
+        List<Map> customfields = UtilMap.getList(taskInfo, "customfields");
+
+        List<String> wtls = new ArrayList<>();//问题类型
+
+        for (Map customfield : customfields) {
+            String cfId = UtilMap.getString(customfield, "cfId");
+
+            switch (cfId){
+                case "6941202e92136abe2d9de68f"://问题类型
+                    List<Map> value = UtilMap.getList(customfield, "value");
+
+                    for (Map map : value) {
+                        wtls.add(UtilMap.getString(map, "title"));
+                    }
+                    break;
+                case "6969da08b9d8a458d706212d"://完成状态
+                    break;
+                case "6969dc054cd1174e86aa213a"://延期次数
+                    break;
+            }
+        }
+
+        String executorId = UtilMap.getString(taskInfo, "executorId");//执行者id
+
+        Map ddUser = new HashMap();
+        if (Strings.isNotBlank(executorId)){
+            Map ddUserInfo = tbClient.idMapQuery(executorId, true).get(0);
+            Map extra = UtilMap.getMap(ddUserInfo, "extra");
+            String ddUserId = UtilMap.getString(extra, "userId");//执行人钉钉userid
+            Map userInfoById = ddClient_contacts.getUserInfoById(ddClient.getAccessToken(),ddUserId);
+            String ddUserName = UtilMap.getString(userInfoById, "name");//执行人钉钉姓名
+            ddUser.put("label",ddUserName);
+            ddUser.put("value",ddUserId);
+            ddUser.put("emplId",ddUserId);
+        }
+
+        Long startDate = extracted(UtilMap.getString(taskInfo, "startDate"));//任务开始时间
+        Long dueDate = extracted(UtilMap.getString(taskInfo, "dueDate"));//任务截止时间
+
+        String tfsId = UtilMap.getString(taskInfo, "tfsId");//任务状态id
+
+        Map body = new HashMap();
+        body.put("tfsIds", tfsId);
+        Map tfsInfo = tbClient.queryProjectCustomFlowStatus(projectId, body).get(0);
+        String tfsName = UtilMap.getString(tfsInfo, "name");//任务状态
+
+        String parentTaskId = UtilMap.getString(taskInfo, "parentTaskId");
+        String parentTaskName = "";
+        String rootTaskName = "";
+        if (Strings.isNotBlank(parentTaskId)){
+            //获取tb任务上级任务
+            Map parentTaskInfo = tbClient.queryTaskDetail(parentTaskId, null, null).get(0);
+            parentTaskName = UtilMap.getString(parentTaskInfo, "content");
+
+            //获取tb顶级任务
+            Map rootTaskInfo = getRootTask(parentTaskId);
+            rootTaskName = UtilMap.getString(rootTaskInfo, "content");
+        }
+
+        Map result = new HashMap();
+        result.put("wtls", wtls);
+        result.put("ddUser", ddUser);
+        result.put("startDate", startDate);
+        result.put("dueDate", dueDate);
+        result.put("tfsName", tfsName);
+        result.put("parentTaskName", parentTaskName);
+        result.put("rootTaskName", rootTaskName);
+
+
+        return McR.success(result);
+    }
+
+    @Override
+    public McR updateTaskDelayInfo(Map map) {
+        String formInstId = UtilMap.getString(map, "formInstId");
+
+        Map formData = ydClient.queryData(YDParam.builder()
+                .formInstanceId(formInstId)
+                .build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+
+        String projectId = UtilMap.getString(formData, "textField_mkkrgg8u");//项目id
+        String taskId = UtilMap.getString(formData, "textField_mkkrgg8y");//任务id
+        long dueDate = UtilMap.getLong(formData, "dateField_mn757w7y");//预计完成时间
+        List<String> questionTypes = UtilMap.getList(formData, "multiSelectField_mn757w7v");//任务类型
+
+        Map taskInfo = tbClient.queryTaskDetail(taskId, null, null).get(0);
+
+        List<Map> customfields = UtilMap.getList(taskInfo, "customfields");
+
+        int delayNum = 0;//延期次数
+
+        for (Map customfield : customfields) {
+            String cfId = UtilMap.getString(customfield, "cfId");
+
+            switch (cfId){
+                case "6941202e92136abe2d9de68f"://问题类型
+                    break;
+                case "6969da08b9d8a458d706212d"://完成状态
+                    break;
+                case "6969dc054cd1174e86aa213a"://延期次数
+                    List<Map> values = UtilMap.getList(customfield, "value");
+                    if (Objects.nonNull(values) && !values.isEmpty()){
+                        Map value = values.get(0);
+                        delayNum = Integer.parseInt(UtilMap.getString(value, "title"));
+                        break;
+                    }
+            }
+        }
+
+        //更新任务截止时间
+
+        // 1. 转换为 Instant(UTC 时间点)
+        Instant instant = Instant.ofEpochMilli(dueDate);
+
+        // 2.1 转换为 UTC 时间(比上海时间早 8 小时)
+        ZonedDateTime utcTime = instant.atZone(ZoneId.of("UTC"));
+        DateTimeFormatter utcFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
+        String utcDateTime = utcTime.format(utcFormatter);
+        System.out.println("UTC date-time (比上海早8小时): " + utcDateTime); // 输出: 2026-03-20T01:30:00Z
+
+        tbClient.updateTaskDueDate(taskId, utcDateTime, tbConf.getOperatorId());
+
+        //更新任务延期次数
+        Map body = new HashMap();
+        body.put("customfieldId", "6969dc054cd1174e86aa213a");
+
+        Map value = new HashMap();
+        value.put("title",delayNum + 1 + "");
+        body.put("value",Arrays.asList(value));
+
+        Map map1 = tbClient.updateTaskCustomField(taskId, tbConf.getOperatorId(), body);
+
+        log.info("map1:{}",JSONObject.toJSONString(map1));
+
+        //更新任务问题类型
+        Map body2 = new HashMap();
+        body2.put("customfieldId", "6941202e92136abe2d9de68f");
+        List<Map> value2 = new ArrayList<>();
+        for (String questionType : questionTypes) {
+            Map map3 = new HashMap();
+            map3.put("title", questionType);
+            value2.add(map3);
+        }
+        body2.put("value",value2);
+
+        Map map2 = tbClient.updateTaskCustomField(taskId, tbConf.getOperatorId(), body2);
+
+        log.info("map1:{}",JSONObject.toJSONString(map1));
+
+        return McR.success();
+    }
+
+    private Map getRootTask(String taskId) {
+        Map taskInfo = tbClient.queryTaskDetail(taskId, null, null).get(0);
+
+        String parentTaskId = UtilMap.getString(taskInfo, "parentTaskId");
+
+        if (Strings.isNotBlank(parentTaskId)){
+            return getRootTask(parentTaskId);
+        }else {
+            return taskInfo;
+        }
+    }
+
+    //转换时区并返回时间戳
+    private static Long extracted(String dateStr) {
+        if (Strings.isNotBlank(dateStr)){
+            // 1. 解析为 Instant(UTC 时间)
+            Instant instant = Instant.parse(dateStr);
+
+            // 2. 转换为目标时区(Asia/Shanghai, UTC+8)
+            ZoneId shanghaiZone = ZoneId.of("Asia/Shanghai");
+            ZonedDateTime shanghaiTime = instant.atZone(shanghaiZone);
+
+            // 3. 转换为时间戳(毫秒)
+            long timestamp = shanghaiTime.toInstant().toEpochMilli();
+
+            // 输出结果
+            System.out.println("UTC 时间: " + instant);
+            System.out.println("上海时间: " + shanghaiTime);
+            System.out.println("时间戳(毫秒): " + timestamp);
+
+            return timestamp;
+        }else {
+            return null;
+        }
+
+    }
+}

+ 9 - 5
mjava-zhongche/src/main/resources/application-dev.yml

@@ -13,10 +13,10 @@ logging:
 
 # dingtalk
 dingtalk:
-  agentId:
-  appKey:
-  appSecret:
-  corpId:
+  agentId: 4396020096
+  appKey: ding26hdqsk96t6t6np0
+  appSecret: pBjGhyUDyinn192nDK7DQcaEsaGDDwfTLOsER-X3ZoWhGU9DURZGykRkw3aLgAtE
+  corpId: ding187f52da89b1e5c8a1320dcb25e91351
   aesKey:
   token:
   operator:
@@ -25,4 +25,8 @@ aliwork:
   appType: APP_SL9V2KUH6GBEISLNXXTJ
   systemToken: HOE66T71Z9H2PLVHM6EU85Q7H2AJ2YV2GRKKMWL1
 
-
+teambition:
+  AppID: 69c4f0f024a34a74e1c06d61
+  AppSecret: X77qcnv2AICiv70R41YZxGVFXRrFGCta
+  OperatorId: 67ce737aaec2f7379c7bbf6f
+  TenantId: 658a6467d87ead477d2d3f9d

+ 12 - 8
mjava-zhongche/src/main/resources/application-prod.yml

@@ -9,20 +9,24 @@ logging:
   config: classpath:logback-spring.xml
   path: /home/server/zhongche/log/
   level:
-    com.malk.*: info
+    com.malk.*: debug
 
 # dingtalk
 dingtalk:
-  agentId:
-  appKey:
-  appSecret:
-  corpId:
+  agentId: 4396020096
+  appKey: ding26hdqsk96t6t6np0
+  appSecret: pBjGhyUDyinn192nDK7DQcaEsaGDDwfTLOsER-X3ZoWhGU9DURZGykRkw3aLgAtE
+  corpId: ding187f52da89b1e5c8a1320dcb25e91351
   aesKey:
   token:
   operator:
 
 aliwork:
-  appType:
-  systemToken:
-
+  appType: APP_SL9V2KUH6GBEISLNXXTJ
+  systemToken: HOE66T71Z9H2PLVHM6EU85Q7H2AJ2YV2GRKKMWL1
 
+teambition:
+  AppID: 69c4f0f024a34a74e1c06d61
+  AppSecret: X77qcnv2AICiv70R41YZxGVFXRrFGCta
+  OperatorId: 67ce737aaec2f7379c7bbf6f
+  TenantId: 658a6467d87ead477d2d3f9d

+ 4 - 0
mjava-zhongche/src/test/java/com/malk/zhongche/ZcTest.java

@@ -0,0 +1,4 @@
+package com.malk.zhongche;
+
+public class ZcTest {
+}