Kaynağa Gözat

Merge remote-tracking branch 'origin/master'

xmy 4 ay önce
ebeveyn
işleme
bc3fb8d277
80 değiştirilmiş dosya ile 9045 ekleme ve 165 silme
  1. 5 2
      mjava-fenggefushi/src/main/java/com/malk/fenggefushi/service/Impl/HeiHuOrderServiceImpl.java
  2. 84 0
      mjava-heshu/pom.xml
  3. 17 0
      mjava-heshu/src/main/java/com/malk/heshu/HeShuApplication.java
  4. 24 0
      mjava-heshu/src/main/java/com/malk/heshu/config/KDWebApiConf.java
  5. 34 0
      mjava-heshu/src/main/java/com/malk/heshu/config/KDWebApiConfig.java
  6. 256 0
      mjava-heshu/src/main/java/com/malk/heshu/controller/HeShuController.java
  7. 18 0
      mjava-heshu/src/main/java/com/malk/heshu/entity/BillQuery.java
  8. 26 0
      mjava-heshu/src/main/java/com/malk/heshu/entity/ContactInfo.java
  9. 189 0
      mjava-heshu/src/main/java/com/malk/heshu/entity/CustomerInfo.java
  10. 40 0
      mjava-heshu/src/main/java/com/malk/heshu/entity/FBillHead.java
  11. 15 0
      mjava-heshu/src/main/java/com/malk/heshu/entity/FNumber.java
  12. 18 0
      mjava-heshu/src/main/java/com/malk/heshu/entity/IdObject.java
  13. 7 0
      mjava-heshu/src/main/java/com/malk/heshu/entity/Model.java
  14. 215 0
      mjava-heshu/src/main/java/com/malk/heshu/entity/SupplierEntity.java
  15. 54 0
      mjava-heshu/src/main/java/com/malk/heshu/schedule/XiDingTask.java
  16. 45 0
      mjava-heshu/src/main/resources/application-dev.yml
  17. 45 0
      mjava-heshu/src/main/resources/application-prod.yml
  18. 15 0
      mjava-heshu/src/main/resources/application.yml
  19. 61 0
      mjava-heshu/src/main/resources/logback-spring.xml
  20. 321 0
      mjava-heshu/src/test/java/com/malk/heshu/JdTest.java
  21. 2 0
      mjava-huagao/src/main/java/com/malk/huagao/service/impl/KdYdOrderServiceImpl.java
  22. 1 1
      mjava-huagao/src/test/java/com/malk/huagao/EqbTest.java
  23. 8 0
      mjava-jinlun/src/main/java/com/malk/jinlun/schedule/JinlunTask.java
  24. 3 0
      mjava-jinlun/src/main/java/com/malk/jinlun/service/JinlunTaskService.java
  25. 153 14
      mjava-jinlun/src/main/java/com/malk/jinlun/service/impl/JinlunTaskServiceImpl.java
  26. 5 0
      mjava-jinlun/src/test/java/com/malk/jinlun/DdTest.java
  27. 153 0
      mjava-qiwang/pom.xml
  28. 112 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Controller/CallBackController.java
  29. 222 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Controller/CompanyTitleController.java
  30. 120 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Controller/InvoiceLibraryController.java
  31. 907 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Controller/QiWangController.java
  32. 18 0
      mjava-qiwang/src/main/java/com/malk/qiwang/MjavaQiwangApplication.java
  33. 19 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Service/ICompanyTitleService.java
  34. 36 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Service/IInvoiceLibraryService.java
  35. 7 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Service/McProjectService.java
  36. 9 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Service/QiWangService.java
  37. 39 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Service/TXYInvoice.java
  38. 151 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Service/impl/CompanyTitleServiceImpl.java
  39. 2652 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Service/impl/InvoiceLibraryServiceImpl.java
  40. 29 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Service/impl/McProjectServiceImpl.java
  41. 17 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Service/impl/QiWangServiceImpl.java
  42. 165 0
      mjava-qiwang/src/main/java/com/malk/qiwang/Service/impl/TXYImplInvoice.java
  43. 19 0
      mjava-qiwang/src/main/java/com/malk/qiwang/config/StartupRunner.java
  44. 76 0
      mjava-qiwang/src/main/java/com/malk/qiwang/entity/CompanyTitle.java
  45. 128 0
      mjava-qiwang/src/main/java/com/malk/qiwang/entity/InvoiceLibrary.java
  46. 46 0
      mjava-qiwang/src/main/java/com/malk/qiwang/mapper/CompanyTitleMapper.java
  47. 26 0
      mjava-qiwang/src/main/java/com/malk/qiwang/mapper/InvoiceLibraryMapper.java
  48. 5 0
      mjava-qiwang/src/main/java/com/malk/qiwang/mapper/xml/CompanyTitleMapper.xml
  49. 5 0
      mjava-qiwang/src/main/java/com/malk/qiwang/mapper/xml/InvoiceLibraryMapper.xml
  50. 220 0
      mjava-qiwang/src/main/java/com/malk/qiwang/model/McInvoiceDto.java
  51. 68 0
      mjava-qiwang/src/main/java/com/malk/qiwang/model/McInvoiceKind.java
  52. 40 0
      mjava-qiwang/src/main/java/com/malk/qiwang/tencent/TXYConf.java
  53. 113 0
      mjava-qiwang/src/main/java/com/malk/qiwang/tencent/TXYConfNh.java
  54. 267 0
      mjava-qiwang/src/main/java/com/malk/qiwang/utils/HTTPHelper.java
  55. 84 0
      mjava-qiwang/src/main/java/com/malk/qiwang/utils/MPGenerator.java
  56. 61 0
      mjava-qiwang/src/main/resources/application-dev.yml
  57. 60 0
      mjava-qiwang/src/main/resources/application-prod.yml
  58. 15 0
      mjava-qiwang/src/main/resources/application.yml
  59. 61 0
      mjava-qiwang/src/main/resources/logback-spring.xml
  60. 13 0
      mjava-qiwang/src/test/java/com/malk/qiwang/MjavaQiwangApplicationTests.java
  61. 23 7
      mjava-siku/src/main/java/com/malk/siku/controller/SikuController.java
  62. 2 1
      mjava-siku/src/main/java/com/malk/siku/schedule/SikuTask.java
  63. 4 0
      mjava-siku/src/main/java/com/malk/siku/service/SikuService.java
  64. 423 127
      mjava-siku/src/main/java/com/malk/siku/service/impl/SikuServiceImpl.java
  65. 1 0
      mjava-siku/src/main/java/com/malk/siku/service/impl/SikuTaskServiceImpl.java
  66. 4 4
      mjava-siku/src/main/java/com/malk/siku/utils/MkBxUtil.java
  67. 34 4
      mjava-siku/src/main/java/com/malk/siku/utils/MkYpUtil.java
  68. 178 0
      mjava-siku/src/main/java/com/malk/siku/utils/QyddUtil.java
  69. 108 4
      mjava-siku/src/test/java/com.malk.siku/SkTest.java
  70. 74 0
      mjava-yzl/pom.xml
  71. 17 0
      mjava-yzl/src/main/java/com/malk/yzl/YzlApplication.java
  72. 114 0
      mjava-yzl/src/main/java/com/malk/yzl/controller/ZzwController.java
  73. 32 0
      mjava-yzl/src/main/resources/application-dev.yml
  74. 15 0
      mjava-yzl/src/main/resources/application.yml
  75. 61 0
      mjava-yzl/src/main/resources/logback-spring.xml
  76. 138 0
      mjava-yzl/src/test/java/com/malk/yzl/JdTest.java
  77. 6 0
      mjava-zhongche/src/main/java/com/malk/zhongche/controller/ZhongcheController.java
  78. 4 0
      mjava-zhongche/src/main/java/com/malk/zhongche/service/ZhongcheService.java
  79. 164 1
      mjava-zhongche/src/main/java/com/malk/zhongche/service/impl/ZhongcheServiceImpl.java
  80. 19 0
      mjava-zhongche/src/test/java/com/malk/zhongche/ZcTest.java

+ 5 - 2
mjava-fenggefushi/src/main/java/com/malk/fenggefushi/service/Impl/HeiHuOrderServiceImpl.java

@@ -2553,13 +2553,14 @@ public class HeiHuOrderServiceImpl implements HeiHuOrderService {
         for (Map<String, Object> row : tableData) {
 //            String orderCode = row.get("textField_mm2t71jm"); // 采购订单号
             String orderCode = UtilMap.getString(row,"textField_mm2t71jm");
+            String saleOrderCode = UtilMap.getString(row,"textField_ml6g7k5f");
             String orderFax = UtilMap.getString(row,"orderFax");
             if (orderCode == null || orderCode.isEmpty()) {
                 continue;
             }
 
             // 获取或创建该订单的汇总Map
-            Map<String, Double> orderSum = summaryMap.computeIfAbsent(orderCode+"~"+orderFax,
+            Map<String, Double> orderSum = summaryMap.computeIfAbsent(orderCode+"~"+orderFax + "~"+saleOrderCode,
                     k -> {
                         Map<String, Double> newMap = new HashMap<>();
                         newMap.put("salesAmount", 0.0);      // 销售金额总和
@@ -2602,6 +2603,7 @@ public class HeiHuOrderServiceImpl implements HeiHuOrderService {
         for (Map.Entry<String, Map<String, Double>> entry : summaryMap.entrySet()) {
             String[] split = entry.getKey().split("~");
             String orderCode = split[0];
+            String saleOrderCode = split[2];
             Double orderFax = Double.parseDouble(split[1]);
             Map<String, Double> sums = entry.getValue();
 
@@ -2612,10 +2614,11 @@ public class HeiHuOrderServiceImpl implements HeiHuOrderService {
             // 构建结果行
             Map<String, String> summaryRow = new LinkedHashMap<>();
             summaryRow.put("textField_ml7ch2pk", orderCode);//orderCode:采购审批单单号
+            summaryRow.put("textField_motpbfwq", saleOrderCode);//saleOrderCode:销售订单单号
             summaryRow.put("numberField_ml862225", formatNumber(salesAmount));//salesAmount:销售总金额
             summaryRow.put("numberField_ml862226", formatNumber(purchaseAmount));//purchaseAmount:采购订单总金额
             summaryRow.put("numberField_ml862228", formatNumber(flygcb));//flygcb:辅料预估总成本
-            summaryRow.put("numberField_ml86222d",formatNumber((salesAmount - purchaseAmount/orderFax - flygcb) / salesAmount));//毛利率
+            summaryRow.put("numberField_ml86222d",formatNumber((salesAmount - purchaseAmount/orderFax - flygcb) / salesAmount * 100));//毛利率
             Double mlv = (salesAmount - purchaseAmount/orderFax - flygcb) / salesAmount;
             if(mlv >= 0.15){
                 summaryRow.put("numberField_mm2t71jo", String.valueOf(1));

+ 84 - 0
mjava-heshu/pom.xml

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.7.18</version> <!-- 使用最新的稳定版或其他适用版本 -->
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <groupId>com.malk.heshu</groupId>
+    <artifactId>mjava-heshu</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>base</artifactId>
+            <version>1.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.example</groupId>
+            <artifactId>k3cloud</artifactId>
+            <version>8.2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.example</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>heshu</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>

+ 17 - 0
mjava-heshu/src/main/java/com/malk/heshu/HeShuApplication.java

@@ -0,0 +1,17 @@
+package com.malk.heshu;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+@EnableScheduling
+public class HeShuApplication {
+    public static void main(String[] args) {
+        try {
+            SpringApplication.run(HeShuApplication.class,args);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+}

+ 24 - 0
mjava-heshu/src/main/java/com/malk/heshu/config/KDWebApiConf.java

@@ -0,0 +1,24 @@
+package com.malk.heshu.config;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "kingdee")
+@Slf4j
+public class KDWebApiConf {
+
+    private String XKDApiAcctID;
+
+    private String XKDApiUserName;
+
+    private String XKDApiAppID;
+
+    private String XKDApiAppSec;
+
+    private String XKDApiServerUrl;
+
+}

+ 34 - 0
mjava-heshu/src/main/java/com/malk/heshu/config/KDWebApiConfig.java

@@ -0,0 +1,34 @@
+package com.malk.heshu.config;
+
+import com.kingdee.bos.webapi.entity.IdentifyInfo;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+public class KDWebApiConfig {
+    private Properties properties = new Properties();
+
+    public KDWebApiConfig(String filePath) throws IOException {
+        try (FileInputStream input = new FileInputStream(filePath)) {
+            properties.load(input);
+        }
+    }
+
+    public String getProperty(String key) {
+        return properties.getProperty(key);
+    }
+
+//    public static void main(String[] args) {
+//        try {
+//            KDWebApiConfig config = new KDWebApiConfig("mjava-jinlun/src/main/resources/application-dev.yml");
+//            System.out.println("AcctID: " + config.getProperty("X-KDApi-AcctID"));
+//            // 打印其他属性...
+//        } catch (IOException e) {
+//            e.printStackTrace();
+//        }
+//    }
+
+
+
+}

+ 256 - 0
mjava-heshu/src/main/java/com/malk/heshu/controller/HeShuController.java

@@ -0,0 +1,256 @@
+package com.malk.heshu.controller;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.fastjson.JSONObject;
+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.heshu.entity.*;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
+import com.malk.utils.PublicUtil;
+import com.malk.utils.UtilMap;
+import com.malk.heshu.config.KDWebApiConf;
+import lombok.extern.slf4j.Slf4j;
+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.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.fail;
+
+@RestController
+@Slf4j
+public class HeShuController {
+
+    @Autowired
+    private KDWebApiConf kdWebApiConf;
+    @Autowired
+    private YDClient ydClient;
+
+    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;
+    }
+    @GetMapping("/test")
+    public McR test(){
+        return McR.success("111");
+    }
+
+    @PostMapping("/saveSupplier")
+    public McR saveSupplier(@RequestBody JSONObject params){
+        log.info("saveSupplier:{}",params);
+        if(PublicUtil.isNull(params,"fid")){
+            return McR.error("201","缺少参数!");
+        }
+        try {
+            Thread.sleep(500);// 休眠5s避免同时更新一条数据
+            Map formData= (Map) ydClient.queryData(YDParam.builder().formInstId(params.getString("fid")).build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+            if(formData==null){
+                return McR.error("201","未查询到数据!");
+            }
+            List<String> types=UtilMap.getList(formData,"checkboxField_mma72l0x");
+            String gysType;
+            if(types.contains("供应商")){
+                gysType="01";
+            }else {
+                gysType="03";
+            }
+            SupplierEntity supplierEntity = BeanUtil.toBean(formData, SupplierEntity.class);
+            SupplierEntity.FBaseInfo fBaseInfo = BeanUtil.toBean(formData, SupplierEntity.FBaseInfo.class);
+            SupplierEntity.FFinanceInfo fFinanceInfo = BeanUtil.toBean(formData, SupplierEntity.FFinanceInfo.class);
+            List<Map> list=UtilMap.getList(formData,"tableField_mma72l0q");
+            List<SupplierEntity.FBankInfo> bkList=new ArrayList<>();
+            for(Map map:list){
+                SupplierEntity.FBankInfo  fBankInfo = BeanUtil.toBean(map, SupplierEntity.FBankInfo.class);
+                bkList.add(fBankInfo);
+            }
+            fBaseInfo.setFDeptId(new IdObject(UtilMap.getString(formData,"textField_mogukmdd")));// 业务部门
+            supplierEntity.setFBaseInfo(fBaseInfo);
+            supplierEntity.setFFinanceInfo(fFinanceInfo);
+            supplierEntity.setFBankInfo(bkList);
+            List<Map> list2=UtilMap.getList(formData,"tableField_mma72kx1");
+            List<SupplierEntity.FSupplierContact> lxrList=new ArrayList<>();
+            for(Map map:list2){
+                SupplierEntity.FSupplierContact  lxrInfo = BeanUtil.toBean(map, SupplierEntity.FSupplierContact.class);
+                lxrList.add(lxrInfo);
+            }
+            supplierEntity.setFSupplierContact(lxrList);
+            supplierEntity.setFGroup(new IdObject(gysType));
+            supplierEntity.setF_UNW_yida("https://garktl.aliwork.com/APP_QM42OEGLMNNGBLIJELJI/processDetail?formUuid=FORM-9C0EC03227CC49738447A27B4563779F0WLW&procInsId="+params.getString("fid"));
+            String operator=UtilMap.getString(formData,"radioField_mma72l0t");// 操作类型 客商准入  客商更新
+            if(operator.equals("客商更新")){
+                String fId=UtilMap.getString(formData,"textField_moi1ejl2");
+                if(!PublicUtil.isNull(fId)){
+                    // 反审核
+                    unAudit("BD_Supplier",fId);
+                    supplierEntity.setFSupplierId(Integer.parseInt(fId));
+                }
+            }
+            return  saveToAudit("BD_Supplier",supplierEntity,params.getString("fid"),params.getString("key"),"selectField_mogukmd9","textareaField_mogukmdb","textField_moi1ejl2",null);
+        }catch (Exception e){
+            return McR.error("201",e.getMessage());
+        }
+    }
+
+    @PostMapping("/saveCust")
+    public McR saveCust(@RequestBody JSONObject params){
+        log.info("saveCust:{}",params);
+        if(PublicUtil.isNull(params,"fid")){
+            return McR.error("201","缺少参数!");
+        }
+        try {
+            Map formData= (Map) ydClient.queryData(YDParam.builder().formInstId(params.getString("fid")).build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+            if(formData==null){
+                return McR.error("201","未查询到数据!");
+            }
+            formData.put("textField_mma6vp851",formData.get("textField_mma6vp85"));
+            formData.put("textField_mma6vp7p1",formData.get("textField_mma6vp7p"));
+            CustomerInfo customerInfo = BeanUtil.toBean(formData, CustomerInfo.class);
+            List<Map> list=UtilMap.getList(formData,"tableField_mma72l0q");
+            List<CustomerInfo.CustBank> bkList=new ArrayList<>();
+            for(Map map:list){
+                CustomerInfo.CustBank  fBankInfo = BeanUtil.toBean(map, CustomerInfo.CustBank.class);
+                bkList.add(fBankInfo);
+            }
+            customerInfo.setFT_BD_CUSTBANK(bkList);
+            List<Map> list2=UtilMap.getList(formData,"tableField_mma72kx1");
+            List<ContactInfo> lxrList=new ArrayList<>();
+            for(Map map:list2){
+                ContactInfo contactInfo=new ContactInfo();
+                contactInfo.setFName(UtilMap.getString(map,"textField_mma72kx2"));
+                contactInfo.setFMobile(UtilMap.getString(map,"textField_mma72kx3"));
+                contactInfo.setFCompanyType("BD_Customer");
+                contactInfo.setFBizLocation(UtilMap.getString(map,"textField_mogukmdi"));
+                contactInfo.setFBizAddress(UtilMap.getString(map,"textField_mogukmdi"));
+                lxrList.add(contactInfo);
+            }
+            customerInfo.setFSALDEPTID(new FNumber(UtilMap.getString(formData,"textField_mogukmdd")));// 业务部门
+            String custTypeValue=UtilMap.getString(formData,"radioField_mma72kxi");
+            String custType;
+            if(custTypeValue.equals("贸易商")){
+                custType="02";
+            }else if(custTypeValue.equals("工厂")){
+                custType="01";
+            }else {
+                custType="05";
+            }
+            customerInfo.setFGroup(new FNumber(custType));
+            String operator=UtilMap.getString(formData,"radioField_mma72l0t");// 操作类型 客商准入  客商更新
+            if(operator.equals("客商更新")){
+                String fId=UtilMap.getString(formData,"textField_moi1ejl1");
+                if(!PublicUtil.isNull(fId)){
+                    // 反审核
+                    unAudit("BD_Customer",fId);
+                    customerInfo.setFCUSTID(Integer.parseInt(fId));
+                }
+            }
+            return  saveToAudit("BD_Customer",customerInfo,params.getString("fid"),params.getString("key"),"selectField_mogukmd8","textareaField_mogukmda","textField_moi1ejl1",lxrList);
+        }catch (Exception e){
+            return McR.error("201",e.getMessage());
+        }
+    }
+
+
+    private McR saveToAudit(String formid, Object object,String fid,String codeKey,String statusKey,String msgKey,String idKey,List<ContactInfo> lxrList) 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);
+        JSONObject reObj = JSONObject.parseObject(result,JSONObject.class);
+        if (sRet.isSuccessfully()) {
+            if(!PublicUtil.isNull(codeKey)){
+                // 回写信息
+                Map updateMap=UtilMap.map(codeKey,reObj.getJSONObject("Result").getString("Number"));
+                updateMap.put(statusKey,"成功");
+                updateMap.put(idKey,reObj.getJSONObject("Result").getString("Id"));// ID 内码
+                ydClient.operateData(YDParam.builder().formInstId(fid).updateFormDataJson(
+                        JSONObject.toJSONString(updateMap)
+                ).build(), YDConf.FORM_OPERATION.update);
+            }
+            if(lxrList!=null){
+                for (ContactInfo contactInfo : lxrList) {
+                    contactInfo.setFCompany(new FNumber(reObj.getJSONObject("Result").getString("Number")));
+                    String data=new Gson().toJson(contactInfo);
+                    String id=saveToAudit("BD_CommonContact",new Gson().fromJson(data,Object.class));
+                }
+            }
+            JsonObject jsonData = new JsonObject();
+            jsonData.addProperty("Ids", sRet.getResult().getId());
+            String result2=client.submit(formid, jsonData.toString());
+            resultObj.put("submit",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());
+                resultObj.put("audit",result3);
+                RepoRet repoRet3 = gson.fromJson(result3, RepoRet.class);
+                if (repoRet3.getResult().getResponseStatus().isIsSuccess()) {
+                    log.info("审批通过,新增完成");
+                    return McR.success(resultObj);
+//                    Map map=UtilMap.map("PkIds, TOrgIds",sRet.getResult().getId(),"1,105818,105822,127834,127835,127838,127843,127846,127847,127848,127850,127862,1370321,1325841,1327202,1646858");
+//                    String result4=client.allocate("formid",JSONObject.toJSONString(map));
+//                    resultObj.put("allocate",result4);
+//                    RepoRet repoRet4 = gson.fromJson(result4, RepoRet.class);
+//                    if (repoRet4.getResult().getResponseStatus().isIsSuccess()) {
+//                        log.info("分配完成");
+//                        return McR.success(resultObj);
+//                    }
+                }
+            }
+        }else {
+            log.info("保存失败:{}",result);
+            Map updateMap=UtilMap.map(statusKey,"失败");
+            updateMap.put(msgKey,result);
+            ydClient.operateData(YDParam.builder().formInstId(fid).updateFormDataJson(
+                    JSONObject.toJSONString(updateMap)
+            ).build(), YDConf.FORM_OPERATION.update);
+        }
+        return McR.error("203",JSONObject.toJSONString(resultObj));
+    }
+    private String saveToAudit(String formid, Object object) throws Exception {
+        K3CloudApi client = new K3CloudApi(initIden());
+        String result=client.save(formid,JSONObject.toJSONString(UtilMap.map("Model",object)));
+        System.out.println(result);
+        Gson gson = new Gson();
+        RepoRet sRet = gson.fromJson(result, RepoRet.class);
+        JSONObject reObj = JSONObject.parseObject(result,JSONObject.class);
+        if (sRet.isSuccessfully()) {
+            return reObj.getJSONObject("Result").getString("Id");
+        }else {
+            return "";
+        }
+    }
+    private void unAudit(String formid,String fNumber) throws Exception {
+        K3CloudApi client = new K3CloudApi(initIden());
+        Gson gson = new Gson();
+        JsonObject jsonData = new JsonObject();
+        jsonData.addProperty("Ids", fNumber);
+        String result=client.unAudit(formid, jsonData.toString());
+        RepoRet sRet2 = gson.fromJson(result, RepoRet.class);
+        if (!sRet2.isSuccessfully()) {
+            log.info("反审核失败:{}",result);
+        }
+    }
+}

+ 18 - 0
mjava-heshu/src/main/java/com/malk/heshu/entity/BillQuery.java

@@ -0,0 +1,18 @@
+package com.malk.heshu.entity;
+
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class BillQuery {
+    private String FormId;
+    private String FieldKeys;
+    private List<Map> FilterString;
+    private String OrderString;
+    private int TopRowCount;
+    private int StartRow;
+    private int Limit;
+    private String SubSystemId;
+}

+ 26 - 0
mjava-heshu/src/main/java/com/malk/heshu/entity/ContactInfo.java

@@ -0,0 +1,26 @@
+package com.malk.heshu.entity;
+
+import lombok.Data;
+
+@Data
+public class ContactInfo {
+
+    private Integer FCONTACTID; //实体主键
+    private String FNumber; //编码
+    private String FName; //姓名 (必填项)
+    private FNumber Fex; //性别
+    private String FPost; //职务
+    private String FCompanyType; //类型 (必填项)
+    private FNumber FCompany; //所属公司
+    private String FTel; //固定电话
+    private String FMobile; //移动电话
+    private String FFax; //传真
+    private String FEmail; //邮箱
+    private String FBizAddress; //详细地址
+    private String FBizLocation; //地点名称
+    private String FBizLocNumber; //地点编码
+    private String FIsDefaultContact; //默认联系人
+    private String FIsDefaultConsignee; //默认收货地址
+    private String FForbidDate; //禁用日期
+    private FNumber FCustId; //客户编码
+}

+ 189 - 0
mjava-heshu/src/main/java/com/malk/heshu/entity/CustomerInfo.java

@@ -0,0 +1,189 @@
+package com.malk.heshu.entity;
+
+import cn.hutool.core.annotation.Alias;
+import lombok.Data;
+import java.util.List;
+
+/**
+ * 客户信息实体类
+ */
+@Data
+public class CustomerInfo {
+    
+    private Integer FCUSTID;                // 主键-客户ID
+    private FNumber FCreateOrgId = new FNumber("000");      // 创建组织(必填)
+    private String FNumber;                 // 客户编码
+    private FNumber FUseOrgId = new FNumber("000");;         // 使用组织
+    @Alias("textField_mma6vp7o")
+    private String FName;                   // 客户名称(必填)
+    private String FShortName;              // 简称
+    private FNumber FCOUNTRY;          // 国家
+    private FNumber FPROVINCIAL;       // 地区
+    private String FADDRESS;                // 通讯地址
+    private String FZIP;                    // 邮政编码
+    private String FWEBSITE;                // 公司网址
+    private String FTEL;                    // 联系电话
+    private String FFAX;                    // 传真
+    private FNumber FCompanyClassify;  // 公司类别
+    private FNumber FCompanyNature;    // 公司性质
+    private FNumber FCompanyScale;     // 公司规模
+    private String FINVOICETITLE;           // 发票抬头
+    @Alias("textField_mma6vp85")
+    private String FTAXREGISTERCODE;        // 纳税登记号
+    @Alias("textField_mma72kwv")
+    private String FINVOICEBANKNAME;        // 开户银行
+    private String FINVOICETEL;             // 开票联系电话
+    @Alias("textField_mma72kww")
+    private String FINVOICEBANKACCOUNT;     // 银行账号
+    @Alias("textField_mma6vp7p1")
+    private String FINVOICEADDRESS;         // 开票通讯地址
+    private FNumber FSUPPLIERID;       // 对应供应商
+    private String FIsGroup;                // 集团客户
+    private String FIsDefPayer;             // 默认付款方
+    private FNumber FCustTypeId;       // 客户类别
+    private FNumber FGROUPCUSTID;      // 对应集团客户
+    private FNumber FGroup;            // 客户分组
+    private FNumber FTRADINGCURRID;    // 结算币别(必填)
+    private FNumber FCorrespondOrgId;  // 对应组织
+    private String FDescription;            // 备注
+    private FNumber FSALDEPTID;        // 销售部门
+    private FNumber FSELLER;           // 销售员
+    private FNumber FSETTLETYPEID;     // 结算方式
+    private FNumber FRECCONDITIONID;   // 收款条件
+    private FNumber FDISCOUNTLISTID;   // 折扣表
+    private FNumber FPRICELISTID;      // 价目表
+    private Integer FTRANSLEADTIME;         // 运输提前期
+    private String FInvoiceType;            // 发票类型
+    private FNumber FTaxType;          // 税分类
+    private FNumber FRECEIVECURRID;    // 收款币别
+    private Integer FPriority;               // 客户优先级
+    private FNumber FTaxRate;          // 默认税率
+    private String FISCREDITCHECK;          // 启用信用管理
+    private String FIsTrade;                // 是否交易客户
+    private String F_JX_Combo;              // 是否信用客户(必填)
+    private String FUncheckExpectQty;       // 不校验可发量
+    @Alias("textField_mma6vp7v")
+    private String FLegalPerson;             // 法人代表
+    @Alias("numberField_mma6vp83")
+    private String FRegisterFund;           // 注册资本
+    @Alias("dateField_mma6vp7w")
+    private String FFoundDate;               // 创立日期
+    private String FDomains;                 // 行业
+    @Alias("textField_mma6vp851")
+    private String FSOCIALCRECODE;           // 统一社会信用代码
+    @Alias("textField_mma6vp7p")
+    private String FRegisterAddress;         // 注册地址
+    @Alias("textField_mogukmd2")
+    private String F_UNW_Remark_apv;           // 开票要求
+    @Alias("textField_mma72kx0")
+    private String F_UNW_Text_kpyx;          // 开票电子邮箱
+
+    private CustomerExt FT_BD_CUSTOMEREXT;   // 商务信息
+    private List<CustLocation> FT_BD_CUSTLOCATION;   // 联系人
+    private List<CustBank> FT_BD_CUSTBANK;           // 银行信息
+    private List<CustContact> FT_BD_CUSTCONTACT;     // 地址信息
+    private List<CustOrderOrg> FT_BD_CUSTORDERORG;   // 订货组织
+    private List<CustSubAccount> FT_BD_CUSTSUBACCOUNT; // 子账户信息
+
+
+    // 用户ID字段结构
+    @Data
+    public static class FUserIdField {
+        private String FUserID;
+    }
+    
+    // 商务信息扩展
+    @Data
+    public static class CustomerExt {
+        private Integer FEntryId;                // 主键
+        private String FEnableSL;                // 启用商联在线
+        private String FFreezeLimit;             // 冻结范围
+        private FUserIdField FFreezeOperator;    // 冻结人
+        private String FFreezeDate;              // 冻结日期
+        private FNumber FPROVINCE;          // 省份
+        private FNumber FCITY;              // 城市
+        private FNumber FDefaultConsiLoc;   // 默认收货地点
+        private FNumber FDefaultSettleLoc;  // 默认开票地点
+        private FNumber FDefaultPayerLoc;   // 默认付款地点
+        private FNumber FDefaultContact;    // 默认联系人
+        private Integer FMarginLevel;             // 保证金比例
+        private String FDebitCard;               // 结算卡
+        private FNumber FSettleId;          // 结算方
+        private FNumber FChargeId;          // 付款方
+        private String FALLOWJOINZHJ;             // 允许对接智慧订货
+        private FNumber FStarOrgId;         // 星辰组织
+    }
+    
+    // 联系人信息
+    @Data
+    public static class CustLocation {
+        private FNumber FContactId;         // 联系人编码
+        private String FIsDefaultConsigneeCT;    // 默认收货地址
+        private String FIsCopy;                  // 是否复制
+    }
+    
+    // 银行信息
+    @Data
+    public static class CustBank {
+        private Integer FENTRYID;                // 主键
+        private FNumber FCOUNTRY1;          // 开户国家
+        @Alias("textField_mma72kwy")
+        private String FBANKCODE;                // 银行账号
+        @Alias("textField_mogukmd1")
+        private String FACCOUNTNAME;             // 账户名称
+        private FNumber FBankTypeRec;       // 收款银行
+        private String FTextBankDetail;          // 网点名称
+        private FNumber FBankDetail;        // 银行网点
+        private String FOpenAddressRec;          // 开户行地址
+        @Alias("textField_mma72kwx")
+        private String FOPENBANKNAME;            // 开户银行
+        private String FCNAPS;                   // 联行号
+        private FNumber FCURRENCYID;        // 币别
+        private String FISDEFAULT1;              // 默认
+    }
+    
+    // 地址信息
+    @Data
+    public static class CustContact {
+        private Integer FENTRYID;                // 主键
+        private String FNUMBER1;                 // 交货地点编码
+        @Alias("textField_mogukmdi")
+        private String FNAME1;                   // 交货地点
+        @Alias("textField_mogukmdi")
+        private String FADDRESS1;                // 详细地址
+//        @Alias("textField_mogukmdf")
+        private FNAME FTContact;               // 联系人
+        @Alias("textField_mogukmdg")
+        private String FMOBILE;                  // 移动电话
+        private Integer FTRANSLEADTIME1;         // 运输提前期
+        private String FIsDefaultConsignee;      // 默认收货地址
+        private String FIsDefaultSettle;         // 默认开票地址
+        private String FIsDefaultPayer;          // 默认付款地址
+        private String FIsUsed;                  // 启用
+    }
+
+    @Data
+    public static class FNAME {
+        private String FNAME;
+        public FNAME(String FNAME) {
+            this.FNAME = FNAME;
+        }
+        public FNAME() {}
+    }
+    
+    // 订货组织
+    @Data
+    public static class CustOrderOrg {
+        private Integer FEntryID;                // 主键
+        private FNumber FOrderOrgId;        // 订货组织
+        private String FIsDefaultOrderOrg;       // 默认
+    }
+    
+    // 子账户信息
+    @Data
+    public static class CustSubAccount {
+        private Integer FEntryID;                // 主键
+        private String FSUBACCOUNTTYPE;          // 子账户类型
+        private String FSUBACCOUNT;              // 子账户号
+    }
+}

+ 40 - 0
mjava-heshu/src/main/java/com/malk/heshu/entity/FBillHead.java

@@ -0,0 +1,40 @@
+package com.malk.heshu.entity;
+
+import com.malk.utils.UtilMap;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class FBillHead extends Model{
+    private String FID;//实体主键
+    private String FDocumentStatus;//数据状态
+    private String FForbidStatus;//禁用状态
+    private String FName;//名称 (必填项)
+    private String FNumber;//编码
+    private String FDescription;//描述
+    private Map<String,String> FCreateOrgId;//创建组织 (必填项)
+    private Map<String,String> FUseOrgId;//使用组织 (必填项)
+    private String FCreatorId;//创建人
+    private String FModifierId;//修改人
+    private String FCreateDate;//创建日期
+    private String FModifyDate;//修改日期
+    private Map<String,String> F_ABC_Assistant;//项目类型 (必填项)
+    private String F_VPOX_Text;//CRM编号
+
+    public void setFCreateOrgId(String fCreateOrgId){
+        this.FCreateOrgId = UtilMap.map("FNumber",fCreateOrgId);
+    }
+    public void setFUseOrgId(String fUseOrgId){
+        this.FUseOrgId = UtilMap.map("FNumber",fUseOrgId);
+    }
+    public FBillHead(String FName,String FNumber,String type){
+        this.FUseOrgId = UtilMap.map("FNumber","100");
+        this.FCreateOrgId = UtilMap.map("FNumber","100");
+        this.FName=FName;
+        this.FNumber=FNumber;
+        this.F_ABC_Assistant = UtilMap.map("FNumber",type);
+    }
+    public FBillHead(){}
+}

+ 15 - 0
mjava-heshu/src/main/java/com/malk/heshu/entity/FNumber.java

@@ -0,0 +1,15 @@
+package com.malk.heshu.entity;
+
+import lombok.Data;
+
+@Data
+public class FNumber {
+    public FNumber() {
+    }
+
+    public FNumber(String FNumber) {
+        this.FNumber = FNumber;
+    }
+
+    private String FNumber;
+}

+ 18 - 0
mjava-heshu/src/main/java/com/malk/heshu/entity/IdObject.java

@@ -0,0 +1,18 @@
+package com.malk.heshu.entity;
+
+import lombok.Data;
+
+/**
+ * ID对象,用于存储带有编码或用户ID的对象
+ */
+@Data
+public class IdObject {
+    private String FNumber;      // 编码
+    private String FUserID;      // 用户ID
+    private String FNUMBER;      // 编码(大写形式)
+
+    public IdObject(String FNumber) {
+        this.FNumber = FNumber;
+    }
+    public IdObject(){};
+}

+ 7 - 0
mjava-heshu/src/main/java/com/malk/heshu/entity/Model.java

@@ -0,0 +1,7 @@
+package com.malk.heshu.entity;
+
+import lombok.Data;
+
+@Data
+public class Model {
+}

+ 215 - 0
mjava-heshu/src/main/java/com/malk/heshu/entity/SupplierEntity.java

@@ -0,0 +1,215 @@
+package com.malk.heshu.entity;
+
+import cn.hutool.core.annotation.Alias;
+import lombok.Data;
+import java.util.List;
+
+/**
+ * 供应商实体类
+ */
+@Data
+public class SupplierEntity {
+
+    // 单据头字段
+    private Integer FSupplierId;           // 实体主键
+    private String FDocumentStatus;        // 数据状态
+    private String FForbidStatus;          // 禁用状态
+    @Alias("textField_mma6vp7o")
+    private String FName;                  // 名称(必填项)
+    private String FNumber;                // 编码
+    private String FDescription;           // 描述
+    private IdObject FCreateOrgId = new IdObject("000");         // 创建组织(必填项)
+    private IdObject FUseOrgId = new IdObject("000");            // 使用组织(必填项)
+    private IdObject FCreatorId;           // 创建人
+    private IdObject FModifierId;          // 修改人
+    private String FCreateDate;            // 创建日期
+    private String FModifyDate;            // 修改日期
+    private String FShortName;             // 简称
+    private IdObject FForbiderId;          // 禁用人
+    private String FForbidDate;            // 禁用日期
+    private String FAuditDate;             // 审核日期
+    private IdObject FAuditorId;            // 审核人
+    private IdObject FGroup;               // 供应商分组
+    private IdObject FCorrespondOrgId;      // 对应组织
+    private String FSYNCGYOWNERSTATUS;      // 同步货主状态(GY)
+    private String FRegNumber;              // 注册编码
+    private IdObject FGROUPSUPPLYID;        // 对应集团供应商
+    private String FISGROUP;                // 集团供应商
+    private String F_UNW_yida;              // 宜搭审批连接
+
+    public SupplierEntity() {}
+
+    // 基本信息
+    private FBaseInfo FBaseInfo;
+
+    // 商务信息
+    private FBusinessInfo FBusinessInfo;
+
+    // 财务信息
+    private FFinanceInfo FFinanceInfo;
+
+    // 银行信息
+    private List<FBankInfo> FBankInfo;
+
+    // 组织信息
+    private List<FLocationInfo> FLocationInfo;
+
+    // 联系人
+    private List<FSupplierContact> FSupplierContact;
+
+    /**
+     * 基本信息
+     */
+    @Data
+    public static class FBaseInfo {
+        private Integer FEntryId;                 // 实体主键
+        private IdObject FCountry;                // 国家
+        private IdObject FProvincial;             // 地区
+        private String FAddress;                  // 通讯地址
+        private String FZip;                      // 邮政编码
+        private IdObject FLanguage;               // 语言
+        private String FWebSite;                  // 公司网址
+        private IdObject FTrade;                  // 行业
+        @Alias("dateField_mma6vp7w")
+        private String FFoundDate;                // 创立日期
+        @Alias("textField_mma6vp7v")
+        private String FLegalPerson;              // 法人代表
+        @Alias("numberField_mma6vp83")
+        private Integer FRegisterFund;            // 注册资金(万元)
+        private String FRegisterCode;             // 工商登记号
+        @Alias("textField_mma6vp85")
+        private String FSOCIALCRECODE;            // 统一社会信用代码
+        private String FTendPermit;               // 生产经营许可证
+        @Alias("textField_mma6vp7p")
+        private String FRegisterAddress;          // 注册地址
+        private IdObject FDeptId;                 // 负责部门
+        private IdObject FStaffId;                // 负责人
+        private IdObject FSupplierClassify;       // 供应商分类
+        private String FSupplyClassify;           // 供应类别
+        private IdObject FSupplierGrade;          // 供应商等级
+        private IdObject FCompanyClassify;        // 公司类别
+        private IdObject FCompanyNature;          // 公司性质
+        private IdObject FCompanyScale;           // 公司规模
+        private String FStartDate;                // 生效日期
+        private String FEndDate;                  // 失效日期
+    }
+    
+    /**
+     * 商务信息
+     */
+    @Data
+    public static class FBusinessInfo {
+        private Integer FEntryId;                 // 实体主键
+        private IdObject FPurchaserGroupId;       // 采购组
+        private Integer FMinPOValue;              // 最小订单量
+        private String FNeedConfirm;              // 需要确认
+        private IdObject FParentSupplierId;       // 汇总公司
+        private String FBusinessStatus;           // 业务状态
+        private String FFreezeLimit;              // 冻结范围
+        private IdObject FSettleTypeId;           // 结算方式
+        private IdObject FPRICELISTID;            // 默认价目表
+        private Object FWipStockPlaceId;          // 默认WIP仓位
+        private IdObject FWipStockId;             // 默认WIP仓库
+        private IdObject FDiscountListId;         // 默认折扣表
+        private IdObject FProviderId;             // 供货方
+        private IdObject FFreezeOperator;         // 冻结人
+        private String FFreezeDate;               // 冻结日期
+        private IdObject FVmiStockId;             // VMI仓库
+        private String FVmiBusiness;              // VMI业务
+        private String FEnableSL;                 // 启用供应商协同
+        private Integer FDepositRatio;            // 保证金比例%
+        private String FDefaultContactId;         // 默认联系人
+    }
+    
+    /**
+     * 财务信息
+     */
+    @Data
+    public static class FFinanceInfo {
+        private Integer FEntryId;                 // 实体主键
+        private IdObject FPayCurrencyId;          // 结算币别(必填项)
+        private IdObject FCustomerId;             // 对应客户
+        private Integer FPayAdvanceAmount;        // 单次预付额度
+        @Alias("textField_mma6vp85")
+        private String FTaxRegisterCode;          // 税务登记号
+        private String FTendType;                 // 经营类型
+        private IdObject FTaxType;                // 税分类
+        private String FFinanceDesc;              // 描述
+        private IdObject FPayCondition;           // 付款条件
+        private String FInvoiceType;              // 发票类型
+        private IdObject FSettleId;               // 结算方
+        private IdObject FChargeId;               // 收款方
+        private IdObject FTaxRateId;              // 默认税率
+    }
+    
+    /**
+     * 银行信息
+     */
+    @Data
+    public static class FBankInfo {
+        private Integer FBankId;                  // 实体主键
+        private IdObject FBankCountry;            // 国家
+        @Alias("textField_mma72kwy")
+        private String FBankCode;                 // 银行账号
+        @Alias("textField_mogukmd1")
+        private String FBankHolder;               // 账户名称
+        private String FBankIsDefault;            // 默认
+        private String FBankDesc;                 // 描述
+        private IdObject FBankCurrencyId;         // 币别
+        @Alias("textField_mma72kwx")
+        private String FOpenBankName;             // 开户银行
+        private IdObject FBankTypeRec;            // 收款银行
+        private String FOpenAddressRec;           // 开户行地址
+        private String FCNAPS;                    // 联行号
+        private String FSwiftCode;                // SwiftCode
+        private String FTextBankDetail;           // 网点名称
+        private IdObject FBankDetail;             // 银行网点
+    }
+    
+    /**
+     * 组织信息(地点信息)
+     */
+    @Data
+    public static class FLocationInfo {
+        private Integer FLocationId;              // 实体主键
+        private Integer FTransportDays;           // 运输时间
+        private Integer FPlanDeliveryPeriod;      // 计划交货周期
+        private String FLocDesc;                  // 备注
+        private String FLocNumber;                // 地点编码
+        private String FLocName;                  // 地点名称(必填项)
+        private String FLocAddress;               // 通讯地址(必填项)
+        private String FLocIsUsed;                // 启用
+        private String FLocTel;                   // 电话
+        private String FLocMobile;                // 手机(必填项)
+        private String FLocFax;                   // 传真
+        private String FLocEMail;                 // 电子邮箱
+        private String FIsDefaultSupply;          // 默认供货地址
+        private String FIsDefaultSettle;          // 默认开票地址
+        private String FIsDefaultPayee;           // 默认收款地址
+        private String FLocContact;               // 联系人(旧)
+        private IdObject FLocNewContact;          // 联系人(必填项)
+    }
+    
+    /**
+     * 联系人信息
+     */
+    @Data
+    public static class FSupplierContact {
+        private Integer FContactId;               // 实体主键
+        @Alias("textField_mma72kx2")
+        private String FContact;                  // 联系人
+        private String FPost;                     // 职务
+        @Alias("textField_mma72kx3")
+        private String FTel;                      // 电话
+        private String FMobile;                   // 手机
+        private String FFax;                      // 传真
+        private String FEMail;                    // 电子邮箱
+        private String FIMCode;                   // 即时通讯
+        private String FContactIsDefault;         // 默认联系人
+        private String FContactDescription;       // 备注
+        private String FCommonContactId;          // 供应商联系人
+        private String FContactNumber;            // 编码
+        private String FConForbidStatus;          // 禁用状态
+        private String FGender;                   // 性别
+    }
+}

+ 54 - 0
mjava-heshu/src/main/java/com/malk/heshu/schedule/XiDingTask.java

@@ -0,0 +1,54 @@
+package com.malk.heshu.schedule;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.kingdee.bos.webapi.entity.IdentifyInfo;
+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.heshu.config.KDWebApiConf;
+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;
+
+import java.util.*;
+
+/**
+ * @EnableScheduling 开启定时任务 [配置参考McScheduleTask]
+ */
+@Slf4j
+@Configuration
+@EnableScheduling
+@ConditionalOnProperty(name = {"enable.scheduling"})
+public class XiDingTask {
+
+    @Autowired
+    private KDWebApiConf kdWebApiConf;
+
+    @Autowired
+    private YDClient ydClient;
+    @Autowired
+    private YDConf ydConf;
+
+    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;
+    }
+
+}

+ 45 - 0
mjava-heshu/src/main/resources/application-dev.yml

@@ -0,0 +1,45 @@
+server:
+  port: 9000
+  servlet:
+    context-path: /api/heshu
+
+enable:
+  scheduling: true
+logging:
+  config: classpath:logback-spring.xml
+  path: /home/server/heshu/logs/
+  level:
+    com.malk.*: info
+
+# dingtalk
+dingtalk:
+  agentId: 4424860263
+  appKey: dingwrnq1nh8hoqvtqsr
+  appSecret: EUN7g-sskl5HmUPUhzWxoauTnjGJIHeLs-5W6SkcsH2W_fqGX2O0Hv94mNnVirgf
+  corpId: dingfafe4e9b1128aad035c2f4657eb6378f
+
+# aliwork
+aliwork:
+  appType: APP_QM42OEGLMNNGBLIJELJI
+  systemToken: ZDD66AA1PPG4HEBKPH0TSCZX72QX3O4ZGWFNMZKO
+
+kingdee:
+  # 第三方系统登录授权的账套ID
+  X-KDApi-AcctID: 69b7650beaa43d
+  # 第三方系统登录授权的用户
+  X-KDApi-UserName: Administrator
+  # 第三方系统登录授权的应用ID
+  X-KDApi-AppID: 339218_S41q6zHu4mrb7YWI53TB0a9I1r4Y1rKL
+  # 第三方系统登录授权的应用密钥
+  X-KDApi-AppSec: fae9e4a1820f4e7c839eafebdfa0e4e5
+  # 服务Url地址(公有云统一走网关sdk底层已处理,无需传X-KDApi-ServerUrl,下面这行需要注释)
+  X-KDApi-ServerUrl: http://124.70.8.12/k3cloud/
+  # 账套语系,默认2052
+  # X-KDApi-LCID: 2052
+  # 组织编码,启用多组织时配置对应的组织编码才有效
+  # X-KDApi-OrgNum: 100
+  # 允许的最大连接延时,单位为秒
+  # X-KDApi-ConnectTimeout: 120
+  # 允许的最大读取延时,单位为秒
+  # X-KDApi-RequestTimeout: 120
+

+ 45 - 0
mjava-heshu/src/main/resources/application-prod.yml

@@ -0,0 +1,45 @@
+server:
+  port: 9000
+  servlet:
+    context-path: /api/heshu
+
+enable:
+  scheduling: true
+logging:
+  config: classpath:logback-spring.xml
+  path: /home/server/heshu/logs/
+  level:
+    com.malk.*: info
+
+# dingtalk
+dingtalk:
+  agentId: 4424860263
+  appKey: dingwrnq1nh8hoqvtqsr
+  appSecret: EUN7g-sskl5HmUPUhzWxoauTnjGJIHeLs-5W6SkcsH2W_fqGX2O0Hv94mNnVirgf
+  corpId: dingfafe4e9b1128aad035c2f4657eb6378f
+
+# aliwork
+aliwork:
+  appType: APP_QM42OEGLMNNGBLIJELJI
+  systemToken: ZDD66AA1PPG4HEBKPH0TSCZX72QX3O4ZGWFNMZKO
+
+kingdee:
+  # 第三方系统登录授权的账套ID
+  X-KDApi-AcctID: 6675a1bf6428ea
+  # 第三方系统登录授权的用户
+  X-KDApi-UserName: Administrator
+  # 第三方系统登录授权的应用ID
+  X-KDApi-AppID: 341950_01aJ5cupVqgaS+Ss6eWoT9WJ5L1W2plp
+  # 第三方系统登录授权的应用密钥
+  X-KDApi-AppSec: 98d2869acbe8499c9c57d20a9ca6807a
+  # 服务Url地址(公有云统一走网关sdk底层已处理,无需传X-KDApi-ServerUrl,下面这行需要注释)
+  X-KDApi-ServerUrl: http://124.70.8.12/k3cloud/
+  # 账套语系,默认2052
+  # X-KDApi-LCID: 2052
+  # 组织编码,启用多组织时配置对应的组织编码才有效
+  # X-KDApi-OrgNum: 100
+  # 允许的最大连接延时,单位为秒
+  # X-KDApi-ConnectTimeout: 120
+  # 允许的最大读取延时,单位为秒
+  # X-KDApi-RequestTimeout: 120
+

+ 15 - 0
mjava-heshu/src/main/resources/application.yml

@@ -0,0 +1,15 @@
+spring:
+  profiles:
+    active: prod
+  servlet:
+    multipart:
+      max-file-size: 100MB
+      max-request-size: 100MB
+  http:
+    enabled: false
+
+#  configuration:
+#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+  global-config:
+    db-config:
+      id-type: auto

+ 61 - 0
mjava-heshu/src/main/resources/logback-spring.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false" scan="false" scanPeriod="60 seconds">
+    <springProperty scope="context" name="LOG_HOME" source="logging.path" defaultValue="d:\\jianhui_cloudpure\logs\"/>
+    <property name="FileNamePattern" value="${LOG_HOME}%d{yyyyMM}/%d{dd}"/>
+
+    <!-- 定义控制台输出 -->
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - [%thread] - %-5level - %logger{50} - %msg%n</pattern>
+        </layout>
+    </appender>
+
+    <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 指定日志文件的名称 -->
+        <!--<file>${FileNamePattern}/info.log</file>-->
+
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${FileNamePattern}/info-%i.log</fileNamePattern>
+            <MaxHistory>30</MaxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <MaxFileSize>30MB</MaxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
+        </layout>
+    </appender>
+
+    <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
+        <discriminator>
+            <Key>processid</Key>
+            <DefaultValue>sys</DefaultValue>
+        </discriminator>
+        <sift>
+            <appender name="FILE-${processid}"
+                      class="ch.qos.logback.core.rolling.RollingFileAppender">
+                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+                    <FileNamePattern>
+                        ${FileNamePattern}/${processid}.log
+                    </FileNamePattern>
+                </rollingPolicy>
+                <layout class="ch.qos.logback.classic.PatternLayout">
+                    <Pattern>
+                        %d{yyyyMMdd:HH:mm:ss.SSS} [%thread] %-5level %msg%n
+                    </Pattern>
+                </layout>
+            </appender>
+        </sift>
+    </appender>
+
+
+    <!-- 日志输出级别 -->
+    <logger name="org.springframework" level="debug"  additivity="false"/>
+    <logger name="com.malk.connecter" level="debug"/>
+    <root level="INFO">
+        <appender-ref ref="stdout"/>
+        <appender-ref ref="appLogAppender"/>
+        <appender-ref ref="SIFT"/>
+    </root>
+</configuration>

+ 321 - 0
mjava-heshu/src/test/java/com/malk/heshu/JdTest.java

@@ -0,0 +1,321 @@
+package com.malk.heshu;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+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.aliwork.YDSearch;
+import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
+import com.malk.utils.PublicUtil;
+import com.malk.utils.UtilMap;
+import com.malk.heshu.config.KDWebApiConf;
+import com.malk.heshu.entity.*;
+import lombok.extern.slf4j.Slf4j;
+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;
+
+import java.util.*;
+
+@Slf4j
+@SpringBootTest
+@RunWith(SpringRunner.class)
+public class JdTest {
+
+    @Autowired
+    private KDWebApiConf kdWebApiConf;
+
+    @Autowired
+    private YDClient ydClient;
+    @Autowired
+    private YDConf ydConf;
+
+    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;
+    }
+
+    @Test
+    public void saveCust() throws Exception {
+        JSONObject params=new JSONObject();
+        params.put("fid","f27295d0-7eec-4210-aca0-77d83fc1331e");
+        params.put("key","textField_mnhav84y");
+        try {
+            Map formData= (Map) ydClient.queryData(YDParam.builder().formInstId(params.getString("fid")).build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+            if(formData==null){
+                return ;
+            }
+            formData.put("textField_mma6vp851",formData.get("textField_mma6vp85"));
+            CustomerInfo customerInfo = BeanUtil.toBean(formData, CustomerInfo.class);
+            List<Map> list=UtilMap.getList(formData,"tableField_mma72l0q");
+            List<CustomerInfo.CustBank> bkList=new ArrayList<>();
+            for(Map map:list){
+                CustomerInfo.CustBank  fBankInfo = BeanUtil.toBean(map, CustomerInfo.CustBank.class);
+                bkList.add(fBankInfo);
+            }
+            customerInfo.setFT_BD_CUSTBANK(bkList);
+            List<Map> list2=UtilMap.getList(formData,"tableField_mma72kx1");
+            List<ContactInfo> lxrList=new ArrayList<>();
+            for(Map map:list2){
+                ContactInfo contactInfo=new ContactInfo();
+                contactInfo.setFName(UtilMap.getString(map,"textField_mma72kx2"));
+                contactInfo.setFMobile(UtilMap.getString(map,"textField_mma72kx3"));
+                contactInfo.setFCompanyType("BD_Customer");
+                contactInfo.setFBizLocation(UtilMap.getString(map,"textField_mogukmdi"));
+                contactInfo.setFBizAddress(UtilMap.getString(map,"textField_mogukmdi"));
+                lxrList.add(contactInfo);
+            }
+            customerInfo.setFSALDEPTID(new FNumber(UtilMap.getString(formData,"textField_mogukmdd")));// 业务部门
+            String custTypeValue=UtilMap.getString(formData,"radioField_mma72kxi");
+            String custType;
+            if(custTypeValue.equals("贸易商")){
+                custType="02";
+            }else if(custTypeValue.equals("工厂")){
+                custType="01";
+            }else {
+                custType="05";
+            }
+            customerInfo.setFGroup(new FNumber(custType));
+            String operator=UtilMap.getString(formData,"radioField_mma72l0t");// 操作类型 客商准入  客商更新
+//            if(operator.equals("客商更新")){
+//                String fId=UtilMap.getString(formData,"textField_moi1ejl1");
+//                if(!PublicUtil.isNull(fId)){
+//                    // 反审核
+//                    unAudit("BD_Customer",fId);
+//                    customerInfo.setFCUSTID(Integer.parseInt(fId));
+//                }
+//            }
+//            McR mcr=saveToAudit("BD_Customer",customerInfo,params.getString("fid"),params.getString("key"),"selectField_mogukmd8","textareaField_mogukmda","textField_moi1ejl1",lxrList);
+            System.out.println(JSONObject.toJSONString(customerInfo));
+        }catch (Exception e){
+        }
+    }
+
+    @Test
+    public void saveSupplier() throws Exception {
+        Map formData= (Map) ydClient.queryData(YDParam.builder().formInstId("a4fba63b-586c-43ee-9d34-daaeee2b19f1").build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+        System.out.println(formData);
+        SupplierEntity supplierEntity = BeanUtil.toBean(formData, SupplierEntity.class);
+        SupplierEntity.FBaseInfo fBaseInfo = BeanUtil.toBean(formData, SupplierEntity.FBaseInfo.class);
+        List<Map> list=UtilMap.getList(formData,"tableField_mma72l0q");
+        List<SupplierEntity.FBankInfo> bkList=new ArrayList<>();
+        for(Map map:list){
+            SupplierEntity.FBankInfo  fBankInfo = BeanUtil.toBean(map, SupplierEntity.FBankInfo.class);
+            bkList.add(fBankInfo);
+        }
+        supplierEntity.setFBaseInfo(fBaseInfo);
+        supplierEntity.setFBankInfo(bkList);
+        List<Map> list2=UtilMap.getList(formData,"tableField_mma72kx1");
+        List<SupplierEntity.FSupplierContact> lxrList=new ArrayList<>();
+        for(Map map:list2){
+            SupplierEntity.FSupplierContact  lxrInfo = BeanUtil.toBean(map, SupplierEntity.FSupplierContact.class);
+            lxrList.add(lxrInfo);
+        }
+        supplierEntity.setFSupplierContact(lxrList);
+        System.out.println(supplierEntity);
+//        System.out.println(saveToAudit("BD_Supplier",supplierEntity));
+    }
+
+    private McR saveToAudit(String formid, Object object,String fid,String codeKey,String statusKey,String msgKey,String idKey,List<ContactInfo> lxrList) 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);
+        JSONObject reObj = JSONObject.parseObject(result,JSONObject.class);
+        if (sRet.isSuccessfully()) {
+            if(!PublicUtil.isNull(codeKey)){
+                // 回写信息
+                Map updateMap=UtilMap.map(codeKey,reObj.getJSONObject("Result").getString("Number"));
+                updateMap.put(statusKey,"成功");
+                updateMap.put(idKey,reObj.getJSONObject("Result").getString("Id"));// ID 内码
+                ydClient.operateData(YDParam.builder().formInstId(fid).updateFormDataJson(
+                        JSONObject.toJSONString(updateMap)
+                ).build(), YDConf.FORM_OPERATION.update);
+            }
+            if(lxrList!=null){
+                for (ContactInfo contactInfo : lxrList) {
+                    contactInfo.setFCompany(new FNumber(reObj.getJSONObject("Result").getString("Number")));
+                    String data=new Gson().toJson(contactInfo);
+                    String id=saveToAudit("BD_CommonContact",new Gson().fromJson(data,Object.class));
+                }
+            }
+            JsonObject jsonData = new JsonObject();
+            jsonData.addProperty("Ids", sRet.getResult().getId());
+            String result2=client.submit(formid, jsonData.toString());
+            resultObj.put("submit",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());
+                resultObj.put("audit",result3);
+                RepoRet repoRet3 = gson.fromJson(result3, RepoRet.class);
+                if (repoRet3.getResult().getResponseStatus().isIsSuccess()) {
+                    log.info("审批通过,新增完成");
+                    return McR.success(resultObj);
+//                    Map map=UtilMap.map("PkIds, TOrgIds",sRet.getResult().getId(),"1,105818,105822,127834,127835,127838,127843,127846,127847,127848,127850,127862,1370321,1325841,1327202,1646858");
+//                    String result4=client.allocate("formid",JSONObject.toJSONString(map));
+//                    resultObj.put("allocate",result4);
+//                    RepoRet repoRet4 = gson.fromJson(result4, RepoRet.class);
+//                    if (repoRet4.getResult().getResponseStatus().isIsSuccess()) {
+//                        log.info("分配完成");
+//                        return McR.success(resultObj);
+//                    }
+                }
+            }
+        }else {
+            log.info("保存失败:{}",result);
+            Map updateMap=UtilMap.map(statusKey,"失败");
+            updateMap.put(msgKey,result);
+            ydClient.operateData(YDParam.builder().formInstId(fid).updateFormDataJson(
+                    JSONObject.toJSONString(updateMap)
+            ).build(), YDConf.FORM_OPERATION.update);
+        }
+        return McR.error("203",JSONObject.toJSONString(resultObj));
+    }
+
+    private void unAudit(String formid,String fNumber) throws Exception {
+        K3CloudApi client = new K3CloudApi(initIden());
+        Gson gson = new Gson();
+        JsonObject jsonData = new JsonObject();
+        jsonData.addProperty("Ids", fNumber);
+        String result=client.unAudit(formid, jsonData.toString());
+        RepoRet sRet2 = gson.fromJson(result, RepoRet.class);
+        if (!sRet2.isSuccessfully()) {
+            log.info("反审核失败:{}",result);
+        }
+    }
+
+    @Test
+    public void queryOrder(){
+        K3CloudApi client = new K3CloudApi(initIden());
+        try {
+            int startRow = 0;
+            int limit = 2000;
+            BillQuery billQuery = new BillQuery();
+            billQuery.setFormId("AR_RECEIVEBILL");
+            billQuery.setFieldKeys("FPAYUNIT.FName,FREALRECAMOUNTFOR,FDATE,FSETTLETYPEID,FSETTLETYPEID.FName,F_ABC_Base1,FRECACCOUNTNAME,FACCOUNTID.FNumber,FACCOUNTID.FName,FSALEERID.FName,F_ABC_Base,F_ABC_BaseProperty,FBPBILLNUMBER,FBPBILLPARAMOUNT,FBPBILLTYPE,FEXPIRY");
+//            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","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);
+            billQuery.setLimit(limit);
+            billQuery.setStartRow(startRow);
+            String result=client.billQuery(JSONObject.toJSONString(billQuery));
+            System.out.println(result);
+//            JSONArray jsonArray = JSONArray.parseArray(result);
+//            for(int i=0;i<jsonArray.size();i++){
+//                JSONObject jsonObject = jsonArray.getJSONObject(i);
+//                System.out.println(jsonObject);
+//                Receivebill rb= BeanUtil.toBean(jsonObject, Receivebill.class);
+//                if(!PublicUtil.isNull(rb.getAssociationFormField_lypey1wr())){
+//                    List<Map> data=(List<Map>) ydClient.queryData(YDParam.builder().formUuid("FORM-8E4AA59DFB354F2D922826F47F70B31AZ8ES")
+//                            .searchCondition(JSONObject.toJSONString(Arrays.asList(YDConf.searchCondition_TextFiled("textField_lx05suvl",rb.getAssociationFormField_lypey1wr(),"eq"))))
+//                            .build(), YDConf.FORM_QUERY.retrieve_list).getData();
+//                    if(data.size()>0){
+//                        System.out.println(data.get(0).get("formInstanceId"));
+//                        List<Map> kh=ydConf.associationForm("FORM-8E4AA59DFB354F2D922826F47F70B31AZ8ES", String.valueOf(data.get(0).get("formInstanceId")),rb.getAssociationFormField_lypey1wr(),"",false);
+//                        rb.setAssociationFormField_lypey1wr(JSONObject.toJSONString(kh));
+//                    }else{
+//                        rb.setAssociationFormField_lypey1wr("[]");
+//                    }
+//                }
+//                Map prodata=new HashMap();
+//                if(!PublicUtil.isNull(rb.getAssociationFormField_lsvmld22())){
+//                    List<Map> data=(List<Map>) ydClient.queryData(YDParam.builder().formUuid("FORM-2E06211370FA43D3AEAAC0CF7636365491YX")
+//                            .searchCondition(JSONObject.toJSONString(Arrays.asList(YDConf.searchCondition_TextFiled("textField_m0c4utr2",rb.getAssociationFormField_lsvmld22(),"eq"))))
+//                            .build(), YDConf.FORM_QUERY.retrieve_list).getData();
+//                    if(data.size()>0){
+//                        System.out.println(data.get(0).get("formInstanceId"));
+//                        Map formData= UtilMap.getMap(data.get(0),"formData");
+//                        List<Map> kh=ydConf.associationForm("FORM-2E06211370FA43D3AEAAC0CF7636365491YX", String.valueOf(data.get(0).get("formInstanceId")),UtilMap.getString(formData,"textField_m50ci9rk"),"",false);
+//                        rb.setAssociationFormField_lsvmld22(JSONObject.toJSONString(kh));
+//                        prodata.put("textField_lwgba84b",formData.get("textField_m0namazl"));
+//                        prodata.put("textField_lxvrmu61",formData.get("textField_m0namazj"));
+//                        prodata.put("textField_lypey1wx",formData.get("textField_m0c4utr2"));
+//                        prodata.put("textField_m1aft8ye",formData.get("textField_m6yurmat"));
+//                        prodata.put("numberField_lxu21h6c",formData.get("numberField_mdcwz9mr"));
+//                        prodata.put("numberField_lxu29mvg",formData.get("numberField_mdcwz9mv"));
+//                        prodata.put("numberField_lxu336sn",formData.get("numberField_m0gb97py"));
+//                    }else{
+//                        rb.setAssociationFormField_lsvmld22("[]");
+//                    }
+//                }
+//                prodata.putAll(JSONObject.parseObject(JSONObject.toJSONString(rb.toYiDa())));
+//                ydClient.operateData(YDParam.builder().formUuid("FORM-9BDAFB39320246EFACC176C9E33E51DC4N40")
+//                        .formDataJson(JSONObject.toJSONString(prodata)).build(), YDConf.FORM_OPERATION.start);
+//            }
+
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    @Test
+    public void update(){
+//        unAudit("BD_Customer","");
+    }
+
+    @Test
+    public void queryOrder2(){
+        ContactInfo contactInfo=new ContactInfo();
+        contactInfo.setFName("张三");
+        contactInfo.setFMobile("17700001111");
+        contactInfo.setFCompanyType("BD_Customer");
+        contactInfo.setFCompany(new FNumber("CUST5127"));
+        contactInfo.setFBizLocation("测试地址");
+        contactInfo.setFBizAddress("测试地址");
+        try {
+            String data=new Gson().toJson(contactInfo);
+            System.out.println(data);
+            JSONObject jsonObject=JSONObject.parseObject(data);
+            System.out.println(jsonObject);
+            String id=saveToAudit("BD_CommonContact",new Gson().fromJson(data,Object.class));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    private String saveToAudit(String formid, Object object) throws Exception {
+        K3CloudApi client = new K3CloudApi(initIden());
+        String result=client.save(formid,JSONObject.toJSONString(UtilMap.map("Model",object)));
+        System.out.println(result);
+        Gson gson = new Gson();
+        RepoRet sRet = gson.fromJson(result, RepoRet.class);
+        JSONObject reObj = JSONObject.parseObject(result,JSONObject.class);
+        if (sRet.isSuccessfully()) {
+            return reObj.getJSONObject("Result").getString("Id");
+        }else {
+            return "";
+        }
+    }
+
+
+
+
+
+}

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

@@ -212,6 +212,7 @@ public class KdYdOrderServiceImpl extends ServiceImpl<KdYdOrderMapper, KdYdOrder
                     String bz1 = safeGetString(item, "textareaField_mjryuaok");
                     int sl = parseInt(safeGetString(item, "numberField_mfbx1prb"), 0);
                     BigDecimal zse = toBigDecimal(safeGetString(item, "numberField_mfbx1prh"));
+                    BigDecimal bbh = toBigDecimal(safeGetString(item, "numberField_mowq936x"));
                     BigDecimal zje = toBigDecimal(safeGetString(item, "numberField_mfbx1pri"));
                     BigDecimal zjshj = toBigDecimal(safeGetString(item, "numberField_mfbx1prj"));
                     BigDecimal jj = toBigDecimal(safeGetString(item, "numberField_mfbx1prk"));
@@ -236,6 +237,7 @@ public class KdYdOrderServiceImpl extends ServiceImpl<KdYdOrderMapper, KdYdOrder
                     table1Map.put("bz", bz1);
                     table1Map.put("sl", sl);
                     table1Map.put("se1", zse);
+                    table1Map.put("bbh", bbh);
                     table1Map.put("je1", zje);
                     table1Map.put("jshj1", zjshj);
                     table1Map.put("jj", jj);

+ 1 - 1
mjava-huagao/src/test/java/com/malk/huagao/EqbTest.java

@@ -132,7 +132,7 @@ public class EqbTest {
 //            reqBodyObj.put("convertToPDF", "true");
             reqBodyObj.put("convertToHTML", true);
             reqBodyObj.put("fileName", "其他客户销售合同.docx");
-            reqBodyObj.put("fileSize", "28246 ");
+            reqBodyObj.put("fileSize", "28246");
             //reqBodyObj.put("convertToHTML", "false");
 
             // 请求Body体数据

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

@@ -62,4 +62,12 @@ public class JinlunTask {
         jinlunTaskService.syncSaleOrder();
     }
 
+    //定时同步应收收款核销记录
+    @Scheduled(cron = "0 7 0 * * ?")
+    public void syncReceiptVerification(){
+        jinlunTaskService.syncReceiptVerification();
+    }
+
+
+
 }

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

@@ -15,4 +15,7 @@ public interface JinlunTaskService {
 
     void syncSaleOrder();
 
+    //应收收款核销记录
+    void syncReceiptVerification();
+
 }

+ 153 - 14
mjava-jinlun/src/main/java/com/malk/jinlun/service/impl/JinlunTaskServiceImpl.java

@@ -9,13 +9,11 @@ import com.malk.jinlun.service.CpClient;
 import com.malk.jinlun.service.JinlunTaskService;
 import com.malk.utils.UtilMap;
 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.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 @Slf4j
 @Service
@@ -254,7 +252,7 @@ public class JinlunTaskServiceImpl implements JinlunTaskService {
                 Map map1 = UtilMap.getMap(content, "data");
                 List<Map> list1 = UtilMap.getList(map1, "Sheet1760153734916");
 
-                for (int i = 0; i < items.size(); i++) {
+                for (int i = 0; i < list1.size(); i++) {
                     items.get(i).put("rowStatus", "Modified");
                     items.get(i).put("id", (UtilMap.getString(list1.get(i),"id")));//子表实例id
                 }
@@ -393,7 +391,7 @@ public class JinlunTaskServiceImpl implements JinlunTaskService {
                 Map map1 = UtilMap.getMap(content, "data");
                 List<Map> list1 = UtilMap.getList(map1, "Sheet1760585205663");
 
-                for (int i = 0; i < items.size(); i++) {
+                for (int i = 0; i < list1.size(); i++) {
                     items.get(i).put("rowStatus", "Modified");
                     items.get(i).put("id", (UtilMap.getString(list1.get(i),"id")));//子表实例id
                 }
@@ -789,7 +787,7 @@ public class JinlunTaskServiceImpl implements JinlunTaskService {
 
         //审核日期为昨天至今天
         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","FBillNo","67","S304-260410001","","","0"));//单据编号等于XX
+//        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FBillNo","67","S305-251031001","","","0"));//单据编号等于XX
 
         billQuery.setFilterString(filterString);
         billQuery.setLimit(limit);
@@ -848,7 +846,7 @@ public class JinlunTaskServiceImpl implements JinlunTaskService {
 //            data.put("",UtilMap.getString(saleOut,""));//客户
             data.put("ShortText1775637878744",UtilMap.getString(saleOut,"FCustId.FName"));//客户名称
             data.put("Text1775637885319",UtilMap.getString(saleOut,"FCustId.FNumber"));//客户编号
-            data.put("StaffSingle1775629353797",UtilMap.getString(saleOut, "FSalerId.FName"));//销售员
+            data.put("ShortText1776926946903",UtilMap.getString(saleOut, "FSalerId.FName"));//销售员
             String fWgrComboRe5 = UtilMap.getString(saleOut, "F_WGR_Combo_re5");
             String fWgrComboRe5Value = "";
             switch (fWgrComboRe5){
@@ -859,7 +857,7 @@ public class JinlunTaskServiceImpl implements JinlunTaskService {
             }
             data.put("Dropdown1775629436727",fWgrComboRe5Value);//订单要求
             data.put("Date1775629061650",UtilMap.getString(saleOut, "FDate").split("\\.")[0].replace("T"," "));//日期
-            data.put("StaffSelector1775629377100",UtilMap.getString(saleOut, "F_Sl_gendanyuan.FName"));//跟单员
+            data.put("ShortText1776926951569",UtilMap.getString(saleOut, "F_Sl_gendanyuan.FName"));//跟单员
 
 
 
@@ -920,7 +918,7 @@ public class JinlunTaskServiceImpl implements JinlunTaskService {
         //处理特殊字段格式
         for (Map<String, Object> stringObjectMap : list) {
             //成员
-            String salerName = UtilMap.getString(stringObjectMap,"StaffSingle1775629353797");
+            String salerName = UtilMap.getString(stringObjectMap,"ShortText1776926946903");
             if(cpUserMap.containsKey(salerName)){
                 Map cpUserInfo = cpUserMap.get(salerName);
                 stringObjectMap.put("StaffSingle1775629353797",cpUserInfo);//销售员
@@ -936,10 +934,10 @@ public class JinlunTaskServiceImpl implements JinlunTaskService {
                 }
             }
 
-            String gendanName = UtilMap.getString(stringObjectMap, "StaffSelector1775629377100");
+            String gendanName = UtilMap.getString(stringObjectMap, "ShortText1776926951569");
             if(cpUserMap.containsKey(gendanName)){
-                Map cpUserInfo = cpUserMap.get(gendanName);
-                stringObjectMap.put("StaffSingle1775629353797",cpUserInfo);//跟单员
+                Map cpUserInfo = new HashMap(cpUserMap.get(gendanName));
+                stringObjectMap.put("StaffSelector1775629377100",cpUserInfo);//跟单员
             }else {
                 List<Map> cpUserInfoList = cpClient.getCpUserInfo(null, null, null, null, gendanName, 0, 1);
                 if (cpUserInfoList.size() == 1){
@@ -992,7 +990,7 @@ public class JinlunTaskServiceImpl implements JinlunTaskService {
                 List<Map> list1 = UtilMap.getList(map1, "Sheet1775629877034");
 
                 if (!list1.isEmpty()){
-                    for (int i = 0; i < items.size(); i++) {
+                    for (int i = 0; i < list1.size(); i++) {
                         items.get(i).put("rowStatus", "Modified");
                         items.get(i).put("id", (UtilMap.getString(list1.get(i),"id")));//子表实例id
                     }
@@ -1013,6 +1011,147 @@ public class JinlunTaskServiceImpl implements JinlunTaskService {
         }
     }
 
+    @Override
+    public void syncReceiptVerification() {
+        log.info("开始同步应收收款核销明细");
+        K3CloudApi client = new K3CloudApi(initIden());
+
+        List<Map> result = new ArrayList<>();
+        List<Map> list = new ArrayList<>();
+
+        int startRow = 0;
+        int limit = 2000;
+
+        BillQuery billQuery = new BillQuery();
+        billQuery.setFormId("AR_MatchRecord");
+        billQuery.setFieldKeys("FBILLNO,FCURWRITTENOFFAMOUNTFOR,FCURWRITTENOFFAMOUNT,FCURRENCYID.FName,FSOURCETYPE.FName,FSRCBILLNO,FVERIFYDATE,FCONTACTUNITTYPE,FCONTACTUNIT.FNumber,FCONTACTUNIT.FName,FBILLNUMBER");
+        List<Map> filterString = new ArrayList<>();
+
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FVERIFYDATE","265",1,"","","0"));//核销日期在今天之前N天以后
+//        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FVERIFYDATE","39","2026-01-01 00:00:00","","","0"));//核销日期>=XX
+//        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FVERIFYDATE","16","2026-03-31 00:00:00","","","0"));//核销日期<=XX
+        filterString.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FCURWRITTENOFFAMOUNTFOR","21",0,"","","0"));//本次核销金额>0
+
+        billQuery.setFilterString(filterString);
+        billQuery.setLimit(limit);
+
+        do {
+            billQuery.setStartRow(startRow);
+            String s = null;
+
+            try {
+                s = client.billQuery(JSONObject.toJSONString(billQuery));
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+            result = (List<Map>)JSONObject.parse(s);
+            list.addAll(result);
+
+            startRow += limit;
+        }while (result.size() == limit);
+
+        System.out.println("1111");
+
+        for (Map map : list) {
+            Map body = new HashMap();
+            body.put("ShortText1776845631494",UtilMap.getString(map, "FBILLNO"));//核销单号
+            body.put("Number1776845666515",UtilMap.getDouble(map, "FCURWRITTENOFFAMOUNTFOR"));//本次核销金额
+            body.put("Number1776845698524",UtilMap.getDouble(map, "FCURWRITTENOFFAMOUNT"));//本次核销金额本位币
+            body.put("ShortText1776845718075",UtilMap.getString(map, "FCURRENCYID.FName"));//结算币别
+            body.put("ShortText1776845730884",UtilMap.getString(map, "FSOURCETYPE.FName"));//单据类型
+            String fsrcbillno = UtilMap.getString(map, "FSRCBILLNO");
+            body.put("ShortText1776845842726", fsrcbillno);//应收单编号
+            body.put("Date1776845858285",UtilMap.getString(map, "FVERIFYDATE").split("\\.")[0].replace("T"," "));//核销日期
+            String fcontactunittype = UtilMap.getString(map, "FCONTACTUNITTYPE");
+            String fcontactunittypeValue = "";
+            switch (fcontactunittype){
+                case "BD_Supplier":fcontactunittypeValue="供应商";break;
+                case "BD_Customer":fcontactunittypeValue="客户";break;
+                case "BD_Empinfo":fcontactunittypeValue="员工";break;
+                case "FIN_OTHERS":fcontactunittypeValue="其他往来单位";break;
+                default:break;
+            }
+            body.put("ShortText1776845885255",fcontactunittypeValue);//往来单位类型
+            body.put("ShortText1776845907662",UtilMap.getString(map, "FCONTACTUNIT.FNumber"));//往来单位编码
+            body.put("Text1776845928307",UtilMap.getString(map, "FCONTACTUNIT.FName"));//往来单位名称
+
+            String saleOrderNumber = UtilMap.getString(map, "FBILLNUMBER");//销售订单号
+
+            if (Strings.isBlank(saleOrderNumber)){
+                //查询应收单
+                BillQuery billQuery2 = new BillQuery();
+                billQuery2.setFormId("AR_receivable");
+                billQuery2.setFieldKeys("FBillNo,FSourceBillNo");
+                List<Map> filterString2 = new ArrayList<>();
+                filterString2.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FBillNo","17",fsrcbillno,"","","0"));//单据编号包含XX
+                billQuery2.setFilterString(filterString2);
+                billQuery2.setLimit(1);
+                billQuery2.setStartRow(0);
+
+                try {
+                    List<Map> ysdList = (List<Map>) JSONObject.parse(client.billQuery(JSONObject.toJSONString(billQuery2)));
+                    if (!ysdList.isEmpty()){
+                        Map ysd = ysdList.get(0);
+                        String fSourceBillNo = UtilMap.getString(ysd, "FSourceBillNo");//销售出库单单号
+
+                        if (Strings.isNotBlank(fSourceBillNo)){
+                            //查询销售出库单
+                            BillQuery billQuery3 = new BillQuery();
+                            billQuery3.setFormId("SAL_OUTSTOCK");
+                            billQuery3.setFieldKeys("FBillNo,FSrcBillNo");
+                            List<Map> filterString3 = new ArrayList<>();
+                            filterString3.add(UtilMap.map("FieldName, Compare, Value, Left, Right, Logic","FBillNo","17",fSourceBillNo,"","","0"));//单据编号包含XX
+                            billQuery3.setFilterString(filterString3);
+                            billQuery3.setLimit(1);
+                            billQuery3.setStartRow(0);
+
+                            List<Map> ckdList = (List<Map>) JSONObject.parse(client.billQuery(JSONObject.toJSONString(billQuery3)));
+                            if (!ckdList.isEmpty()){
+                                Map ckd = ckdList.get(0);
+
+                                saleOrderNumber = UtilMap.getString(ckd, "FSrcBillNo");//销售订单号
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            body.put("ShortText1776845949665",saleOrderNumber);
+
+            String schemaCode = "YSSKHXJL";
+
+            //查询是否存在
+            Map queryCondition = new HashMap();
+            queryCondition.put("op", "and");
+            queryCondition.put("items", Arrays.asList(
+                    UtilMap.map("queryFilterType, propertyCode, propertyValue", "Eq", "ShortText1776845631494", UtilMap.getString(body, "ShortText1776845631494")),
+                    UtilMap.map("queryFilterType, propertyCode, propertyValue", "Eq", "ShortText1776845842726", UtilMap.getString(body, "ShortText1776845842726"))));
+            Map result2 = cpClient.getCpBoList(schemaCode,queryCondition,null, 0, 1, null);
+
+            Map bizObjectPage = UtilMap.getMap(UtilMap.getMap(result2, "data"),"bizObjectPage");
+
+            int totalElements = UtilMap.getInt(bizObjectPage, "totalElements");
+
+            if (totalElements > 0) {
+                //更新
+                Map content = ((List<Map>) UtilMap.getList(bizObjectPage, "content")).get(0);
+
+                String bizObjectId = UtilMap.getString(content,"bizObjectId");//主表实例id
+
+                body.put("id",bizObjectId);
+
+                Map result3 = cpClient.updateCpBo(schemaCode, body,null);
+            }else {
+                //云枢新增销售出库单
+                Map result3 = cpClient.createCpBo(schemaCode, body,null);
+            }
+        }
+
+
+
+    }
+
     private IdentifyInfo initIden(){
         //注意 1:此处不再使用参数形式传入用户名及密码等敏感信息,改为在登录配置文件中设置。
         //注意 2:必须先配置第三方系统登录授权信息后,再进行业务操作,详情参考各语言版本SDK介绍中的登录配置文件说明。

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

@@ -76,6 +76,11 @@ public class DdTest {
         jinlunTaskService.syncSaleOrder();
     }
 
+    @Test
+    public void test17() {
+        jinlunTaskService.syncReceiptVerification();
+    }
+
     @Test
     public void test8() {
         try {

+ 153 - 0
mjava-qiwang/pom.xml

@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>mjava-qiwang</groupId>
+    <artifactId>mjava-qiwang</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>mjava-qiwang</name>
+    <description>mjava-qiwang</description>
+   <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+
+    </properties>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.7.18</version>
+        <relativePath/>
+    </parent>
+    <dependencies>
+        <!-- Spring Boot Starters -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <!-- 自定义基础组件 -->
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>base</artifactId>
+            <version>1.3</version>
+        </dependency>
+
+        <!-- MySQL 驱动 -->
+        <dependency>
+            <groupId>com.mysql</groupId>
+            <artifactId>mysql-connector-j</artifactId>
+            <version>8.0.33</version>
+        </dependency>
+
+        <!-- SQL Server 驱动(如果不需要可以移除) -->
+        <dependency>
+            <groupId>com.microsoft.sqlserver</groupId>
+            <artifactId>mssql-jdbc</artifactId>
+            <version>12.4.2.jre8</version>
+        </dependency>
+
+        <!-- MyBatis-Plus -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.5.3.2</version>
+        </dependency>
+
+        <!-- MyBatis-Plus 代码生成器 -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>3.5.5</version>
+        </dependency>
+
+        <!-- 模板引擎(修复版本) -->
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+            <version>2.3</version>
+        </dependency>
+
+        <!-- FreeMarker(可选,与 Velocity 二选一) -->
+        <dependency>
+            <groupId>org.freemarker</groupId>
+            <artifactId>freemarker</artifactId>
+            <version>2.3.32</version>
+        </dependency>
+
+        <!-- Lombok -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <!-- 腾讯云 OCR -->
+        <dependency>
+            <groupId>com.tencentcloudapi</groupId>
+            <artifactId>tencentcloud-sdk-java-ocr</artifactId>
+            <version>3.1.1210</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.tencentcloudapi</groupId>
+            <artifactId>tencentcloud-sdk-java</artifactId>
+            <version>3.1.1442</version>
+        </dependency>
+
+        <!-- 图片处理 -->
+        <dependency>
+            <groupId>net.coobird</groupId>
+            <artifactId>thumbnailator</artifactId>
+            <version>0.4.8</version>
+        </dependency>
+
+        <!-- 图片处理扩展 -->
+        <dependency>
+            <groupId>com.twelvemonkeys.imageio</groupId>
+            <artifactId>imageio-tiff</artifactId>
+            <version>3.5</version>
+        </dependency>
+
+        <!-- PDF 处理 -->
+        <dependency>
+            <groupId>e-iceblue</groupId>
+            <artifactId>spire.pdf.free</artifactId>
+            <version>5.1.0</version>
+        </dependency>
+
+        <!-- 测试 -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <repositories>
+        <repository>
+            <id>com.e-iceblue</id>
+            <name>e-iceblue</name>
+            <url>https://repo.e-iceblue.com/nexus/content/groups/public/</url>
+        </repository>
+    </repositories>
+    <build>
+        <finalName>qiwang</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <executable>true</executable>
+                    <includeSystemScope>true</includeSystemScope>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 112 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Controller/CallBackController.java

@@ -0,0 +1,112 @@
+package com.malk.qiwang.Controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.malk.controller.DDCallbackController;
+import com.malk.qiwang.Service.IInvoiceLibraryService;
+import com.malk.server.dingtalk.DDConf;
+import com.malk.server.dingtalk.crypto.DingCallbackCrypto;
+import com.malk.service.dingtalk.DDClient_Event;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@RestController
+@Component
+@RequestMapping("/aa")
+public class CallBackController extends DDCallbackController {
+    @Autowired
+    private DDConf ddConf;
+    @Autowired
+    private IInvoiceLibraryService invoiceLibrary;
+    @Autowired
+    private DDClient_Event ddClient_event;
+
+
+    /**
+     * 钉钉审批回调: [依赖包方案已弃用]
+     * -
+     * DingCallbackCrypto 方案: 官网案例 DingCallbackCrypto 不在钉钉架包, 需要单独引用
+     * 在钉钉开放平台重新保存回调地址后, 所有的注册事件会被关闭:: 通过代码注册不成功; 官方回复, 要么使用调用注册的方式 要么是后台的方式, 二选一
+     */
+    @SneakyThrows
+    public Map<String, String> invokeCallback(@RequestParam(value = "signature", required = false) String signature,
+                                              @RequestParam(value = "timestamp", required = false) String timestamp,
+                                              @RequestParam(value = "nonce", required = false) String nonce,
+                                              @RequestBody(required = false) JSONObject json) {
+        log.info("signature:{}",signature);
+        log.info("timestamp:{}",timestamp);
+        log.info("nonce:{}",nonce);
+        log.info("json:{}",json);
+//        MDC.put("MDC_KEY_PID", "1003");
+        DingCallbackCrypto callbackCrypto = new DingCallbackCrypto(ddConf.getToken(), ddConf.getAesKey(), ddConf.getAppKey());
+        final String decryptMsg = callbackCrypto.getDecryptMsg(signature, timestamp, nonce, json.getString("encrypt"));
+        JSONObject eventJson = JSON.parseObject(decryptMsg);
+        Map success = callbackCrypto.getEncryptedMap(DDConf.CALLBACK_RESPONSE, System.currentTimeMillis(), DingCallbackCrypto.Utils.getRandomStr(8));
+
+        String eventType = eventJson.getString("EventType");
+
+
+
+        if (DDConf.CALLBACK_CHECK.equals(eventType)) {
+            log.info("----- [DD]验证注册 -----");
+            return success;
+        }
+        if (DDConf.BPMS_INSTANCE_CHANGE.equals(eventType)) {
+            log.info("----- [DD]验证注册 -----");
+            String processCode = eventJson.getString("processCode");
+            String type = eventJson.getString("type");
+            String result = eventJson.getString("result");
+            String processInstanceId = eventJson.getString("processInstanceId");
+            String eventId = eventJson.getString("eventId");//事件id
+            // 检查回调事件是否已经处理过,如果是,则忽略该回调
+            if (isCallbackProcessed(eventId)) {
+                log.info("----- [DD]该签到回调事件已处理过 忽略该回调 -----");
+                return success;
+            }else {
+                // 将回调事件和当前时间戳添加到已处理集合中
+                long currentTime = System.currentTimeMillis();
+                eventList.put(eventId, currentTime);
+            }
+            if("terminate".equals(type) || "finish".equals(type) && "refuse".equals(result)){
+                log.info("----- [DD]审批回调, {}", eventJson);
+                invoiceLibrary.deleteAllByOaId(processInstanceId);
+            }
+
+            return success;
+        }
+
+        log.info("----- [DD]已注册, 未处理的其它回调 -----, {}", eventJson);
+        return success;
+    }
+
+    //保存10s内已处理的回调事件
+    private Map<String, Long> eventList = new HashMap<>();
+
+    /**
+     * 检查该回调事件在10s内是否处理过,应对钉钉瞬间重复回调
+     *
+     * @param eventId 回调事件id
+     * @return 是否处理过
+     */
+    private boolean isCallbackProcessed(String eventId) {
+        // 清理超过10s的回调事件
+        long currentTime = System.currentTimeMillis();
+        long expirationTime = currentTime - TimeUnit.MINUTES.toMillis(10);
+        eventList.entrySet().removeIf(entry -> entry.getValue() < expirationTime);
+
+        return eventList.containsKey(eventId);
+    }
+
+}

+ 222 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Controller/CompanyTitleController.java

@@ -0,0 +1,222 @@
+package com.malk.qiwang.Controller;
+
+import com.malk.qiwang.Service.ICompanyTitleService;
+import com.malk.qiwang.entity.CompanyTitle;
+import com.malk.qiwang.mapper.CompanyTitleMapper;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Workflow;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.checkerframework.checker.units.qual.A;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.*;
+
+/**
+ * <p>
+ * 公司抬头库表 前端控制器
+ * </p>
+ *
+ * @author LQY
+ * @since 2026-04-24
+ */
+@RestController
+@RequestMapping("/qw1")
+@Slf4j
+public class CompanyTitleController {
+@Autowired
+private ICompanyTitleService companyTitleService;
+@Autowired
+private YDClient ydClient;
+    @Autowired
+    private DDClient_Workflow ddClientWorkflow ;
+    @Autowired
+    private DDClient ddClient;
+    @Autowired
+    private CompanyTitleMapper companyTitleMapper;
+    @PostMapping("/companyTitle")
+    public McR insertTransfer2(@RequestBody(required = false) Map<String, Object> map) {
+        if (map == null) {
+            map = new HashMap<>();
+            log.info("请求体为空,使用默认参数");
+        }
+        log.info("接收到的参数: {}", map);
+
+        // 获取参数
+        String processCode = "PROC-187CB1F8-5BF0-403A-9D01-94EEF987DD77";
+
+        // 设置时间范围(默认查询最近30天)
+        Long startTime = System.currentTimeMillis() - 30L * 24 * 60 * 60 * 1000;
+        Long endTime = System.currentTimeMillis();
+
+        // 获取钉钉accessToken
+        String accessToken = ddClient.getAccessToken();
+
+        // 递归获取所有审批实例ID
+        List<String> allInstanceIds = ddClientWorkflow.getInstanceIds_all(accessToken, processCode, startTime, endTime, null);
+
+        log.info("共查询到 {} 条审批实例", allInstanceIds.size());
+
+        // 批量处理审批实例
+        int successCount = 0;
+        int failCount = 0;
+
+        // 用于记录处理的税号,避免重复处理同一个税号(可选,根据业务需求)
+        Set<String> processedTaxIds = new HashSet<>();
+
+        for (String instanceId : allInstanceIds) {
+            try {
+                // 获取审批实例详情
+                Map<String, Object> processInstance = ddClientWorkflow.getProcessInstanceId(accessToken, instanceId);
+
+                if (processInstance != null) {
+                    // 提取并保存公司抬头数据
+                    boolean result = saveCompanyTitleFromInstance(processInstance, processedTaxIds);
+                    if (result) {
+                        successCount++;
+                    } else {
+                        failCount++;
+                    }
+                } else {
+                    failCount++;
+                }
+            } catch (Exception e) {
+                log.error("处理审批实例失败: instanceId={}", instanceId, e);
+                failCount++;
+            }
+        }
+
+        log.info("处理完成: 成功={}, 失败={}", successCount, failCount);
+
+        return McR.success();
+    }
+
+    private boolean saveCompanyTitleFromInstance(Map<String, Object> processInstance, Set<String> processedTaxIds) {
+        List<Map<String, Object>> formComponentValues =
+                (List<Map<String, Object>>) processInstance.get("formComponentValues");
+
+        if (formComponentValues == null || formComponentValues.isEmpty()) {
+            log.warn("表单数据为空");
+            return false;
+        }
+
+        String tt = "", sh = "", dz = "", dh = "", yh = "", zh = "", zt = "";
+
+        // 修复:安全获取审批时间,避免类型转换异常
+        Long finishTime = null;
+        Object finishTimeObj = processInstance.get("finishTime");
+        if (finishTimeObj != null) {
+            if (finishTimeObj instanceof Long) {
+                finishTime = (Long) finishTimeObj;
+            } else if (finishTimeObj instanceof String) {
+                try {
+                    finishTime = Long.parseLong((String) finishTimeObj);
+                } catch (NumberFormatException e) {
+                    log.warn("finishTime格式转换失败: {}", finishTimeObj);
+                }
+            } else if (finishTimeObj instanceof Integer) {
+                finishTime = ((Integer) finishTimeObj).longValue();
+            }
+        }
+
+        for (Map<String, Object> formComponentValue : formComponentValues) {
+            String id = String.valueOf(formComponentValue.get("id"));
+            String value = formComponentValue.get("value") != null ?
+                    String.valueOf(formComponentValue.get("value")) : "";
+
+            switch (id) {
+                case "TextField-K2AD4O5B":
+                    tt = value;
+                    break;
+                case "TextField_1JEUFYV5F4E80":
+                    sh = value;
+                    break;
+                case "TextField_EJZY527VJXC0":
+                    dz = value;
+                    break;
+                case "TextField_12YU12T3PZC0":
+                    dh = value;
+                    break;
+                case "TextField_1Z4P9MQFOW3K0":
+                    yh = value;
+                    break;
+                case "TextField_NUL1SS1PJQ80":
+                    zh = value;
+                    break;
+                case "DDSelectField_528A36XIP9C0":
+                    zt = value;
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        if (StringUtils.isBlank(sh)) {
+            log.warn("税号为空,跳过保存");
+            return false;
+        }
+
+        // 可选:避免重复处理同一个税号
+        if (processedTaxIds.contains(sh)) {
+            log.debug("税号 {} 已处理过,跳过", sh);
+            return false;
+        }
+
+        // 查询数据库中该税号的最新记录
+        CompanyTitle existing = companyTitleMapper.selectByTaxId(sh);
+
+        if (existing != null) {
+            // 比较审批时间,判断是否为最新数据
+            if (finishTime != null && existing.getUpdatedAt() != null) {
+                long existingTime = existing.getUpdatedAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
+                if (finishTime <= existingTime) {
+                    log.debug("当前审批数据不是最新,跳过更新: taxId={}, 审批时间={}, 数据库更新时间={}",
+                            sh, finishTime, existingTime);
+                    return false;
+                }
+            }
+
+            // 更新
+            existing.setCompanyName(tt);
+            existing.setAddress(dz);
+            existing.setPhone(dh);
+            existing.setBankName(yh);
+            existing.setBankAccount(zh);
+            existing.setStatus("启用".equals(zt) ? (byte) 0 : (byte) 1);
+            existing.setUpdatedAt(LocalDateTime.now());
+
+            companyTitleMapper.updateById(existing);
+            log.info("公司抬头更新成功: taxId={}, 审批时间={}", sh, finishTime);
+        } else {
+            // 新增
+            CompanyTitle companyTitle = new CompanyTitle();
+            companyTitle.setCompanyName(tt);
+            companyTitle.setTaxId(sh);
+            companyTitle.setAddress(dz);
+            companyTitle.setPhone(dh);
+            companyTitle.setBankName(yh);
+            companyTitle.setBankAccount(zh);
+            companyTitle.setStatus("启用".equals(zt) ? (byte) 0 : (byte) 1);
+            companyTitle.setCreatedAt(LocalDateTime.now());
+            companyTitle.setUpdatedAt(LocalDateTime.now());
+
+            companyTitleMapper.insert(companyTitle);
+            log.info("公司抬头新增成功: taxId={}", sh);
+        }
+
+        processedTaxIds.add(sh);
+        return true;
+    }
+}

+ 120 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Controller/InvoiceLibraryController.java

@@ -0,0 +1,120 @@
+package com.malk.qiwang.Controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.malk.qiwang.Service.IInvoiceLibraryService;
+import com.malk.qiwang.Service.QiWangService;
+import com.malk.qiwang.Service.TXYInvoice;
+import com.malk.qiwang.entity.InvoiceLibrary;
+import com.malk.qiwang.mapper.InvoiceLibraryMapper;
+import com.malk.server.common.McR;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.service.dingtalk.DDClient_Workflow;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.stereotype.Controller;
+
+import java.util.Map;
+
+/**
+ * <p>
+ * 发票库表 前端控制器
+ * </p>
+ *
+ * @author LQY
+ * @since 2026-04-27
+ */
+@RestController
+@RequestMapping("/qw2")
+@Slf4j
+public class InvoiceLibraryController {
+    @Autowired
+    private IInvoiceLibraryService invoiceLibrary;
+    @Autowired
+    private DDClient ddClient;
+    @Autowired
+    private YDClient ydClient;
+    @Autowired
+    private TXYInvoice txyInvoice;
+    @Value("${dingtalk.operator}")
+    private String operator;
+    @Value("${dingtalk.downloadPath}")
+    private String downloadPath;
+    @Autowired
+    private DDClient_Workflow ddClientWorkflow ;
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+    @Autowired
+    private InvoiceLibraryMapper baseMapper;
+    private static final String url = "http://47.103.203.2:9092/qiwang/";
+            //员工报销
+    @PostMapping("/invoiceLibrary")
+    public McR test(@RequestBody Map map) {
+        log.info("map:{}", map);
+        invoiceLibrary.invoiceLibrary(map);
+       return McR.success();
+    }
+    //付款申请
+    @PostMapping("/invoiceLibrary1")
+    public McR invoiceLibrary1(@RequestBody Map map) {
+        log.info("map:{}", map);
+        invoiceLibrary.invoiceLibrary1(map);
+        return McR.success();
+    }
+
+    //合作商付款申请
+    @PostMapping("/invoiceLibrary2")
+    public McR invoiceLibrary2(@RequestBody Map map) {
+        log.info("map:{}", map);
+        invoiceLibrary.invoiceLibrary2(map);
+        return McR.success();
+    }
+
+    //合作商报销申请
+    @PostMapping("/invoiceLibrary3")
+    public McR invoiceLibrary3(@RequestBody Map map) {
+        log.info("map:{}", map);
+        invoiceLibrary.invoiceLibrary3(map);
+        return McR.success();
+    }
+
+    //出差费用申请
+    @PostMapping("/invoiceLibrary5")
+    public McR invoiceLibrary5(@RequestBody Map map) {
+        log.info("map:{}", map);
+        invoiceLibrary.invoiceLibrary5(map);
+        return McR.success();
+    }
+
+    //付款申请(一对多)
+    @PostMapping("/invoiceLibrary6")
+    public McR invoiceLibrary6(@RequestBody Map map) {
+        log.info("map:{}", map);
+        invoiceLibrary.invoiceLibrary6(map);
+        return McR.success();
+    }
+    @PostMapping("/invoiceLibrarys")
+    public McR test2(@RequestBody Map map) {
+        log.info("map:{}", map);
+        invoiceLibrary.invoiceLibrarys(map);
+        return McR.success();
+    }
+    @PostMapping("/updateOaStatusByOaId")
+    public McR test1(@RequestBody Map map) {
+        log.info("map:{}", map);
+        invoiceLibrary.updateOaStatusByOaId(map);
+        return McR.success();
+    }
+    @PostMapping("/deleteAll")
+    public McR deleteAllByOaId(@RequestParam("oaId") String oaId) {
+
+        log.info("map:{}", oaId);
+        invoiceLibrary.deleteAllByOaId(oaId);
+       return McR.success();
+    }
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 907 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Controller/QiWangController.java


+ 18 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/MjavaQiwangApplication.java

@@ -0,0 +1,18 @@
+package com.malk.qiwang;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+@MapperScan("com.malk.qiwang.mapper")
+@EnableScheduling
+public class MjavaQiwangApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(MjavaQiwangApplication.class, args);
+    }
+
+}

+ 19 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Service/ICompanyTitleService.java

@@ -0,0 +1,19 @@
+package com.malk.qiwang.Service;
+
+import com.malk.qiwang.entity.CompanyTitle;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import java.util.Map;
+
+/**
+ * <p>
+ * 公司抬头库表 服务类
+ * </p>
+ *
+ * @author LQY
+ * @since 2026-04-24
+ */
+public interface ICompanyTitleService extends IService<CompanyTitle> {
+
+    void insertCompanyTitle(Map map);
+}

+ 36 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Service/IInvoiceLibraryService.java

@@ -0,0 +1,36 @@
+package com.malk.qiwang.Service;
+
+import com.malk.qiwang.entity.InvoiceLibrary;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.malk.server.common.McR;
+
+import java.util.Map;
+
+/**
+ * <p>
+ * 发票库表 服务类
+ * </p>
+ *
+ * @author LQY
+ * @since 2026-04-27
+ */
+public interface IInvoiceLibraryService extends IService<InvoiceLibrary> {
+
+    McR invoiceLibrary(Map map);
+
+    void updateOaStatusByOaId(Map map);
+
+    McR invoiceLibrarys(Map map);
+
+    McR deleteAllByOaId(String oaId);
+
+    McR invoiceLibrary1(Map map);
+
+    McR invoiceLibrary2(Map map);
+
+    McR invoiceLibrary3(Map map);
+
+    McR invoiceLibrary5(Map map);
+
+    McR invoiceLibrary6(Map map);
+}

+ 7 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Service/McProjectService.java

@@ -0,0 +1,7 @@
+package com.malk.qiwang.Service;
+
+public interface McProjectService {
+
+    void init();
+
+}

+ 9 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Service/QiWangService.java

@@ -0,0 +1,9 @@
+package com.malk.qiwang.Service;
+
+import java.util.Map;
+
+public interface QiWangService {
+
+
+    void invoiceLibrary(Map map);
+}

+ 39 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Service/TXYInvoice.java

@@ -0,0 +1,39 @@
+package com.malk.qiwang.Service;
+
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+
+import java.util.Map;
+
+public interface TXYInvoice {
+
+    /**
+     * 混贴票据识别 [将弃用, 直接返回识别数据, ppExt: 官方已停止更新, PDF多张异常]
+     *
+     * @param image 下载图片经Base64编码后不超过 7M。图片下载时间不超过 3 秒
+     */
+    @Deprecated
+    Map doMixedInvoiceOCR(String image) throws TencentCloudSDKException;
+
+    /**
+     * 通用票据识别(高级版)[返回结构化数据] ppExt: 新版本官方返回数据已结构化, 以官方为准
+     *
+     * @param image 下载图片经Base64编码后不超过 8M。图片下载时间不超过 3 秒
+     */
+    Map doRecognizeGeneralInvoice(String image) throws TencentCloudSDKException;
+
+    /**
+     * 发票验真[新版]
+     *
+     * @param invoiceKind         ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
+     * @param invoiceCode         票代码(10或12 位),全电发票为空
+     * @param checkCode           校验码后 6 位,增值税普通发票、增值税电子普通发票、增值税普通发票(卷式)、增值税电子普通发票(通行费)时必填;
+     * @param excludingTax/amount 不含税金额,增值税专用发票、增值税电子专用发票、机动车销售统一发票、二手车销售统一发票、区块链发票时必填; 全电发票为价税合计(含税金额)
+     */
+    Map doVatInvoiceVerifyNew(String invoiceKind, String invoiceCode, String invoiceNo, String invoiceDate, String amount, String checkCode, String excludingTax, String tips) throws TencentCloudSDKException;
+
+    /**
+     * 名片识别
+     */
+    Map doBusinessCardOCR(String image) throws TencentCloudSDKException;
+
+}

+ 151 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Service/impl/CompanyTitleServiceImpl.java

@@ -0,0 +1,151 @@
+package com.malk.qiwang.Service.impl;
+
+import com.malk.qiwang.Service.TXYInvoice;
+import com.malk.qiwang.entity.CompanyTitle;
+import com.malk.qiwang.mapper.CompanyTitleMapper;
+import com.malk.qiwang.Service.ICompanyTitleService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.dingtalk.DDR_New;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Contacts;
+import com.malk.service.dingtalk.DDClient_Workflow;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * <p>
+ * 公司抬头库表 服务实现类
+ * </p>
+ *
+ * @author LQY
+ * @since 2026-04-24
+ */
+@Service
+@Slf4j
+public class CompanyTitleServiceImpl extends ServiceImpl<CompanyTitleMapper, CompanyTitle> implements ICompanyTitleService {
+    @Autowired
+    private DDClient ddClient;
+    @Autowired
+    private YDClient ydClient;
+    @Autowired
+    private TXYInvoice txyInvoice;
+    @Value("${dingtalk.operator}")
+    private String operator;
+    @Value("${dingtalk.downloadPath}")
+    private String downloadPath;
+    @Autowired
+    private DDClient_Workflow ddClientWorkflow ;
+    @Autowired
+    private DDClient_Contacts ddClient_contacts;
+    private static final String url = "http://20f2fcef.r39.cpolar.top/qiwang/";
+    @Autowired
+    private CompanyTitleMapper companyTitleMapper;  // 或者使用 Mapper
+    @Override
+    public void insertCompanyTitle(Map map) {
+        log.info("map:{}", map);
+        String processInstanceId = UtilMap.getString(map, "processInstanceId");
+        String action = UtilMap.getString(map, "action");
+        String nsh = UtilMap.getString(map, "nsh");
+        // 删除操作
+        if ("del".equals(action)) {
+            // 根据税号删除
+            if (nsh != null && !nsh.isEmpty()) {
+                int result = companyTitleMapper.deleteByTaxId(nsh);
+                if (result > 0) {
+                    log.info("公司抬头删除成功: 税号={}", nsh);
+                } else {
+                    log.warn("公司抬头删除失败: 税号={} 不存在", nsh);
+                }
+            } else {
+                log.warn("删除操作失败: 税号为空");
+            }
+            return; // 删除操作完成后直接返回
+        }
+
+        // 新增操作(原有逻辑)
+        Map processInstance = ddClientWorkflow.getProcessInstanceId(ddClient.getAccessToken(), processInstanceId);
+
+        if (Objects.nonNull(processInstance)) {
+            List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
+            System.out.println("formComponentValues====" + formComponentValues);
+
+            String tt = "", sh = "", dz = "", dh = "", yh = "", zh = "", zt = "";
+
+            for (Map formComponentValue : formComponentValues) {
+                String id = String.valueOf(formComponentValue.get("id"));
+                String value = formComponentValue.get("value") != null ?
+                        String.valueOf(formComponentValue.get("value")) : "";
+
+                switch (id) {
+                    case "TextField-K2AD4O5B": tt = value; break;
+                    case "TextField_1JEUFYV5F4E80": sh = value; break;
+                    case "TextField_EJZY527VJXC0": dz = value; break;
+                    case "TextField_12YU12T3PZC0": dh = value; break;
+                    case "TextField_1Z4P9MQFOW3K0": yh = value; break;
+                    case "TextField_NUL1SS1PJQ80": zh = value; break;
+                    case "DDSelectField_528A36XIP9C0": zt = value; break;
+                    default: break;
+                }
+            }
+
+            // 检查税号是否已存在(避免重复插入)
+            CompanyTitle existing = companyTitleMapper.selectByTaxId(sh);
+            if (existing != null) {
+                log.warn("公司抬头已存在: 税号={}, 执行更新操作", sh);
+                // 更新操作
+                existing.setCompanyName(tt);
+                existing.setAddress(dz);
+                existing.setPhone(dh);
+                existing.setBankName(yh);
+                existing.setBankAccount(zh);
+                if ("启用".equals(zt)) {
+                    existing.setStatus((byte) 0);
+                } else if ("停用".equals(zt)) {
+                    existing.setStatus((byte) 1);
+                } else {
+                    existing.setStatus((byte) 0);
+                }
+                existing.setUpdatedAt(LocalDateTime.now());
+                companyTitleMapper.updateById(existing);
+                log.info("公司抬头更新成功: companyName={}, taxId={}", tt, sh);
+            } else {
+                // 新增操作
+                CompanyTitle companyTitle = new CompanyTitle();
+                companyTitle.setCompanyName(tt);
+                companyTitle.setTaxId(sh);
+                companyTitle.setAddress(dz);
+                companyTitle.setPhone(dh);
+                companyTitle.setBankName(yh);
+                companyTitle.setBankAccount(zh);
+
+                // 处理状态
+                if ("启用".equals(zt)) {
+                    companyTitle.setStatus((byte) 0);
+                } else if ("停用".equals(zt)) {
+                    companyTitle.setStatus((byte) 1);
+                } else {
+                    companyTitle.setStatus((byte) 0);
+                }
+
+                companyTitle.setCreatedAt(LocalDateTime.now());
+                companyTitle.setUpdatedAt(LocalDateTime.now());
+
+                // 保存
+                companyTitleMapper.insert(companyTitle);
+                log.info("公司抬头新增成功: companyName={}, taxId={}", tt, sh);
+            }
+        }
+    }
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 2652 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Service/impl/InvoiceLibraryServiceImpl.java


+ 29 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Service/impl/McProjectServiceImpl.java

@@ -0,0 +1,29 @@
+package com.malk.qiwang.Service.impl;
+
+import com.malk.core.McProject;
+
+import com.malk.qiwang.Service.McProjectService;
+import com.malk.service.aliwork.YDClient;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class McProjectServiceImpl implements McProjectService {
+
+    @Autowired
+    private YDClient ydClient;
+
+    @Override
+    public void init() {
+        MDC.put("MDC_KEY_PID","1002");
+        McProject.addDd("1003",new String[] {"dinglh2civttmfufkrha","5Zwobht8IX48Q-y9a3E21cY1oswzCycmgxVFTzNZ8IP62SdItL6EzhmFbCik7wH_"});//卡倍亿一期
+//        McProject.addYida("1003",new String[] {"APP_CRSI2VXGJE74J60OEFPD","C1A66XB1JOAMVXWCE3H28B05EU7T2F3AM4XXLN3"});//特充
+//        McProject.addYida("1009",new String[] {"APP_S5U4NUUK2T4RF8UR17EN","JL666BD1QGXNTZQ5DXEI97Q1USK92I1G6160MTCF"});//卡倍亿二期-分层审核
+//        McProject.addYida("1019",new String[] {"APP_UT77LJBEO7ZH3N5MX1TJ","ND966TC1C69P0KL9EE47C6WBVCBH29IMLRZ1M6E"});//卡倍亿二期-产量分析
+//        McProject.addYida("1020",new String[] {"APP_TROTJSBUI5IMEJYKXJU1","VF666N91369PUM829XYCL8LD9A433TH9GSZ1M8A"});//卡倍亿二期-OCR识别
+        log.info("项目加载完毕:1002");
+    }
+}

+ 17 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Service/impl/QiWangServiceImpl.java

@@ -0,0 +1,17 @@
+package com.malk.qiwang.Service.impl;
+
+import com.malk.qiwang.Service.QiWangService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+@Slf4j
+@Service
+public class QiWangServiceImpl implements QiWangService {
+
+    @Override
+    public void invoiceLibrary(Map map) {
+
+    }
+}

+ 165 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/Service/impl/TXYImplInvoice.java

@@ -0,0 +1,165 @@
+package com.malk.qiwang.Service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.malk.qiwang.Service.TXYInvoice;
+import com.malk.qiwang.tencent.TXYConf;
+import com.malk.server.common.McException;
+import com.malk.utils.UtilMap;
+import com.malk.utils.UtilNumber;
+import com.tencentcloudapi.ckafka.v20190819.models.DescribeInstancesRequest;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import com.tencentcloudapi.cvm.v20170312.CvmClient;
+import com.tencentcloudapi.cvm.v20170312.models.DescribeInstancesResponse;
+import com.tencentcloudapi.ocr.v20181119.OcrClient;
+import com.tencentcloudapi.ocr.v20181119.models.*;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+@Slf4j
+@Service
+public class TXYImplInvoice implements TXYInvoice {
+
+    @Autowired
+    private TXYConf txyConf;
+
+    // 创建请求描述
+    private ClientProfile doRequest(String endPoint) {
+
+        HttpProfile httpProfile = new HttpProfile();
+        httpProfile.setEndpoint(endPoint);
+        ClientProfile clientProfile = new ClientProfile();
+        clientProfile.setHttpProfile(httpProfile);
+        return clientProfile;
+    }
+
+    /**
+     * 混贴票据识别
+     *
+     * @apiNote https://cloud.tencent.com/document/product/866/37835
+     */
+    @Override
+    public Map doMixedInvoiceOCR(String image) throws TencentCloudSDKException {
+
+        Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
+        ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
+        OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);
+
+        MixedInvoiceOCRRequest req = new MixedInvoiceOCRRequest();
+        if (image.startsWith("http")) {
+            req.setImageUrl(image);
+        } else {
+            req.setImageBase64(image);
+        }
+        req.setReturnMultiplePage(true); // PDF多页识别, 仅支持返回文件前30页
+        //log.debug("请求参数, {}", JSON.toJSONString(req));
+        MixedInvoiceOCRResponse resp = client.MixedInvoiceOCR(req);
+        String result = MixedInvoiceOCRResponse.toJsonString(resp);
+        log.debug("请求响应, {}", result);
+        return (Map) JSON.parse(result);
+    }
+
+    /**
+     * 通用票据识别(高级版)
+     *
+     * @apiNote https://cloud.tencent.com/document/api/866/90802
+     */
+    @Override
+    public Map doRecognizeGeneralInvoice(String image) throws TencentCloudSDKException {
+        Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
+        ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
+        OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);
+
+        RecognizeGeneralInvoiceRequest req = new RecognizeGeneralInvoiceRequest();
+        if (image.startsWith("http")) {
+            req.setImageUrl(image);
+        } else {
+            req.setImageBase64(image);
+        }
+        req.setEnableMultiplePage(true); // PDF多页识别, 仅支持返回文件前30页
+        req.setEnableCutImage(false); // 返回切割图片base64
+        RecognizeGeneralInvoiceResponse resp = client.RecognizeGeneralInvoice(req);
+        String result = MixedInvoiceOCRResponse.toJsonString(resp);
+        log.debug("请求响应, {}", result);
+        return (Map) JSON.parse(result);
+    }
+
+    /**
+     * 发票验真[新版]
+     *
+     * @apiNote https://cloud.tencent.com/document/product/866/73674
+     */
+    @Override
+    public Map doVatInvoiceVerifyNew(String invoiceKind, String invoiceCode, String invoiceNo, String invoiceDate, String amount, String checkCode, String excludingTax, String tips) throws TencentCloudSDKException {
+        Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
+        ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
+        OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);
+
+        // 一些特殊发票校验码只有5位, 兼容
+        if (StringUtils.isNotBlank(checkCode) && checkCode.length() > 6) {
+            checkCode = checkCode.substring(checkCode.length() - 6);
+        }
+
+        VatInvoiceVerifyNewRequest req = new VatInvoiceVerifyNewRequest();
+        req.setInvoiceNo(invoiceNo);
+        req.setInvoiceDate(invoiceDate);
+        req.setInvoiceCode(invoiceCode);
+        req.setCheckCode(checkCode);
+        // ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
+        if (invoiceKind.contains("全电")) {
+            // 全电票, 需要价税合计且无发票代码与校验码
+            req.setCheckCode(null);
+            req.setInvoiceCode(null);
+            req.setAmount(amount);
+        } else {
+            req.setAmount(null);
+            req.setAmount(excludingTax);
+        }
+        log.debug("发票验真, {}, {}", invoiceKind, JSON.toJSONString(req));
+        VatInvoiceVerifyNewResponse resp = client.VatInvoiceVerifyNew(req);
+        String result = VatInvoiceVerifyNewResponse.toJsonString(resp);
+        Map rsp = (Map) JSON.parse(result);
+
+        // 因全电票取值, 取值价税合计, 单独校验下金额
+        Map invoice = (Map) rsp.get("Invoice");
+        if (StringUtils.isBlank(tips)) {
+            tips = "发票有疑问";
+        }
+        log.debug("请求响应, {}", result);
+        McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithTax"), amount), tips + ", 价税合计金额不匹配!");
+        // ppExt: 增值税卷票: 票面无税率, 税额. 但接口验证返回或本质上发票是有税率, 税额. 因此取消后置判断
+        McException.assertAccessException(!invoiceKind.contains("卷票") && !UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithoutTax"), excludingTax), tips + ", 不含税金额不匹配!");
+        return rsp;
+    }
+
+    /**
+     * 名片识别
+     *
+     * @apiNote https://console.cloud.tencent.com/api/explorer?Product=ocr&Version=2018-11-19&Action=BusinessCardOCR
+     */
+    @Override
+    public Map doBusinessCardOCR(String image) throws TencentCloudSDKException {
+        Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
+        ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
+        OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);
+
+        BusinessCardOCRRequest req = new BusinessCardOCRRequest();
+        if (image.startsWith("http")) {
+            req.setImageUrl(image);
+        } else {
+            req.setImageBase64(image);
+        }
+        req.setConfig(JSON.toJSONString(UtilMap.map("RetImageType", "PROPROCESS")));
+        //log.debug("请求参数, {}", JSON.toJSONString(req));
+        BusinessCardOCRResponse resp = client.BusinessCardOCR(req);
+        String result = BusinessCardOCRResponse.toJsonString(resp);
+        log.debug("请求响应, {}", result);
+        return (Map) JSON.parse(result);
+    }
+}

+ 19 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/config/StartupRunner.java

@@ -0,0 +1,19 @@
+package com.malk.qiwang.config;
+
+
+import com.malk.qiwang.Service.McProjectService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+@Component
+public class StartupRunner implements ApplicationRunner {
+
+    @Autowired
+    private McProjectService mcProjectService;
+    @Override
+    public void run(ApplicationArguments args) throws Exception {
+        mcProjectService.init();
+    }
+}

+ 76 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/entity/CompanyTitle.java

@@ -0,0 +1,76 @@
+package com.malk.qiwang.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 公司抬头库表
+ * </p>
+ *
+ * @author LQY
+ * @since 2026-04-24
+ */
+@Getter
+@Setter
+  @TableName("company_title")
+public class CompanyTitle implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+      /**
+     * 主键ID,自增
+     */
+        @TableId(value = "id", type = IdType.AUTO)
+      private Integer id;
+
+      /**
+     * 公司抬头/名称
+     */
+      private String companyName;
+
+      /**
+     * 税号/统一社会信用代码
+     */
+      private String taxId;
+
+      /**
+     * 注册地址
+     */
+      private String address;
+
+      /**
+     * 注册电话
+     */
+      private String phone;
+
+      /**
+     * 开户银行
+     */
+      private String bankName;
+
+      /**
+     * 银行账号
+     */
+      private String bankAccount;
+
+      /**
+     * 抬头是否启用: 0: 启用, 1: 停用
+     */
+      private Byte status;
+
+      /**
+     * 创建时间
+     */
+      private LocalDateTime createdAt;
+
+      /**
+     * 更新时间
+     */
+      private LocalDateTime updatedAt;
+}

+ 128 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/entity/InvoiceLibrary.java

@@ -0,0 +1,128 @@
+package com.malk.qiwang.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 发票库表
+ * </p>
+ *
+ * @author LQY
+ * @since 2026-04-27
+ */
+@Getter
+@Setter
+@TableName("invoice_library")
+public class InvoiceLibrary implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 自增主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * OA流水号
+     */
+    private String oaId;
+
+    /**
+     * 发票代码
+     */
+    private String invoiceCode;
+
+    /**
+     * 发票号码
+     */
+    private String invoiceNumber;
+
+    /**
+     * 发票类型
+     */
+    private String invoiceType;
+
+    /**
+     * 开票日期
+     */
+    private LocalDate invoiceDate;
+
+    /**
+     * 不含税金额
+     */
+    private BigDecimal amount;
+
+    /**
+     * 税额
+     */
+    private BigDecimal taxAmount;
+
+    /**
+     * 含税金额
+     */
+    private BigDecimal totalAmount;
+
+    /**
+     * 购买方名称
+     */
+    private String buyerName;
+
+    /**
+     * 购买方税号
+     */
+    private String buyerTaxId;
+
+    /**
+     * 销售方名称
+     */
+    private String sellerName;
+
+    /**
+     * 销售方税号
+     */
+    private String sellerTaxId;
+
+    /**
+     * 状态: 0: 流程中 1: 已通过
+     */
+    private String oaStatus;
+
+    /**
+     * 是否已经生成凭证 0: 否 1: 是
+     */
+    private String invoiceStatus;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createdAt;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updatedAt;
+
+    /**
+     * 科目
+     */
+    private String accountTitle;
+
+    /**
+     * 部门
+     */
+    private String dep;
+
+    /**
+     * 报销金额
+     */
+    private BigDecimal payAmount;
+}

+ 46 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/mapper/CompanyTitleMapper.java

@@ -0,0 +1,46 @@
+package com.malk.qiwang.mapper;
+
+import com.malk.qiwang.entity.CompanyTitle;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * <p>
+ * 公司抬头库表 Mapper 接口
+ * </p>
+ *
+ * @author LQY
+ * @since 2026-04-24
+ */
+public interface CompanyTitleMapper extends BaseMapper<CompanyTitle> {
+    /**
+     * 根据税号删除
+     *
+     * @param taxId 税号
+     * @return 删除条数
+     */
+    @Delete("DELETE FROM company_title WHERE tax_id = #{taxId}")
+    int deleteByTaxId(@Param("taxId") String taxId);
+
+    /**
+     * 根据税号查询
+     *
+     * @param taxId 税号
+     * @return 公司抬头信息
+     */
+//    @Select("SELECT * FROM company_title WHERE tax_id = #{taxId}")
+    @Select("SELECT * FROM company_title WHERE company_name = #{companyName}")
+    CompanyTitle selectByTaxId(@Param("companyName") String companyName);
+
+    /**
+     * 软删除(根据税号更新删除标记)
+     *
+     * @param taxId 税号
+     * @return 更新条数
+     */
+    @Update("UPDATE company_title SET deleted_at = NOW() WHERE tax_id = #{taxId}")
+    int softDeleteByTaxId(@Param("taxId") String taxId);
+}

+ 26 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/mapper/InvoiceLibraryMapper.java

@@ -0,0 +1,26 @@
+package com.malk.qiwang.mapper;
+
+import com.malk.qiwang.entity.CompanyTitle;
+import com.malk.qiwang.entity.InvoiceLibrary;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+/**
+ * <p>
+ * 发票库表 Mapper 接口
+ * </p>
+ *
+ * @author LQY
+ * @since 2026-04-27
+ */
+public interface InvoiceLibraryMapper extends BaseMapper<InvoiceLibrary> {
+
+      /**
+     * 根据发票号查询发票记录
+     * @param invoiceNumber 发票号码
+     * @return 发票记录
+     */
+    @Select("SELECT * FROM invoice_library WHERE invoice_number = #{invoiceNumber} LIMIT 1")
+    InvoiceLibrary selectByInvoiceNumber(@Param("invoiceNumber") String invoiceNumber);
+}

+ 5 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/mapper/xml/CompanyTitleMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.malk.qiwang.mapper.CompanyTitleMapper">
+
+</mapper>

+ 5 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/mapper/xml/InvoiceLibraryMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.malk.qiwang.mapper.InvoiceLibraryMapper">
+
+</mapper>

+ 220 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/model/McInvoiceDto.java

@@ -0,0 +1,220 @@
+package com.malk.qiwang.model;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.malk.base.BaseDto;
+import com.malk.server.common.McException;
+import com.malk.server.common.McREnum;
+import com.malk.utils.UtilMap;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+import java.math.BigDecimal;
+import java.util.Map;
+
+/**
+ * ppExt: 新版本官方返回数据已结构化, 以官方为准
+ *
+ * @apiNote https://cloud.tencent.com/document/api/866/33527#AirTransport 数据结构
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class McInvoiceDto extends BaseDto {
+
+
+    /**************** 发票 ****************/
+
+    /**
+     * 发票名称 [类型全称]
+     */
+    private String name;
+
+    /**
+     * 发票用途 [供应商、报销]
+     */
+    private String type;
+
+    // 兼容: 不为空
+    public String getName() {
+        if (StringUtils.isBlank(name)) {
+            return kindName;
+        }
+        return name;
+    }
+
+    /**
+     * 发票类型 [类型简称]
+     * -
+     * ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
+     */
+    private String kindName;
+
+    /**
+     * 发票类型 [编码]
+     */
+    private int kind;
+
+    /**
+     * 发票代码
+     */
+    private String code;
+
+    /**
+     * 发票号码
+     */
+    private String serial;
+
+    /**
+     * 开票日期 [yyyy-MM-dd]
+     */
+    private String date;
+
+    /**
+     * 校验码
+     */
+    private String checkCode;
+
+    /**
+     * 价税合计
+     */
+    private BigDecimal amount;
+
+    /**
+     * 不含税金额
+     */
+    private BigDecimal excludingTax;
+
+    /// 没有税额时, 税额可能没传递 [因此前提是不含税为空],不含税金额等于价税合计
+    public BigDecimal getExcludingTax() {
+        if (ObjectUtil.isNull((excludingTax)) && (ObjectUtil.isNull(tax) || BigDecimal.ZERO.compareTo(tax) == 0)) {
+            return amount;
+        }
+        return excludingTax;
+    }
+
+    /**
+     * 不含税金额
+     */
+    private BigDecimal tax;
+
+    /// 取值为null, 合计会异常
+    public BigDecimal getTax() {
+        if (ObjectUtil.isNull(tax)) {
+            return BigDecimal.ZERO;
+        }
+        return tax;
+    }
+
+    /**
+     * 购买方名称
+     */
+    private String buyerName;
+
+    /**
+     * 购买方税号
+     */
+    private String buyerTaxId;
+
+    /**
+     * 销售方名称
+     */
+    private String sellerName;
+
+    /**
+     * 销售方税号
+     */
+    private String sellerTaxId;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**************** 交通 ****************/
+
+    /**
+     * 乘客姓名
+     */
+    private String passengerName;
+
+    /**
+     * 座位类型
+     */
+    private String seatType;
+
+    /**
+     * 出发地
+     */
+    private String departurePort;
+
+    /**
+     * 到达地
+     */
+    private String arrivePort;
+
+    /**
+     * 出发时间 [yyyy-MM-dd HH:mm]
+     */
+    private String departureTime;
+
+    /**
+     * 车次编号/航班号
+     */
+    private String trainNo;
+
+    /**
+     * 保险费
+     */
+    private BigDecimal insuranceCosts;
+
+    /**
+     * 燃油附加费
+     */
+    private BigDecimal fuelCosts;
+
+    /**
+     * 民航发展基金
+     */
+    private BigDecimal constructionCosts;
+
+    /**************** 格式化 ****************/
+
+    /**
+     * 实例Map, 服务宜搭组件映射 [明细组件获取表头, 通过名称转换字段]
+     *
+     * @implSpec const headers = this.$("tableField_liv5f4d2").props.children[0].props.children.map(({ props: { label, fieldId } }) => ({ label, compId: fieldId }))
+     */
+    public static Map formatDtoLabelAndProp() {
+
+        Map data = UtilMap.map("发票名称, 发票类型, 发票代码, 发票号码, 开票日期, 校验码, 价税合计, 不含税金额, 税额", "name, kindName, code, serial, date, checkCode, amount, excludingTax, tax");
+        data.putAll(UtilMap.map("购买方名称, 购买方税号, 销售方名称, 销售方税号", "buyerName, buyerTaxId, sellerName, sellerTaxId"));
+        data.putAll(UtilMap.map("乘客姓名, 座位类型, 出发地, 到达地, 出发时间, 车次编号/航班号, 保险费, 燃油附加费, 民航发展基金", "passengerName, seatType, departurePort, arrivePort, departureTime, trainNo, insuranceCosts, fuelCosts, constructionCosts"));
+        return data;
+    }
+
+    /**
+     * 格式化返回
+     */
+    public static Map formatResponse(Object result) {
+//        return UtilMap.map("result, dto", result, formatDtoLabelAndProp());
+        return UtilMap.map("result", result);
+    }
+
+    /**************** 返回值 ****************/
+
+    // 成功状态标记
+    private final static String SUC_CODE = "OK";
+
+    /**
+     * 断言错误信息
+     */
+    public static void assertSuccess(Map result, String kind) {
+        String code = UtilMap.getString(result, "Code");
+        McException.assertException(!SUC_CODE.equals(code), McREnum.VENDOR_ERROR.getCode(), kind, "tencent");
+    }
+}
+

+ 68 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/model/McInvoiceKind.java

@@ -0,0 +1,68 @@
+package com.malk.qiwang.model;
+
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+/**
+ * 定义返回值和对应状态的信息 [旧版本]
+ * ppExt: 新版本官方返回数据已结构化, 以官方为准
+ */
+@Deprecated
+@Slf4j
+public enum McInvoiceKind {
+
+    PP("增值税普通发票", 1),
+    ZP("增值税专用发票", 2),
+    DP("增值税电子普通发票", 3),
+    DZ("增值税电子专用发票", 4),
+    QP("全电普通发票", 5),
+    QZ("全电专用发票", 6),
+
+    HC("火车票", 11),
+    HCDZ("火车票", 16),
+    JP("机票行程单", 12),
+    CZC("出租车发票", 13),
+    DE("定额发票", 14),
+    GLGQ("过路过桥费发票", 15),
+
+    FS("非税发票", 21),
+    OT("其它特殊发票", 22),
+
+    UN("未知类型", -1);
+
+    @Getter
+    private String desc;
+    @Getter
+    private int code;
+
+    /**
+     * 根据code查找
+     */
+    public final static String getKindName(int code) {
+        Optional optional = Arrays.stream(McInvoiceKind.values()).filter(item -> item.code == code).findAny();
+        if (optional.isPresent()) {
+            return ((McInvoiceKind) optional.get()).desc;
+        }
+        return UN.getDesc();
+    }
+
+    /**
+     * 根据name查找
+     */
+    public final static int getKindCode(String name) {
+        Optional optional = Arrays.stream(McInvoiceKind.values()).filter(item -> item.desc.equals(name)).findAny();
+        //log.info("发票类型, {}", Arrays.stream(McInvoiceKind.values()).map(item -> item.desc).collect(Collectors.toList()));
+        if (optional.isPresent()) {
+            return ((McInvoiceKind) optional.get()).code;
+        }
+        return UN.getCode();
+    }
+
+    McInvoiceKind(String name, int code) {
+        this.desc = name;
+        this.code = code;
+    }
+}

+ 40 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/tencent/TXYConf.java

@@ -0,0 +1,40 @@
+package com.malk.qiwang.tencent;
+
+import com.malk.utils.UtilMap;
+import lombok.Data;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * 读取配置文件参考FilePah
+ */
+@Data
+@Component
+//@ConfigurationProperties(prefix = "tencent")
+public class TXYConf {
+
+//    private String APPID="1412895585";
+    private String APPID="1425374127";
+
+//    private String SecretId="AKIDDF3cw3wb3QZUBeuxnTwBCzYu1tWv624t";
+
+//    private String SecretKey="d1CAvRkyxhCbliRwEIB2yugSRNHGSdeb";
+
+    private String SecretId="AKIDZ9WjjU2NUNYAaw87tRmsmUzHLE6Leqsh";
+
+    private String SecretKey="f8NQ8h2CAvTnuTowqX2JNEsKYZXIp9F8";
+
+    private String Region="ap-guangzhou";
+
+    /**
+     * 票据类型
+     * -
+     * 中央非税未返回税号官方说明: 非税发票理论是没有税号的,图片中那个属于信用代码 [两个版本接口均为返回]
+     * ppExt: 新版本官方返回数据已结构化, 以官方为准
+     */
+    @Deprecated
+    public static final Map<String, String> TYPE_INVOICE = UtilMap.map("-1, 0, 1, 2, 3, 5, 8, 9, 10, 11, 12, 13, 15, 16",
+            "未知类型, 出租车发票, 定额发票, 火车票, 增值税发票, 机票行程单, 通用机打发票, 汽车票, 轮船票, 增值税发票(卷票) , 购车发票, 过路过桥费发票, 非税发票, 全电发票");
+
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 113 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/tencent/TXYConfNh.java


+ 267 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/utils/HTTPHelper.java

@@ -0,0 +1,267 @@
+package com.malk.qiwang.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+
+public class HTTPHelper {
+    // slf4j日志记录器
+    private static final Logger LOG = LoggerFactory.getLogger(HTTPHelper.class);
+
+    /***
+     * 向指定URL发送GET方法的请求
+     *
+     * @param apiUrl
+     * @param data
+     * @param projectId
+     * @param signature
+     * @param encoding
+     * @return
+     * @throws Exception
+     */
+    public static String sendGet(String apiUrl, HashMap<String, Object> param,
+                                 LinkedHashMap<String, String> headers, String encoding) throws Exception {
+        // 获得响应内容
+        String http_RespContent = null;
+        HttpURLConnection httpURLConnection = null;
+        int http_StatusCode = 0;
+        String http_RespMessage = null;
+        try {
+            // 实际请求完整Url
+            StringBuffer fullUrl = new StringBuffer();
+            if (null != param) {
+                if (0 != param.size()) {
+                    StringBuffer params = new StringBuffer();
+                    for (Entry<String, Object> entry : param.entrySet()) {
+                        params.append(entry.getKey());
+                        params.append("=");
+                        params.append(entry.getValue().toString());
+                        params.append("&");
+                    }
+                    if (params.length() > 0) {
+                        params.deleteCharAt(params.lastIndexOf("&"));
+                    }
+                    fullUrl.append(apiUrl).append((params.length() > 0) ? "?" + params.toString() : "");
+                } else {
+                    fullUrl.append(apiUrl);
+                }
+            } else {
+                fullUrl.append(apiUrl);
+            }
+
+            LOG.info(">>>> 实际请求Url: " + fullUrl.toString());
+
+            // 建立连接
+            URL url = new URL(fullUrl.toString());
+            httpURLConnection = (HttpURLConnection) url.openConnection();
+            // 需要输出
+            httpURLConnection.setDoOutput(true);
+            // 需要输入
+            httpURLConnection.setDoInput(true);
+            // 不允许缓存
+            httpURLConnection.setUseCaches(false);
+            // HTTP请求方式
+            httpURLConnection.setRequestMethod("GET");
+            // 设置Headers
+            if (null != headers) {
+                for (String key : headers.keySet()) {
+                    httpURLConnection.setRequestProperty(key, headers.get(key));
+                }
+            }
+            // 连接会话
+            httpURLConnection.connect();
+            // 获得响应状态(HTTP状态码)
+            http_StatusCode = httpURLConnection.getResponseCode();
+            // 获得响应消息(HTTP状态码描述)
+            http_RespMessage = httpURLConnection.getResponseMessage();
+            // 获得响应内容
+            if (HttpURLConnection.HTTP_OK == http_StatusCode) {
+                // 返回响应结果
+                http_RespContent = getResponseContent(httpURLConnection);
+            } else {
+                // 返回非200状态时响应结果
+                http_RespContent = getErrorResponseContent(httpURLConnection);
+                String msg =
+                        MessageFormat.format("请求失败: Http状态码 = {0} , {1}", http_StatusCode, http_RespMessage);
+                LOG.info(msg);
+            }
+        } catch (UnknownHostException e) {
+            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
+            Exception ex = new Exception(message);
+            ex.initCause(e);
+            throw ex;
+        } catch (MalformedURLException e) {
+            String message = MessageFormat.format("格式错误的URL: {0}", e.getMessage());
+            Exception ex = new Exception(message);
+            ex.initCause(e);
+            throw ex;
+        } catch (IOException e) {
+            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
+            Exception ex = new Exception(message);
+            ex.initCause(e);
+            throw ex;
+        } catch (Exception e) {
+            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
+            Exception ex = new Exception(message);
+            ex.initCause(e);
+            throw ex;
+        } finally {
+            if (null != httpURLConnection) {
+                httpURLConnection.disconnect();
+            }
+        }
+        return http_RespContent;
+    }
+
+    /***
+     * 向指定URL发送POST方法的请求
+     *
+     * @param apiUrl
+     * @param data
+     * @param projectId
+     * @param signature
+     * @param encoding
+     * @return
+     * @throws Exception
+     */
+    public static String sendPOST(String apiUrl, String data, LinkedHashMap<String, String> headers,
+                                  String encoding) throws Exception {
+        // 获得响应内容
+        String http_RespContent = null;
+        HttpURLConnection httpURLConnection = null;
+        int http_StatusCode = 0;
+        String http_RespMessage = null;
+        try {
+            // 建立连接
+            URL url = new URL(apiUrl);
+            httpURLConnection = (HttpURLConnection) url.openConnection();
+            // 需要输出
+            httpURLConnection.setDoOutput(true);
+            // 需要输入
+            httpURLConnection.setDoInput(true);
+            // 不允许缓存
+            httpURLConnection.setUseCaches(false);
+            // HTTP请求方式
+            httpURLConnection.setRequestMethod("POST");
+            // 设置Headers
+            if (null != headers) {
+                for (String key : headers.keySet()) {
+                    httpURLConnection.setRequestProperty(key, headers.get(key));
+                }
+            }
+            // 连接会话
+            httpURLConnection.connect();
+            // 建立输入流,向指向的URL传入参数
+            DataOutputStream dos = new DataOutputStream(httpURLConnection.getOutputStream());
+            // 设置请求参数
+            dos.write(data.getBytes(encoding));
+            dos.flush();
+            dos.close();
+            // 获得响应状态(HTTP状态码)
+            http_StatusCode = httpURLConnection.getResponseCode();
+            // 获得响应消息(HTTP状态码描述)
+            http_RespMessage = httpURLConnection.getResponseMessage();
+            // 获得响应内容
+            if (HttpURLConnection.HTTP_OK == http_StatusCode) {
+                // 返回响应结果
+                http_RespContent = getResponseContent(httpURLConnection);
+            } else {
+                // 返回非200状态时响应结果
+                http_RespContent = getErrorResponseContent(httpURLConnection);
+                String msg =
+                        MessageFormat.format("请求失败: Http状态码 = {0} , {1}", http_StatusCode, http_RespMessage);
+                LOG.info(msg);
+            }
+        } catch (UnknownHostException e) {
+            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
+            Exception ex = new Exception(message);
+            ex.initCause(e);
+            throw ex;
+        } catch (MalformedURLException e) {
+            String message = MessageFormat.format("格式错误的URL: {0}", e.getMessage());
+            Exception ex = new Exception(message);
+            ex.initCause(e);
+            throw ex;
+        } catch (IOException e) {
+            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
+            Exception ex = new Exception(message);
+            ex.initCause(e);
+            throw ex;
+        } catch (Exception e) {
+            String message = MessageFormat.format("网络请求时发生异常: {0}", e.getMessage());
+            Exception ex = new Exception(message);
+            ex.initCause(e);
+            throw ex;
+        } finally {
+            if (null != httpURLConnection) {
+                httpURLConnection.disconnect();
+            }
+        }
+        return http_RespContent;
+    }
+
+    /***
+     * 读取HttpResponse响应内容
+     *
+     * @param httpURLConnection
+     * @return
+     * @throws UnsupportedEncodingException
+     * @throws IOException
+     */
+    private static String getResponseContent(HttpURLConnection httpURLConnection)
+            throws UnsupportedEncodingException, IOException {
+        StringBuffer contentBuffer = null;
+        BufferedReader responseReader = null;
+        try {
+            contentBuffer = new StringBuffer();
+            String readLine = null;
+            responseReader =
+                    new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(), "UTF-8"));
+            while ((readLine = responseReader.readLine()) != null) {
+                contentBuffer.append(readLine);
+            }
+        } finally {
+            if (null != responseReader) {
+                responseReader.close();
+            }
+        }
+        return contentBuffer.toString();
+    }
+
+    /***
+     * 读取HttpResponse响应内容
+     *
+     * @param httpURLConnection
+     * @return
+     * @throws UnsupportedEncodingException
+     * @throws IOException
+     */
+    private static String getErrorResponseContent(HttpURLConnection httpURLConnection)
+            throws UnsupportedEncodingException, IOException {
+        StringBuffer contentBuffer = null;
+        BufferedReader responseReader = null;
+        try {
+            contentBuffer = new StringBuffer();
+            String readLine = null;
+            responseReader =
+                    new BufferedReader(new InputStreamReader(httpURLConnection.getErrorStream(), "UTF-8"));
+            while ((readLine = responseReader.readLine()) != null) {
+                contentBuffer.append(readLine);
+            }
+        } finally {
+            if (null != responseReader) {
+                responseReader.close();
+            }
+        }
+        return contentBuffer.toString();
+    }
+}

+ 84 - 0
mjava-qiwang/src/main/java/com/malk/qiwang/utils/MPGenerator.java

@@ -0,0 +1,84 @@
+package com.malk.qiwang.utils;
+
+import com.baomidou.mybatisplus.generator.FastAutoGenerator;
+import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
+import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Types;
+
+public class MPGenerator {
+//    public static void main(String[] args) {
+//        //可以直接去官方文档上查看
+//        FastAutoGenerator
+//                .create("jdbc:mysql://localhost:3306/invoice_db?useSSL=false&serverTimezone=Asia/Shanghai",
+//                "root", "123456")
+//                .globalConfig(builder -> {
+//                    builder.author("LQY")
+//                            .disableOpenDir()
+//                            .outputDir(System.getProperty("user.dir")+
+//                                    "/mjava-qiwang/src/main/java");
+//                })
+//                .dataSourceConfig(builder ->
+//                        builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
+//                            int typeCode = metaInfo.getJdbcType().TYPE_CODE;
+//                            if (typeCode == Types.SMALLINT) {
+//                                return DbColumnType.INTEGER;
+//                            }
+//                            return typeRegistry.getColumnType(metaInfo);
+//                        }))
+//                .packageConfig(builder -> {
+//                    builder.parent("com.malk.qiwang")
+//                            .controller("Controller")
+//                            .service("Service")
+//                            .serviceImpl("Service.impl")
+//                            .mapper("mapper")
+//                            .entity("entity");
+//                })
+//                .strategyConfig(builder -> {
+//                    builder.addInclude("invoice_library")
+//                            .entityBuilder().enableLombok();
+//                })
+//                .templateEngine(new VelocityTemplateEngine())
+//                .execute();
+//    }
+//    public static void main(String[] args) {
+//        String url = "jdbc:sqlserver://113.45.187.194:1433;"+"databaseName=dingding;"+"encrypt=false;"+"trustServerCertificate=true;";
+//
+//        try (Connection conn = DriverManager.getConnection(url, "hgdd", "hgdd@2025")) {
+//            System.out.println("✅ 连接 SQL Server 成功!");
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+//    }
+
+    public static void main(String[] args) {
+        // MySQL 本地连接配置
+        String url = "jdbc:mysql://47.103.203.2:3306/invoice_db?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
+        String username = "root";
+        String password = "QWhs@12345";
+
+        // 加载 MySQL 驱动(JDBC 4.0 后可以省略,但保留更稳妥)
+        try {
+            Class.forName("com.mysql.cj.jdbc.Driver");
+        } catch (ClassNotFoundException e) {
+            System.out.println("❌ MySQL JDBC 驱动未找到,请检查依赖");
+            e.printStackTrace();
+            return;
+        }
+
+        // 使用 try-with-resources 自动关闭连接
+        try (Connection conn = DriverManager.getConnection(url, username, password)) {
+            System.out.println("✅ 连接本地 MySQL 数据库成功!");
+            System.out.println("数据库: invoice_db");
+            System.out.println("MySQL 版本: " + conn.getMetaData().getDatabaseProductVersion());
+        } catch (SQLException e) {
+            System.out.println("❌ 连接 MySQL 数据库失败!");
+            System.err.println("错误代码: " + e.getErrorCode());
+            System.err.println("错误信息: " + e.getMessage());
+            e.printStackTrace();
+        }
+    }
+}

+ 61 - 0
mjava-qiwang/src/main/resources/application-dev.yml

@@ -0,0 +1,61 @@
+
+server:
+  port: 9092
+  servlet:
+    context-path: /qiwang
+
+enable:
+  scheduling: true
+logging:
+  config: classpath:logback-spring.xml
+  path: /home/server/logs/qiwang
+  level:
+    com.malk.*: debug
+
+# dingtalk
+dingtalk:
+  agentId: 4362063085
+  appKey: dinglh2civttmfufkrha
+  appSecret: 5Zwobht8IX48Q-y9a3E21cY1oswzCycmgxVFTzNZ8IP62SdItL6EzhmFbCik7wH_
+#  appKey: dingknkn9abneqetgc8a
+#  appSecret: 0JnyzqsxqnVrSwP3SiQvZrMGbk0PyUDcl58o1BS2Bro0lVxUYbi_XZ805IJIHUE8
+
+  operator: 16441447913471369 #刘志
+  operatorUnionId: 99iiLnPefWJRBnaze9vB2fQiEiE #刘志
+  spaceId: 660951480
+  downloadPath: D:\\qiwang\\files\\
+#  agentId: 2691784047
+#  appKey: dinghbynhnd2dbgypmsa
+#  appSecret: Kl5Xw8x0TlEIlvcJuUkYZD18UTTShJmfdKrAIpY8oX-Q_tazyUKA28nQh7dG5-mq
+  corpId: dingdf7ab7df12214b0335c2f4657eb6378f
+  aesKey: yNR53hywSt4zJjjHUAcabqupuPJKWzVDbkTx12Q6Ctw
+  token: xpJRw0yOIo
+spring:
+  datasource:
+    url: jdbc:mysql://47.103.203.2:3306/invoice_db?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
+    username: root
+    password: QWhs@12345
+    driver-class-name: com.mysql.cj.jdbc.Driver
+
+mybatis-plus:
+  configuration:
+    #开启驼峰命名自动映射
+    map-underscore-to-camel-case: true
+    #开启日志打印
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+  type-aliases-package: com.malk.qiwang.entity
+  #扫描mapper文件
+  mapper-locations: classpath:mapper/*.xml
+
+#aliwork:
+#  appType: APP_V25MK3XKODKB02UVTGSH
+#  systemToken: IQC66GC1L5TW5HKF6SX645RC4AXG2CFGQOMCMOQ4
+aliwork:
+  appType:
+  systemToken:
+#aliwork:
+#  appType: APP_G1MXVGRR5L6OTZDEME0M
+#  systemToken: PTA66DA1S07X9DRA9EQZ96UUWJTQ2GHXLL5DMY42
+
+
+

+ 60 - 0
mjava-qiwang/src/main/resources/application-prod.yml

@@ -0,0 +1,60 @@
+
+server:
+  port: 9092
+  servlet:
+    context-path: /qiwang
+
+enable:
+  scheduling: true
+logging:
+  config: classpath:logback-spring.xml
+  path: /home/server/logs/qiwang
+  level:
+    com.malk.*: info
+
+# dingtalk
+dingtalk:
+  agentId: 4362063085
+  appKey: dinglh2civttmfufkrha
+  appSecret: 5Zwobht8IX48Q-y9a3E21cY1oswzCycmgxVFTzNZ8IP62SdItL6EzhmFbCik7wH_
+#  appKey: dingknkn9abneqetgc8a
+#  appSecret: 0JnyzqsxqnVrSwP3SiQvZrMGbk0PyUDcl58o1BS2Bro0lVxUYbi_XZ805IJIHUE8
+  operator: 16441447913471369 #刘志
+  operatorUnionId: 99iiLnPefWJRBnaze9vB2fQiEiE #刘志
+  spaceId: 660951480
+  downloadPath: D:\\qiwang\\files\\
+#  agentId: 2691784047
+#  appKey: dinghbynhnd2dbgypmsa
+#  appSecret: Kl5Xw8x0TlEIlvcJuUkYZD18UTTShJmfdKrAIpY8oX-Q_tazyUKA28nQh7dG5-mq
+  corpId: dingdf7ab7df12214b0335c2f4657eb6378f
+  aesKey: yNR53hywSt4zJjjHUAcabqupuPJKWzVDbkTx12Q6Ctw
+  token: xpJRw0yOIo
+spring:
+  datasource:
+    url: jdbc:mysql://47.103.203.2:3306/invoice_db?useSSL=false&characterEncoding=utf8&serverTimezone=Asia/Shanghai
+    username: root
+    password: QWhs@12345
+    driver-class-name: com.mysql.cj.jdbc.Driver
+
+mybatis-plus:
+  configuration:
+    #开启驼峰命名自动映射
+    map-underscore-to-camel-case: true
+    #开启日志打印
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+  type-aliases-package: com.malk.qiwang.entity
+  #扫描mapper文件
+  mapper-locations: classpath:mapper/*.xml
+
+#aliwork:
+#  appType: APP_V25MK3XKODKB02UVTGSH
+#  systemToken: IQC66GC1L5TW5HKF6SX645RC4AXG2CFGQOMCMOQ4
+aliwork:
+  appType: APP_RPH7R3LF3SMXLRDY1ZJW
+  systemToken: 7M866K91D4LVACB4EADAZ5UJG7IN3OGA33WAMNT
+#aliwork:
+#  appType: APP_G1MXVGRR5L6OTZDEME0M
+#  systemToken: PTA66DA1S07X9DRA9EQZ96UUWJTQ2GHXLL5DMY42
+
+
+

+ 15 - 0
mjava-qiwang/src/main/resources/application.yml

@@ -0,0 +1,15 @@
+spring:
+  profiles:
+    active: dev
+  servlet:
+    multipart:
+      max-file-size: 100MB
+      max-request-size: 100MB
+  http:
+    enabled: false
+
+  #  configuration:
+  #    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+  global-config:
+    db-config:
+      id-type: auto

+ 61 - 0
mjava-qiwang/src/main/resources/logback-spring.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false" scan="false" scanPeriod="60 seconds">
+    <springProperty scope="context" name="LOG_HOME" source="logging.path" defaultValue="/home/server/log/"/>
+    <property name="FileNamePattern" value="${LOG_HOME}%d{yyyyMM}/%d{dd}"/>
+
+    <!-- 定义控制台输出 -->
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - [%thread] - %-5level - %logger{50} - %msg%n</pattern>
+        </layout>
+    </appender>
+
+    <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 指定日志文件的名称 -->
+        <!--<file>${FileNamePattern}/info.log</file>-->
+
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${FileNamePattern}/info-%i.log</fileNamePattern>
+            <MaxHistory>30</MaxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <MaxFileSize>30MB</MaxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
+        </layout>
+    </appender>
+
+    <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
+        <discriminator>
+            <Key>processid</Key>
+            <DefaultValue>sys</DefaultValue>
+        </discriminator>
+        <sift>
+            <appender name="FILE-${processid}"
+                      class="ch.qos.logback.core.rolling.RollingFileAppender">
+                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+                    <FileNamePattern>
+                        ${FileNamePattern}/${processid}.log
+                    </FileNamePattern>
+                </rollingPolicy>
+                <layout class="ch.qos.logback.classic.PatternLayout">
+                    <Pattern>
+                        %d{yyyyMMdd:HH:mm:ss.SSS} [%thread] %-5level %msg%n
+                    </Pattern>
+                </layout>
+            </appender>
+        </sift>
+    </appender>
+
+
+    <!-- 日志输出级别 -->
+    <logger name="org.springframework" level="debug"  additivity="false"/>
+    <logger name="com.zitoo.connecter" level="debug"/>
+    <root level="INFO">
+        <appender-ref ref="stdout"/>
+        <appender-ref ref="appLogAppender"/>
+        <appender-ref ref="SIFT"/>
+    </root>
+</configuration>

+ 13 - 0
mjava-qiwang/src/test/java/com/malk/qiwang/MjavaQiwangApplicationTests.java

@@ -0,0 +1,13 @@
+package com.malk.qiwang;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest(classes = MjavaQiwangApplication.class)
+class MjavaQiwangApplicationTests {
+
+    @Test
+    void contextLoads() {
+    }
+
+}

+ 23 - 7
mjava-siku/src/main/java/com/malk/siku/controller/SikuController.java

@@ -95,20 +95,30 @@ public class SikuController {
         return sikuService.checkBudgetAmt(map);
     }*/
 
-    //每刻云票收款核销回调
-    @PostMapping("/receive/callback")
+    //每刻云票收款核销回调
+    @PostMapping("/VERIFICATION_AR/callback")
     public McR callback(@RequestBody Map map){
-        log.info("每刻云票收款核销回调:{}", JSONObject.toJSONString(map));
+        log.info("每刻云票收款核销回调:{}", JSONObject.toJSONString(map));
 
         sikuService.invoiceWriteBack(map);
 
         return McR.success();
     }
 
-    //每刻云票开票回调
-    @PostMapping("/application/callback")
+    //每刻云票应收单回调(开票成功)
+    @PostMapping("/RECEIVABLE_AR/callback")
+    public McR callback9(@RequestBody Map map){
+        log.info("每刻云票应收单完成回调:{}",JSONObject.toJSONString(map));
+
+        sikuService.invoiceWriteBack9(map);
+
+        return McR.success();
+    }
+
+    //每刻云票开票申请单回调(开票失败)
+    @PostMapping("/INVOICE_APPLICATION_AR/callback")
     public McR callback2(@RequestBody Map map){
-        log.info("每刻云票开票回调:{}",JSONObject.toJSONString(map));
+        log.info("每刻云票开票申请单回调:{}",JSONObject.toJSONString(map));
 
         sikuService.invoiceWriteBack2(map);
 
@@ -167,7 +177,7 @@ public class SikuController {
 
     //每刻报销费用报销单完成回调(项目报销单(个人)、项目差旅报销单、打车(企业支付)("是否有项目"为【是】))
     @PostMapping("/reimbursement2/callback")
-    public McR callback8(@RequestBody Map map){
+        public McR callback8(@RequestBody Map map){
         log.info("每刻报销费用报销单完成回调:{}", JSONObject.toJSONString(map));
 
         sikuService.invoiceWriteBack8(map);
@@ -183,6 +193,12 @@ public class SikuController {
         return McR.success();
     }
 
+    //创建/更新企业滴滴项目
+    @PostMapping("/ddProject")
+    public McR ddProject(@RequestBody Map map){
+        return sikuService.ddProject(map);
+    }
+
     @GetMapping("/files/{fileId}")
     public ResponseEntity<Resource> getFileResource(
             @PathVariable String fileId,

+ 2 - 1
mjava-siku/src/main/java/com/malk/siku/schedule/SikuTask.java

@@ -21,7 +21,8 @@ public class SikuTask {
     private SikuTaskService sikuTaskService;
 
     //定时同步借款台账
-    @Scheduled(cron = "0 0 0 * * ?")
+    //早上9点至晚上6点 每小时同步一次
+    @Scheduled(cron = "0 0 9-18 * * ?")
     public void syncMaterial(){
         sikuTaskService.syncLoanManage();
     }

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

@@ -36,4 +36,8 @@ public interface SikuService {
     void invoiceWriteBack8(Map map);
 
     McR saveRepayment(Map map);
+
+    void invoiceWriteBack9(Map map);
+
+    McR ddProject(Map map);
 }

Dosya farkı çok büyük olduğundan ihmal edildi
+ 423 - 127
mjava-siku/src/main/java/com/malk/siku/service/impl/SikuServiceImpl.java


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

@@ -29,6 +29,7 @@ public class SikuTaskServiceImpl implements SikuTaskService {
     @Override
     public void syncLoanManage() {
         try {
+            log.info("开始同步借还款台账");
             //删除宜搭借款台账
             List<List<String>> formInstanceIdListList = new ArrayList<>();//实例id集合,每100条
 

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

@@ -17,14 +17,14 @@ import java.util.*;
 @Slf4j
 public class MkBxUtil {
     //测试环境
-    private final static String appCode = "AP52Y01LHHTAP9";
+    /*private final static String appCode = "AP52Y01LHHTAP9";
     private final static String appSecret = "N4WuERLteAUPaWebnsHy";
-    private final static String host = "ng.maycur.com";
+    private final static String host = "ng.maycur.com";*/
 
     //生产环境
-    /*private final static String appCode = "AP52RG1SCG8S6L";
+    private final static String appCode = "AP52RG1SCG8S6L";
     private final static String appSecret = "YFTbD2MviqUwztBTbMWd";
-    private final static String host = "ng.maycur.com";*/
+    private final static String host = "ng.maycur.com";
 
     private final Object $lock = new Object[0];
 

+ 34 - 4
mjava-siku/src/main/java/com/malk/siku/utils/MkYpUtil.java

@@ -19,14 +19,14 @@ import java.util.Map;
 @Slf4j
 public class MkYpUtil {
     //测试环境
-    private final static String appCode = "AP53EP1SVDS1N9";
+    /*private final static String appCode = "AP53EP1SVDS1N9";
     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 appCode = "AP565SLVOI76UA";
+    private final static String appCode = "AP565SLVOI76UA";
     private final static String appSecret = "sGoMNMSbaw4MWLLbUTtPye2k6trtfIs1";
-    private final static String host = "pms.maycur.com";*/
+    private final static String host = "pms.maycur.com";
 
     private final Object $lock = new Object[0];
 
@@ -117,6 +117,36 @@ public class MkYpUtil {
         return data;
     }
 
+    //已完成发票数据查询接口V2
+    public static Map getInvoiceInfo(String invoiceNumber){
+        Map body = new HashMap();
+        body.put("searchType","INVOICE_VAT");
+        body.put("invoiceNumber",invoiceNumber);
+        body.put("pageSize",1);
+        body.put("pageNum",1);
+
+        Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/ar/openapi/invoice/v2/search", MkYpUtil.initTokenHeader(), null, body,(Map) null));
+
+        log.info("Result:{}",result);
+
+        Map data = UtilMap.getMap(result, "data");
+
+        List<Map> list = UtilMap.getList(data, "list");
+
+        if (!list.isEmpty()){
+            return list.get(0);
+        }else {
+            return null;
+        }
+    }
+
+    //应收单作废接口
+    public static void receivableObsolete(Map body){
+        Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/ar/openapi/receivable_oa/obsolete", MkYpUtil.initTokenHeader(), null, body,(Map) null));
+
+        log.info("Result:{}",result);
+    }
+
     private static String getSecret(String appCode, String appSecret, long timeMillis){
         log.info("time:{}",timeMillis);
 

+ 178 - 0
mjava-siku/src/main/java/com/malk/siku/utils/QyddUtil.java

@@ -0,0 +1,178 @@
+package com.malk.siku.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.malk.utils.UtilHttp;
+import com.malk.utils.UtilMap;
+import com.malk.utils.UtilToken;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+
+/**
+ * 企业滴滴
+ */
+@Slf4j
+public class QyddUtil {
+    private static String client_id = "3295ee5021a0dd6436d18f56e7c761c6";
+    private static String client_secret = "fe5539d17722035cba70a2e6220c43a4";
+    private static String phone = "18857526310";
+    private static String signKey = "038bD3BAb4a25D84dc96";
+    private static String grant_type = "client_credentials";
+    private static String company_id = "1125994055637379";
+    private static String host = "api.es.xiaojukeji.com";
+
+    private static final Long EXPIRES_IN = 1800000L;
+
+    public static String getToken(){
+        String accessToken = "";
+
+        String token = UtilToken.get("invalid-token-qydd");
+
+        if (StringUtils.isNotBlank(token)) {
+            accessToken = token;
+        } else {
+            //企业滴授权认证
+            long timeMillis = System.currentTimeMillis();
+
+            Map<String, Object> body = new HashMap<>();
+            body.put("client_id", client_id);
+            body.put("client_secret", client_secret);
+            body.put("grant_type", grant_type);
+            body.put("phone", phone);
+            body.put("timestamp", timeMillis);
+
+            String sign = genSign(body, signKey, 0);
+
+            System.out.println("sign:"+sign);
+            System.out.println("timestamp:" + timeMillis);
+
+            body.put("sign", sign);
+            Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/river/Auth/authorize", null, null, body));
+
+            log.info("result:{}",result);
+
+            accessToken = UtilMap.getString(result, "access_token");
+
+            UtilToken.put("invalid-token-qydd", accessToken, EXPIRES_IN);
+        }
+
+        return accessToken;
+    }
+
+    public static Map BudgetCenterAdd(Map body){
+        body.put("client_id",client_id);
+        body.put("company_id",company_id);
+        body.put("access_token",getToken());
+        body.put("timestamp",System.currentTimeMillis()/1000);
+        String sign = genSign(body, signKey, 0);
+        body.put("sign",sign);
+        String s = UtilHttp.doPost("https://" + host + "/river/BudgetCenter/add", null, null, body);
+
+        log.info("result:{}",s);
+
+        Map result = (Map)JSONObject.parse(s);
+
+        return result;
+    }
+
+    public static Map BudgetCenterEdit(Map body){
+        body.put("client_id",client_id);
+        body.put("company_id",company_id);
+        body.put("access_token",getToken());
+        body.put("timestamp",System.currentTimeMillis()/1000);
+        String sign = genSign(body, signKey, 0);
+        body.put("sign",sign);
+        String s = UtilHttp.doPost("https://" + host + "/river/BudgetCenter/edit", null, null, body);
+
+        log.info("result:{}",s);
+
+        Map result = (Map)JSONObject.parse(s);
+
+        return result;
+    }
+
+    //java md5算法
+    public static String md5(String plainText) {
+        byte[] secretBytes = null;
+        try {
+            MessageDigest md  = MessageDigest.getInstance("MD5");
+            md.update(plainText.getBytes("utf-8"));
+            secretBytes = md.digest();
+        }
+        catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("no such algorithm!");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+
+
+        String md5code = new BigInteger(1, secretBytes).toString(16);
+        int length = md5code.length();
+        for (int i = 0; i < 32 - length; i++) {
+            md5code = "0" + md5code;
+        }
+        return md5code;
+    }
+    //java sha256算法
+    public static String sha256Hex(String input) {
+        try {
+            // 创建一个MessageDigest实例,并指定使用SHA-256算法
+            MessageDigest digest = MessageDigest.getInstance("SHA-256");
+
+            // 将输入字符串转换为字节数组,并更新摘要
+            byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
+
+            // 将字节数组转换为十六进制字符串
+            StringBuilder hexString = new StringBuilder();
+            for (byte b : hash) {
+                String hex = Integer.toHexString(0xff & b);
+                if (hex.length() == 1) hexString.append('0');
+                hexString.append(hex);
+            }
+
+            return hexString.toString();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String genSign(Map<String, Object> params, String signKey, Integer signMethod) {
+        params.put("sign_key", signKey);
+        String result = "";
+        try {
+            List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(params.entrySet());
+            Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
+                public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
+                    return (o1.getKey()).compareTo(o2.getKey());
+                }
+            });
+            // 构造签名键值对的格式
+            for (Map.Entry<String, Object> item : infoIds) {
+                if (item.getKey() != null || item.getKey() != "") {
+                    String key = item.getKey();
+                    String val = (item.getValue()+"").trim();
+                    if (result == "") {
+                        result += key + "=" + val;
+                    } else {
+                        result += "&" + key + "=" + val;
+                    }
+                }
+            }
+            //System.out.println(result);
+        } catch(Exception e) {
+            throw new RuntimeException("error");
+        }
+        if(signMethod == 1) {
+            return sha256Hex(result);
+        }
+        return md5(result);
+    }
+
+
+}

+ 108 - 4
mjava-siku/src/test/java/com.malk.siku/SkTest.java

@@ -9,6 +9,13 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+
 @Slf4j
 @SpringBootTest
 @RunWith(SpringRunner.class)
@@ -19,12 +26,12 @@ public class SkTest {
     @Test
     public void getSecret(){
         //每刻报销-测试环境
-        String appCode="AP52Y01LHHTAP9";
-        String appSecret="N4WuERLteAUPaWebnsHy";
+        /*String appCode="AP52Y01LHHTAP9";
+        String appSecret="N4WuERLteAUPaWebnsHy";*/
 
         //每刻报销-生产环境
-        /*String appCode="AP52RG1SCG8S6L";
-        String appSecret="YFTbD2MviqUwztBTbMWd";*/
+        String appCode="AP52RG1SCG8S6L";
+        String appSecret="YFTbD2MviqUwztBTbMWd";
 
         //每刻云票-测试环境
         /*String appCode="AP53EP1SVDS1N9";
@@ -54,6 +61,103 @@ public class SkTest {
         sikuTaskService.syncLoanManage();
     }
 
+    //java md5算法
+    public static String md5(String plainText)
+    {
+        byte[] secretBytes = null;
+        try {
+            MessageDigest md  = MessageDigest.getInstance("MD5");
+            md.update(plainText.getBytes("utf-8"));
+            secretBytes = md.digest();
+        }
+        catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("no such algorithm!");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+
+
+        String md5code = new BigInteger(1, secretBytes).toString(16);
+        int length = md5code.length();
+        for (int i = 0; i < 32 - length; i++) {
+            md5code = "0" + md5code;
+        }
+        return md5code;
+    }
+    //java sha256算法
+    public static String sha256Hex(String input) {
+        try {
+            // 创建一个MessageDigest实例,并指定使用SHA-256算法
+            MessageDigest digest = MessageDigest.getInstance("SHA-256");
+
+            // 将输入字符串转换为字节数组,并更新摘要
+            byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
+
+            // 将字节数组转换为十六进制字符串
+            StringBuilder hexString = new StringBuilder();
+            for (byte b : hash) {
+                String hex = Integer.toHexString(0xff & b);
+                if (hex.length() == 1) hexString.append('0');
+                hexString.append(hex);
+            }
+
+            return hexString.toString();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String genSign(HashMap<String, String> params, String signKey, Integer signMethod)
+    {
+        params.put("sign_key", signKey);
+        String result = "";
+        try {
+            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(params.entrySet());
+            Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
+                public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
+                    return (o1.getKey()).toString().compareTo(o2.getKey());
+                }
+            });
+            // 构造签名键值对的格式
+            for (Map.Entry<String, String> item : infoIds) {
+                if (item.getKey() != null || item.getKey() != "") {
+                    String key = item.getKey();
+                    String val = item.getValue().trim();
+                    if (result == "") {
+                        result += key + "=" + val;
+                    } else {
+                        result += "&" + key + "=" + val;
+                    }
+                }
+            }
+            //System.out.println(result);
+        } catch(Exception e) {
+            throw new RuntimeException("error");
+        }
+        if(signMethod == 1) {
+            return sha256Hex(result);
+        }
+        return md5(result);
+    }
+
+    public static void main (String[] args) throws java.lang.Exception {
+        long l = System.currentTimeMillis() / 1000;
+
+        HashMap<String, String> map = new HashMap<String, String>();
+        map.put("client_id", "3295ee5021a0dd6436d18f56e7c761c6");
+        map.put("client_secret", "fe5539d17722035cba70a2e6220c43a4");
+        map.put("grant_type", "client_credentials");
+        map.put("phone", "18857526310");
+        long currentTimeMillis = System.currentTimeMillis();
+        map.put("timestamp", currentTimeMillis+"");
+
+        String signKey = "038bD3BAb4a25D84dc96";
+        Integer signMethod = 0;
+        String sign = genSign(map, signKey, signMethod);
+        System.out.println("sign:"+sign);
+        System.out.println("timestamp:"+currentTimeMillis);
+    }
+
 
 
 

+ 74 - 0
mjava-yzl/pom.xml

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.7.18</version> <!-- 使用最新的稳定版或其他适用版本 -->
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <groupId>com.malk</groupId>
+    <artifactId>mjava-yzl</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.malk</groupId>
+            <artifactId>base</artifactId>
+            <version>2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>yzl</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>

+ 17 - 0
mjava-yzl/src/main/java/com/malk/yzl/YzlApplication.java

@@ -0,0 +1,17 @@
+package com.malk.yzl;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootApplication(scanBasePackages = {"com.malk"})
+@EnableScheduling
+public class YzlApplication {
+    public static void main(String[] args) {
+        try {
+            SpringApplication.run(YzlApplication.class,args);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+}

+ 114 - 0
mjava-yzl/src/main/java/com/malk/yzl/controller/ZzwController.java

@@ -0,0 +1,114 @@
+package com.malk.yzl.controller;
+
+import com.alibaba.fastjson.JSONArray;
+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.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Schedule;
+import com.malk.utils.PublicUtil;
+import com.malk.utils.UtilMap;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+
+import static com.malk.utils.ISO8601Converter.toISO8601;
+
+@RestController
+@Slf4j
+@RequestMapping("/zzw/")
+public class ZzwController {
+
+    @Autowired
+    private YDClient ydClient;
+    @Autowired
+    private YDConf ydConf;
+    @Autowired
+    private DDClient_Schedule ddClientSchedule;
+    @Autowired
+    private DDClient ddClient;
+
+    @PostMapping("/schedule/create")
+    public McR createSchedule(@RequestBody JSONObject jsonObject){
+        log.info("创建日程接口:{}",jsonObject);
+        if(!PublicUtil.isNull(jsonObject,"sId")){
+            return McR.success("已创建日程");
+        }
+        if(PublicUtil.isNull(jsonObject,"summary","start","end","createUid","fid")){
+            return McR.error("201","参数不能为空!");
+        }
+        List<String> userIds=new ArrayList<>();
+        Map<String,Map> userSaveMap=new HashMap<>();
+        Map formdata=ydClient.queryData(YDParam.builder().formInstId(jsonObject.getString("fid")).build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+        List<Map> mapList=ydConf.associationForm(String.valueOf(formdata.get("associationFormField_mn774naw_id")));
+        for (Map map : mapList) {
+            String instanceId=UtilMap.getString(map, "instanceId");
+            Map user=ydClient.queryData(YDParam.builder().formInstId(instanceId).build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+            if(user!=null&&user.containsKey("employeeField_mogigdaq_id")){
+                userIds.addAll(UtilMap.getList(user, "employeeField_mogigdaq_id"));
+                userSaveMap.put(UtilMap.getString(user,"textField_mn6syci3"),UtilMap.map("textField_mowiqmgq, associationFormField_mn774naw, textField_mowj9roq, selectField_mowiqmgr, dateField_mn6vz0hj",
+                        UtilMap.getString(formdata,"serialNumberField_mn6vz0ha"),Arrays.asList(map),UtilMap.getString(user,"textField_mn6syci3"),"未操作",jsonObject.getLong("end")));
+            }
+        }
+        Map map=new HashMap();
+        map.put("summary",jsonObject.getString("summary"));
+        map.put("start",getDate(jsonObject.getLong("start")));
+        map.put("end",getDate(jsonObject.getLong("end")));
+        map.put("userIds", userIds);
+        if(!PublicUtil.isNull(jsonObject,"location")){
+            map.put("location", UtilMap.map("displayName",jsonObject.getString("location")));
+        }
+        String result=ddClientSchedule.eventsSchedule(ddClient.getAccessToken(),jsonObject.getString("createUid"),map);
+        JSONObject obj=JSONObject.parseObject(result);
+        if(obj.containsKey("id")&& !PublicUtil.isNull(obj.get("id"))){
+            log.info("创建成功:{}",obj);
+            ydClient.operateData(YDParam.builder().updateFormDataJson(JSONObject.toJSONString(UtilMap.map("textField_mowj9rop, textField_moxsll4l",obj.getString("id"),"是"))).formInstId(jsonObject.getString("fid")).build(), YDConf.FORM_OPERATION.update);
+            JSONArray attendees =  obj.getJSONArray("attendees");
+            for (int i = 0; i < attendees.size(); i++) {
+                JSONObject attendee=attendees.getJSONObject(i);
+                String name=attendee.getString("displayName");
+                save(obj.getString("id"),name,getStatus(attendee.getString("responseStatus")),userSaveMap.get(name));
+            }
+        }else {
+            log.info("请求失败!{}",obj.getString("message"));
+            return McR.error("201",obj.getString("message"));
+        }
+        return McR.success("已创建日程");
+    }
+
+    private Map getDate(long time){
+        return UtilMap.map("dateTime, timeZone",toISO8601(time, "Asia/Shanghai"),"Asia/Shanghai");
+    }
+
+    private String getStatus(String code){
+        switch (code){
+            case "needsAction": return "未操作";
+            case "accepted": return "已接受";
+            case "declined": return "已拒绝";
+            case "tentative": return "暂定接受";
+        }
+        return "";
+    }
+
+    private void save(String sid,String uname,String status,Map saveMap){
+        if(saveMap==null||saveMap.isEmpty()){
+            saveMap=new HashMap();
+        }
+        if(PublicUtil.isNull(uname)){
+            return;
+        }
+        saveMap.put("textField_mowj9rop", sid);
+        saveMap.put("selectField_mowiqmgr", status);
+        ydClient.operateData(YDParam.builder().formDataJson(JSONObject.toJSONString(saveMap)).formUuid("FORM-CD59959AAB334321A2542558A8285D5BMZ2K").searchCondition(JSONObject.toJSONString(Arrays.asList(
+                ydConf.searchCondition_TextFiled("textField_mowj9rop",sid,"eq"),ydConf.searchCondition_TextFiled("textField_mowj9roq",uname,"eq")
+        ))).build(), YDConf.FORM_OPERATION.upsert);
+    }
+
+}

+ 32 - 0
mjava-yzl/src/main/resources/application-dev.yml

@@ -0,0 +1,32 @@
+server:
+  port: 9000
+  servlet:
+    context-path: /api/yzl
+
+enable:
+  scheduling: false
+logging:
+  config: classpath:logback-spring.xml
+  path: ./log/
+  level:
+    com.malk.*: debug
+
+# dingtalk
+dingtalk:
+  agentId: 4557768490
+  appKey: dingwpwgcqsh1lihphx1
+  appSecret: 0v_GKckYxTO_kcupoifZ8mfcNAI06eUMjvQk8DjikevqlmcdaKBhjr5WqPPP8zZK
+  corpId:
+  aesKey:
+  token:
+# teambition
+teambition:
+  AppID:
+  AppSecret:
+  TenantId:
+  OperatorId:    # 公共账号, 需要有操作权限 [牧语]
+# aliwork
+aliwork:
+  appType: APP_OKUNHYV4085YXZVZM8VX
+  systemToken: NYE66V61MYB409PAGLDNABX1OS0I2OTSUS6NMIU2
+

+ 15 - 0
mjava-yzl/src/main/resources/application.yml

@@ -0,0 +1,15 @@
+spring:
+  profiles:
+    active: dev
+  servlet:
+    multipart:
+      max-file-size: 100MB
+      max-request-size: 100MB
+  http:
+    enabled: false
+
+#  configuration:
+#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+  global-config:
+    db-config:
+      id-type: auto

+ 61 - 0
mjava-yzl/src/main/resources/logback-spring.xml

@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false" scan="false" scanPeriod="60 seconds">
+    <springProperty scope="context" name="LOG_HOME" source="logging.path" defaultValue="/home/server/log/"/>
+    <property name="FileNamePattern" value="${LOG_HOME}%d{yyyyMM}/%d{dd}"/>
+
+    <!-- 定义控制台输出 -->
+    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - [%thread] - %-5level - %logger{50} - %msg%n</pattern>
+        </layout>
+    </appender>
+
+    <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 指定日志文件的名称 -->
+        <!--<file>${FileNamePattern}/info.log</file>-->
+
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${FileNamePattern}/info-%i.log</fileNamePattern>
+            <MaxHistory>30</MaxHistory>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <MaxFileSize>30MB</MaxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+        </rollingPolicy>
+
+        <layout class="ch.qos.logback.classic.PatternLayout">
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
+        </layout>
+    </appender>
+
+    <appender name="SIFT" class="ch.qos.logback.classic.sift.SiftingAppender">
+        <discriminator>
+            <Key>processid</Key>
+            <DefaultValue>sys</DefaultValue>
+        </discriminator>
+        <sift>
+            <appender name="FILE-${processid}"
+                      class="ch.qos.logback.core.rolling.RollingFileAppender">
+                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+                    <FileNamePattern>
+                        ${FileNamePattern}/${processid}.log
+                    </FileNamePattern>
+                </rollingPolicy>
+                <layout class="ch.qos.logback.classic.PatternLayout">
+                    <Pattern>
+                        %d{yyyyMMdd:HH:mm:ss.SSS} [%thread] %-5level %msg%n
+                    </Pattern>
+                </layout>
+            </appender>
+        </sift>
+    </appender>
+
+
+    <!-- 日志输出级别 -->
+    <logger name="org.springframework" level="debug"  additivity="false"/>
+    <logger name="com.malk.connecter" level="debug"/>
+    <root level="INFO">
+        <appender-ref ref="stdout"/>
+        <appender-ref ref="appLogAppender"/>
+        <appender-ref ref="SIFT"/>
+    </root>
+</configuration>

+ 138 - 0
mjava-yzl/src/test/java/com/malk/yzl/JdTest.java

@@ -0,0 +1,138 @@
+package com.malk.yzl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.malk.server.aliwork.YDConf;
+import com.malk.server.aliwork.YDParam;
+import com.malk.server.aliwork.YDSearch;
+import com.malk.server.dingtalk.DDR_New;
+import com.malk.service.aliwork.YDClient;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Schedule;
+import com.malk.utils.PublicUtil;
+import com.malk.utils.UtilMap;
+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;
+
+import java.lang.reflect.Array;
+import java.util.*;
+
+import static com.malk.utils.ISO8601Converter.toISO8601;
+
+@SpringBootTest
+@RunWith(SpringRunner.class)
+public class JdTest {
+
+
+    @Autowired
+    private YDClient ydClient;
+    @Autowired
+    private YDConf ydConf;
+    @Autowired
+    private DDClient_Schedule ddClientSchedule;
+    @Autowired
+    private DDClient ddClient;
+
+
+    @Test
+    public void test(){
+        Map map=new HashMap();
+//        map.put("summary","日程名称");
+        map.put("start",getDate(1778292000000L));
+        map.put("end",getDate(1778295600000L));
+        map.put("userIds", Arrays.asList("153620324221442254"));
+        map.put("location", UtilMap.map("displayName","甬水商务中心"));
+        String result=ddClientSchedule.eventsSchedule(ddClient.getAccessToken(),"tom",map);
+        JSONObject obj=JSONObject.parseObject(result);
+        if(obj.containsKey("id")&& !PublicUtil.isNull(obj.get("id"))){
+
+        }else {
+            System.out.println("请求失败!"+obj.getString("message"));
+        }
+        System.out.println(result);
+
+
+//        ddClientSchedule.queryAttendees(ddClient.getAccessToken(),"h1TfGwHiP1Nj7U3mXWoptkgiEiE","RFZQRU1JN2NNOFpMRTNNckRhL1ZEZz09");
+    }
+
+    private Map getDate(long time){
+        return UtilMap.map("dateTime, timeZone",toISO8601(time, "Asia/Shanghai"),"Asia/Shanghai");
+    }
+
+    @Test
+    public void queryOrder2(){
+        List<String> users=new ArrayList<>();
+        Map<String,Map> userSaveMap=new HashMap<>();
+
+        Map formdata=ydClient.queryData(YDParam.builder().formInstId("FINST-LX966EB1ZTY4NI2SNVIU787ICN2B2R4OUTGOMUE8").build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+        System.out.println(formdata);
+        List<Map> mapList=ydConf.associationForm(String.valueOf(formdata.get("associationFormField_mn774naw_id")));
+        System.out.println(mapList);
+        for (Map map : mapList) {
+            String instanceId=UtilMap.getString(map, "instanceId");
+            Map user=ydClient.queryData(YDParam.builder().formInstId(instanceId).build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+            if(user!=null&&user.containsKey("employeeField_mogigdaq_id")){
+                users.addAll(UtilMap.getList(user, "employeeField_mogigdaq_id"));
+                userSaveMap.put(UtilMap.getString(user,"textField_mn6syci3"),UtilMap.map("textField_mowiqmgq, associationFormField_mn774naw, textField_mowj9roq, selectField_mowiqmgr, dateField_mn6vz0hj",
+                        UtilMap.getString(formdata,"serialNumberField_mn6vz0ha"),Arrays.asList(map),UtilMap.getString(user,"textField_mn6syci3"),"未操作",null));
+            }
+        }
+        save("","","未操作",userSaveMap);
+    }
+
+    private void save(String sid,String uname,String status,Map saveMap){
+        if(saveMap==null||saveMap.isEmpty()){
+            saveMap=new HashMap();
+        }
+        if(PublicUtil.isNull(uname)){
+            return;
+        }
+        saveMap.put("textField_mowj9rop", sid);
+        saveMap.put("selectField_mowiqmgr", status);
+        ydClient.operateData(YDParam.builder().formDataJson(JSONObject.toJSONString(saveMap)).formUuid("FORM-CD59959AAB334321A2542558A8285D5BMZ2K").searchCondition(JSONObject.toJSONString(Arrays.asList(
+                ydConf.searchCondition_TextFiled("textField_mowj9rop",sid,"eq"),ydConf.searchCondition_TextFiled("textField_mowj9roq",uname,"eq")
+        ))).build(), YDConf.FORM_OPERATION.upsert);
+    }
+
+    @Test
+    public void sync(){
+        long now = System.currentTimeMillis();
+        List<Map> dataList = (List<Map>)ydClient.queryData(YDParam.builder().formUuid("FORM-F99DB628726944A18721E5F7B08B196CZ8F3").searchCondition(JSONObject.toJSONString(Arrays.asList(
+                new YDSearch("textField_moxsll4l","是","是否已创建日程",YDSearch.Type.TEXT_FIELD, YDSearch.Operator.EQ),
+                new YDSearch("dateField_mn6vz0hj",now,"截至时间",YDSearch.Type.DATE_FIELD, YDSearch.Operator.GE)
+        ))).build(), YDConf.FORM_QUERY.retrieve_list).getData();
+        for (Map map : dataList) {
+            Map formData=UtilMap.getMap(map,"formData");
+            List userIds=UtilMap.getList(formData,"employeeField_moglrzqk_id");
+            if(userIds==null||userIds.size()<1){
+                continue;
+            }
+            String sid=UtilMap.getString(formData,"textField_mowj9rop");
+            String result=ddClientSchedule.queryAttendees(ddClient.getAccessToken(),String.valueOf(userIds.get(0)),sid);
+            JSONObject obj=JSONObject.parseObject(result);
+            if(obj.containsKey("attendees")&& !PublicUtil.isNull(obj.get("attendees"))){
+                JSONArray attendees =  obj.getJSONArray("attendees");
+                for (int i = 0; i < attendees.size(); i++) {
+                    JSONObject attendee=attendees.getJSONObject(i);
+                    String name=attendee.getString("displayName");
+                    save(sid,name,getStatus(attendee.getString("responseStatus")),null);
+                }
+            }else {
+                System.out.println("请求失败!"+obj.getString("message"));
+            }
+        }
+    }
+
+    private String getStatus(String code){
+        switch (code){
+            case "needsAction": return "未操作";
+            case "accepted": return "已接受";
+            case "declined": return "已拒绝";
+            case "tentative": return "暂定接受";
+        }
+        return "";
+    }
+}

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

@@ -26,4 +26,10 @@ public class ZhongcheController {
     public McR updateTaskDelayInfo(@RequestBody Map map){
         return zhongcheService.updateTaskDelayInfo(map);
     }
+
+    //更新父任务任务类型
+    @PostMapping("/updateParentTaskType")
+    public McR updateParentTaskType(@RequestBody Map map){
+        return zhongcheService.updateParentTaskType(map);
+    }
 }

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

@@ -9,4 +9,8 @@ public interface ZhongcheService {
 
     McR updateTaskDelayInfo(Map map);
 
+    McR updateParentTaskType(Map map);
+
+    void updateLastTaskSfc();
+
 }

+ 164 - 1
mjava-zhongche/src/main/java/com/malk/zhongche/service/impl/ZhongcheServiceImpl.java

@@ -1,6 +1,8 @@
 package com.malk.zhongche.service.impl;
 
 import com.alibaba.fastjson.JSONObject;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
 import com.malk.server.aliwork.YDConf;
 import com.malk.server.aliwork.YDParam;
 import com.malk.server.common.McR;
@@ -9,9 +11,12 @@ 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.UtilHttp;
 import com.malk.utils.UtilMap;
+import com.malk.utils.UtilToken;
 import com.malk.zhongche.service.ZhongcheService;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.util.Strings;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -130,7 +135,7 @@ public class ZhongcheServiceImpl implements ZhongcheService {
         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");//任务类型
+        List<String> questionTypes = UtilMap.getList(formData, "checkboxField_mp28uz2w");//任务类型
 
         Map taskInfo = tbClient.queryTaskDetail(taskId, null, null).get(0);
 
@@ -199,6 +204,94 @@ public class ZhongcheServiceImpl implements ZhongcheService {
         return McR.success();
     }
 
+    @Override
+    public McR updateParentTaskType(Map map) {
+        log.info("更新父任务任务类型:{}",JSONObject.toJSONString(map));
+        String taskId = UtilMap.getString(map, "taskId");
+
+        Map taskInfo = tbClient.queryTaskDetail(taskId, null, null).get(0);
+
+        String parentTaskId = UtilMap.getString(taskInfo, "parentTaskId");
+
+        if (Strings.isNotBlank(parentTaskId)){
+            Map parentTaskInfo = tbClient.queryTaskDetail(parentTaskId, null, null).get(0);
+
+            String projectId = UtilMap.getString(parentTaskInfo, "projectId");
+            String sfcId = UtilMap.getString(parentTaskInfo, "sfcId");
+
+            //获取项目任务类型
+            List<Map> result = searchProjectSfc(projectId);
+
+            String sfcId2 = "";//任务(企业)
+            String sfcId3 = "";//末级任务(企业)
+
+            for (Map resultMap : result) {
+                String name = UtilMap.getString(resultMap, "name");
+                String id = UtilMap.getString(resultMap, "id");
+
+                switch (name){
+                    case "任务(企业)":sfcId2 = id;break;
+                    case "末级任务(企业)":sfcId3 = id;break;
+                    default:break;
+                }
+            }
+
+            //若父任务任务类型为末级任务(企业),更新为任务(企业)
+            if (sfcId.equals(sfcId3)){
+                updateTaskSfc(parentTaskId, sfcId2);
+            }
+        }
+
+        return McR.success();
+    }
+
+    @Override
+    public void updateLastTaskSfc() {
+//        List<String> projectIds = searchProject();
+        List<String> projectIds = new ArrayList<String>(){{add("681b19b2ac9fa0e9bfaa186e");}};
+
+        for (String projectId : projectIds) {
+//            if (!"68d20eee0e4637c8b70445fc".equals(projectId)) continue;
+
+            String sfcId = "";//末级任务(企业)
+            String sfcId2 = "";//任务(企业)
+
+            //获取项目任务类型
+            List<Map> result = searchProjectSfc(projectId);
+            for (Map resultMap : result) {
+                String name = UtilMap.getString(resultMap, "name");
+                String id = UtilMap.getString(resultMap, "id");
+
+                switch (name){
+                    case "任务(企业)":sfcId2 = id;break;
+                    case "末级任务(企业)":sfcId = id;break;
+                    default:break;
+                }
+            }
+
+            //查询项目下所有任务类型为任务(企业)
+//            List<Map> taskList = tbClient.queryProjectTaskList(projectId, UtilMap.map("q, pageSize", "taskLayer = exceptTopLevel AND scenarioId = " + sfcId2, 1000), null);
+            List<Map> taskList = tbClient.queryProjectTaskList(projectId, UtilMap.map("q, pageSize", "scenarioId = " + sfcId2, 1000), null);
+
+            //遍历所有任务,查询末级任务
+            for (Map task : taskList) {
+                String taskId = UtilMap.getString(task, "id");
+
+                //查询该任务是否有子任务
+                List<Map> sonTaskList = tbClient.queryTaskDetail(null, null, taskId);
+
+                if (sonTaskList.isEmpty()){
+                    //更新任务类型为末级任务(企业)
+                    updateTaskSfc(taskId, sfcId);
+                }
+            }
+
+
+
+
+        }
+    }
+
     private Map getRootTask(String taskId) {
         Map taskInfo = tbClient.queryTaskDetail(taskId, null, null).get(0);
 
@@ -235,4 +328,74 @@ public class ZhongcheServiceImpl implements ZhongcheService {
         }
 
     }
+
+    private static final Long EXPIRES_IN = 7200000L;
+
+    private String getAccessToken() {
+            String accessToken = UtilToken.get("invalid-token-teambition");
+            if (StringUtils.isNotBlank(accessToken)) {
+                return accessToken;
+            } else {
+                Algorithm algorithm = Algorithm.HMAC256(tbConf.getAppSecret());
+                long timestamp = System.currentTimeMillis();
+                Date issuedAt = new Date(timestamp);
+                Date expiresAt = new Date(timestamp + EXPIRES_IN);
+                accessToken = JWT.create().withClaim("_appId", tbConf.getAppID()).withIssuedAt(issuedAt).withExpiresAt(expiresAt).sign(algorithm);
+                log.info("响应token, {}", accessToken);
+                UtilToken.put("invalid-token-teambition", accessToken, EXPIRES_IN);
+                return accessToken;
+            }
+
+    }
+
+    private Map<String, String> initHeaderToken() {
+        Map header = new HashMap();
+        header.put("Authorization", getAccessToken());
+        header.put("X-Tenant-Id", tbConf.getTenantId());
+        header.put("X-Tenant-Type", "organization");
+        return header;
+    }
+
+    // 操作者ID: 若是查询, 以操作人视角作为权限
+    private Map<String, String> initHeaderToken(String operatorId) {
+        Map header = initHeaderToken();
+        header.put("x-operator-id", operatorId);
+        return header;
+    }
+
+    //搜索项目任务类型
+    private List<Map> searchProjectSfc(String projectId) {
+        String s = UtilHttp.doGet("https://open.teambition.com/api/v3/project/" + projectId + "/scenariofieldconfig/search", initHeaderToken(), UtilMap.map("objectTypes", "task"));
+        Map result = (Map) JSONObject.parse(s);
+
+        log.info("result:{}",result);
+
+        List<Map> list = UtilMap.getList(result, "result");
+
+        return list;
+    }
+
+    //更新任务的任务类型
+    private Map updateTaskSfc(String taskId, String sfcId) {
+        String s = UtilHttp.doPut("https://open.teambition.com/api/v3/task/" + taskId + "/sfc/update", initHeaderToken(tbConf.getOperatorId()), null, UtilMap.map("sfcId", sfcId));
+
+        Map result = (Map) JSONObject.parse(s);
+
+        log.info("result:{}",result);
+
+        return result;
+    }
+
+    //通过TQL搜索项目
+    private List<String> searchProject() {
+        String s = UtilHttp.doGet("https://open.teambition.com/api/project/search", initHeaderToken(tbConf.getOperatorId()), UtilMap.map("pageSize", 100));
+
+        Map result = (Map) JSONObject.parse(s);
+
+        log.info("result:{}",result);
+
+        List<String> list = UtilMap.getList(result, "result");
+
+        return list;
+    }
 }

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

@@ -1,4 +1,23 @@
 package com.malk.zhongche;
 
+import com.malk.zhongche.service.ZhongcheService;
+import lombok.extern.slf4j.Slf4j;
+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;
+
+@Slf4j
+@SpringBootTest
+@RunWith(SpringRunner.class)
 public class ZcTest {
+    @Autowired
+    private ZhongcheService zhongcheService;
+
+    @Test
+    //刷新所有项目末级任务的任务类型
+    public void test(){
+        zhongcheService.updateLastTaskSfc();
+    }
 }