lfx 1 month ago
parent
commit
1b563f985e

+ 74 - 0
mjava-aosk/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-aosk</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>1.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>aosk</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-aosk/src/main/java/com/malk/aosk/AoskApplication.java

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

+ 54 - 0
mjava-aosk/src/main/java/com/malk/aosk/controller/AoskDingController.java

@@ -0,0 +1,54 @@
+package com.malk.aosk.controller;
+
+import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.malk.server.common.McR;
+import com.malk.service.dingtalk.DDClient;
+import com.malk.service.dingtalk.DDClient_Workflow;
+import com.malk.utils.PublicUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+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.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+@Slf4j
+@RestController
+@RequestMapping("/oa/file/")
+public class AoskDingController {
+
+    @Autowired
+    private DDClient ddClient;
+    @Autowired
+    private DDClient_Workflow ddClientWorkflow;
+
+    @Value("${aosk.oa.path}")
+    private String PATH;
+
+    @PostMapping("save")
+    public McR save(@RequestBody JSONObject param){
+        log.info("param:{}",param);
+        if(PublicUtil.isNull(param,"pid","form","oano","fileId")){
+            return McR.errorNullPointer();
+        }
+        String pid = param.getString("pid");
+        String yearMonth = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMM"));
+        String filePath = PATH+"/"+yearMonth+"/"+param.getString("form")+"/"+param.getString("oano")+"/";
+        JSONArray fileIds = JSONObject.parseArray(param.getString("fileId"));
+        for(int i=0;i<fileIds.size();i++){
+            JSONObject fileInfo=fileIds.getJSONObject(i);
+            String fileId=fileInfo.getString("fileId");
+            String fileName=fileInfo.getString("fileName");
+            String url=ddClientWorkflow.getFileUrl(ddClient.getAccessToken(),pid,fileId);
+            HttpUtil.downloadFile(url,filePath+fileName);
+        }
+        return McR.success();
+    }
+
+}

+ 28 - 0
mjava-aosk/src/main/resources/application-dev.yml

@@ -0,0 +1,28 @@
+server:
+  port: 9001
+  servlet:
+    context-path: /api
+
+enable:
+  scheduling: false
+aosk:
+  oa:
+    path: /home/server/aosk/file/
+logging:
+  config: classpath:logback-spring.xml
+  path: /home/server/aosk/log/
+  level:
+    com.malk.*: debug
+# dingtalk
+dingtalk:
+  agentId: 2691784047
+  appKey: dinghbynhnd2dbgypmsa
+  appSecret: Kl5Xw8x0TlEIlvcJuUkYZD18UTTShJmfdKrAIpY8oX-Q_tazyUKA28nQh7dG5-mq
+  corpId:
+  aesKey:
+  token:
+# aliwork
+aliwork:
+  appType:
+  systemToken:
+

+ 28 - 0
mjava-aosk/src/main/resources/application-pord.yml

@@ -0,0 +1,28 @@
+server:
+  port: 9002
+  servlet:
+    context-path: /api
+
+enable:
+  scheduling: true
+aosk:
+  oa:
+    path: /home/server/aosk/file/
+logging:
+  config: classpath:logback-spring.xml
+  path: /home/server/aosk/log/
+  level:
+    com.malk.*: info
+# dingtalk
+dingtalk:
+  agentId: 3726436077
+  appKey: ding8gscrk6omavamv35
+  appSecret: 83f9h77IMXKIuhcq8jJvKjV8sANGCWZRLRXFaQUEhZL2ZVWhH7FZsIY-jlY8cQux
+  corpId:
+  aesKey:
+  token:
+# aliwork
+aliwork:
+  appType:
+  systemToken:
+

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

@@ -0,0 +1,15 @@
+spring:
+  profiles:
+    active: pord
+  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-aosk/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>

+ 49 - 17
mjava-mc/src/test/java/com/malk/mc/YyYdTest.java

@@ -3,6 +3,7 @@ package com.malk.mc;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.lang.UUID;
 import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.NumberUtil;
 import cn.hutool.poi.excel.ExcelUtil;
 import com.alibaba.excel.EasyExcel;
 import com.alibaba.fastjson.JSON;
@@ -56,7 +57,6 @@ public class YyYdTest {
         MDC.put("MDC_KEY_PID","2001");
         Object obj=ydClient.queryData(YDParam.builder().formInstanceId("95bab7fb-5957-4a8c-9f82-b5b79de0844c").build(), YDConf.FORM_QUERY.retrieve_id);
         System.out.println(JSONObject.toJSONString(obj));
-
     }
 
     @Test
@@ -247,7 +247,7 @@ public class YyYdTest {
     }
 
     /***
-     * 客户档案最终用户回刷
+     * 合同档案最终用户回刷
      */
     @Test
     public void test5(){
@@ -264,37 +264,63 @@ public class YyYdTest {
             for (int i = 0; i < datalist.size(); i++) {
                 Map data=datalist.get(i);
                 log.info("第{}页,第{}条数据:{}",page,i+1,data.get("formInstanceId"));
-//                Map formData=UtilMap.getMap(data,"formData");
+                Map formData=UtilMap.getMap(data,"formData");
 //                if(PublicUtil.isNull(formData,"textField_m7txzt1j")){
 //                    continue;
 //                }
-//                List<Map> table=UtilMap.getList(formData,"tableField_lvuku8m3");
+                List<Map> table=UtilMap.getList(formData,"tableField_lvuku8m3");
 //                List<String> s1=new ArrayList<>(); // 省
 //                List<String> s2=new ArrayList<>(); // 市
 //                List<String> s3=new ArrayList<>(); // 最终用户
 //                List<String> s4=new ArrayList<>(); // 医院等级
+                for (Map item:table) {
+                    String name=UtilMap.getString(item,"selectField_lw4jf0ys");
+                    Map khMap=getData(name);
+                    Map ddMap=JSONObject.parseObject(String.valueOf(khMap.get("addressField_lugff49g")),Map.class);
+                    if(ddMap==null||!ddMap.containsKey("regionText")){
+                        continue;
+                    }
+                    List<Map> regionText=UtilMap.getList(ddMap,"regionText");
+                    item.put("textField_m7lccg50",UtilMap.getString(regionText.get(0),"zh_CN"));
+                    item.put("textField_m7lccg51",UtilMap.getString(regionText.get(1),"zh_CN"));
+                    item.put("textField_m1ajkyj0",UtilMap.getString(khMap,"selectField_lv0b91jn"));
+//                    s1.add(UtilMap.getString(regionText.get(0),"zh_CN"));
+//                    s2.add(UtilMap.getString(regionText.get(1),"zh_CN"));
+//                    s3.add(name);
+//                    s4.add(UtilMap.getString(khMap,"selectField_lv0b91jn"));
+
+                }
+                Map upMap=UtilMap.map("tableField_lvuku8m3",table);
+//                Map upMap=UtilMap.map("tableField_lvuku8m3, textField_m7txzt1j, textField_m7txzt1k, textField_m7txsvfu, textField_m7txsvfv",
+//                        table,String.join("/",s1),String.join("/",s2),String.join("/",s3),String.join("/",s4));
+//                Map upMap=UtilMap.map("textField_m7txzt1j, textField_m7txzt1k, textField_m7txsvfu, textField_m7txsvfv","","","","");
+
+//                List<Map> table=UtilMap.getList(formData,"tableField_lv0mefjq");
 //                for (Map item:table) {
-//                    String name=UtilMap.getString(item,"selectField_lw4jf0ys");
+//                    String name=UtilMap.getString(item,"selectField_lv0mf6ew");
 //                    Map khMap=getData(name);
 //                    Map ddMap=JSONObject.parseObject(String.valueOf(khMap.get("addressField_lugff49g")),Map.class);
 //                    if(ddMap==null||!ddMap.containsKey("regionText")){
 //                        continue;
 //                    }
 //                    List<Map> regionText=UtilMap.getList(ddMap,"regionText");
-//                    item.put("textField_m7lccg50",UtilMap.getString(regionText.get(0),"zh_CN"));
-//                    item.put("textField_m7lccg51",UtilMap.getString(regionText.get(1),"zh_CN"));
+//                    item.put("textField_m8r5vzl2",UtilMap.getString(regionText.get(0),"zh_CN"));
+//                    item.put("textField_m8r5vzl3",UtilMap.getString(regionText.get(1),"zh_CN"));
 //                    item.put("textField_m1ajkyj0",UtilMap.getString(khMap,"selectField_m72yft63"));
-//                    s1.add(UtilMap.getString(regionText.get(0),"zh_CN"));
-//                    s2.add(UtilMap.getString(regionText.get(1),"zh_CN"));
-//                    s3.add(name);
-//                    s4.add(UtilMap.getString(khMap,"selectField_m72yft63"));
-//
+//                    item.put("textField_m8o4kfcf",UtilMap.getString(khMap,"textField_lv0cahf9"));
 //                }
-//                Map upMap=UtilMap.map("tableField_lvuku8m3, textField_m7txzt1j, textField_m7txzt1k, textField_m7txsvfu, textField_m7txsvfv",
-//                        table,String.join("/",s1),String.join("/",s2),String.join("/",s3),String.join("/",s4));
-                Map upMap=UtilMap.map("textField_m7txzt1j, textField_m7txzt1k, textField_m7txsvfu, textField_m7txsvfv","","","","");
+//                formData.putIfAbsent("numberField_ltdyaizp",0);
+//                formData.putIfAbsent("numberField_ltdyaizx",0);
+//                formData.putIfAbsent("numberField_lv3kj7j2",0);
+//                formData.putIfAbsent("numberField_lv0fhmy1",0);
+//                String amt= NumberUtil.sub(UtilMap.getString(formData,"numberField_ltdyaizc"),NumberUtil.add(UtilMap.getString(formData,"numberField_ltdyaizp"),UtilMap.getString(formData,"numberField_ltdyaizx")).toString()).toString();
+//                Map upMap=UtilMap.map("numberField_m7pzn95k, tableField_lv0mefjq",amt,table);
+//                upMap.put("numberField_ltdyaizp",formData.get("numberField_ltdyaizp"));
+//                upMap.put("numberField_ltdyaizx",formData.get("numberField_ltdyaizx"));
+//                upMap.put("numberField_lv3kj7j2",formData.get("numberField_lv3kj7j2"));
+//                upMap.put("numberField_lv0fhmy1",formData.get("numberField_lv0fhmy1"));
                 ydClient.operateData(YDParam.builder().formInstanceId(String.valueOf(data.get("formInstanceId"))).updateFormDataJson(JSONObject.toJSONString(upMap))
-                        .useLatestVersion(false).build(),  YDConf.FORM_OPERATION.update);
+                        .useLatestVersion(true).build(),  YDConf.FORM_OPERATION.update);
             }
         }
     }
@@ -314,6 +340,9 @@ public class YyYdTest {
         }else return new HashMap<>();
     }
 
+    /***
+     * 客户档案省市回刷
+     */
     @Test
     public void test4(){
         MDC.put("MDC_KEY_PID","1013");
@@ -330,7 +359,7 @@ public class YyYdTest {
                 Map data=datalist.get(i);
                 log.info("第{}页,第{}条数据:{}",page,i+1,data.get("formInstanceId"));
                 Map formData=UtilMap.getMap(data,"formData");
-                if(formData.containsKey("textField_m7u2p5n8")){
+                if(!PublicUtil.isNull(formData,"textField_m7u2p5n8")){
                     continue;
                 }
                 Map ddMap=JSONObject.parseObject(String.valueOf(formData.get("addressField_lugff49g")),Map.class);
@@ -346,6 +375,9 @@ public class YyYdTest {
     }
 
 
+    /***
+     * 查询审批记录
+     */
     @Test
     public void test6(){
         MDC.put("MDC_KEY_PID","1013");

+ 1 - 0
mjava-pake/pom.xml

@@ -8,6 +8,7 @@
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <version>2.2.0.RELEASE</version> <!-- 使用最新的稳定版或其他适用版本 -->
+        <relativePath/>
     </parent>
 
     <groupId>com.malk</groupId>

+ 58 - 103
mjava-xzkj/src/main/java/com/malk/xzkj/controller/IVController.java

@@ -38,6 +38,8 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.net.URL;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -162,9 +164,15 @@ public class IVController {
             image = pdfUrlConvertBase64(image);
         }
         List<Map> invoices = (List<Map>) txyInvoice.doRecognizeGeneralInvoice(image).get("MixedInvoiceItems");
+        List<String> nos=new ArrayList<>();
         List<McInvoiceDto> result = invoices.stream().map(item -> {
             Map prop = UtilMap.getMap(UtilMap.getMap(item, "SingleInvoiceInfos"), UtilMap.getString(item, "SubType"));
-
+            // 2025.5.12 去除小计金额,并去除发票编号重复数据
+            String no=UtilMap.getString(prop, "Number");
+            if(nos.contains(no)){
+                return null;
+            }
+            nos.add(no);
             String kind = UtilMap.getString(item, "TypeDescription");
             String invoiceName = UtilMap.getString(item, "SubTypeDescription");
             if (kind.equals("全电发票")) {
@@ -185,9 +193,9 @@ public class IVController {
                     .serial(UtilMap.getString(prop, "Number"))
                     .date(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "Date")))
                     .checkCode(UtilMap.getString(prop, "CheckCode"))
-                    // ppExt: 多明细行时, 优先取值合计 [全电票返回了subTotal字段, 但值为空]
-                    .amount(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "SubTotal", "Total", "Fare")))
-                    .tax(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "SubTax", "Tax")))
+                    // ppExt: 多明细行时, 优先取值合计 [全电票返回了subTotal字段, 但值为空] // 2025.5.12 去除小计金额,并去除发票编号重复数据
+                    .amount(UtilNumber.setBigDecimal(UtilMap.getString_first(prop,  "Total", "Fare"))) // "SubTotal",
+                    .tax(UtilNumber.setBigDecimal(UtilMap.getString_first(prop,  "Tax"))) // "SubTax",
                     .excludingTax(UtilNumber.setBigDecimal(UtilMap.getString(prop, "PretaxAmount")))
                     .buyerName(StringUtils.isBlank(guyuanNameRepalce(UtilMap.getString(prop, "Buyer")))?"":guyuanNameRepalce(UtilMap.getString(prop, "Buyer")))
                     // ppExt: 中央非税未返回税号官方说明: 非税发票理论是没有税号的,图片中属于信用代码
@@ -206,6 +214,10 @@ public class IVController {
                     .constructionCosts(UtilNumber.setBigDecimal((UtilMap.getString(prop, "AirDevelopmentFund"))))   // 行程单: 民航发展基金
                     .build();
             // ppExt: 机票行程单, 行程与座位信息在明细内
+            if("火车票".equals(kind)){
+                invoiceDto.setTax(calculateTax(invoiceDto.getAmount(), new BigDecimal("0.09"), 2));
+                invoiceDto.setExcludingTax(invoiceDto.getAmount().subtract(invoiceDto.getTax()));
+            }
             if ("机票行程单".equals(item.get("TypeDescription"))) {
                 Map flight = (Map) UtilMap.getList(prop, "FlightItems").get(0);
                 invoiceDto.setDepartureTime(UtilString.replaceDateZH_cn(UtilMap.getString(item, "DateGetOn")) + " " + UtilMap.getString(prop, "TimeGetOn"));
@@ -218,89 +230,25 @@ public class IVController {
                 invoiceDto.setDepartureTime(UtilMap.getString(prop, "TimeGetOn") + " ~ " + UtilMap.getString(prop, "TimeGetOff"));
             }
             return invoiceDto;
-        }).collect(Collectors.toList());
+        }).filter(item -> item!=null).collect(Collectors.toList());
         return McR.success(McInvoiceDto.formatResponse(result));
     }
 
     /**
-     * 混票识别 [旧版本, 已废弃]
+     * 计算税额方法
+     * @param faceValue 票面金额
+     * @param taxRate 税率(如9%传0.09)
+     * @param scale 小数位数
+     * @return 税额
      */
-    @PostMapping("invoice-iv")
-    McR invoice_iv(@RequestBody Map<String, String> data) throws TencentCloudSDKException {
-
-        McException.assertParamException_Null(data, "url");
-        String image = ydClient.convertTemporaryUrl(data.get("url"),0);
-        log.info("混票识别, 免登地址, {}", image);
-        // 非PDF, 且内存大于3M, 压缩后上传
-        if (UtilMap.getFloat(data, "size") > 3.0f && !UtilMap.getBoolean(data, "isPdf")) {
-            image = imageUrlConvertBase64(image);
+    public static BigDecimal calculateTax(BigDecimal faceValue, BigDecimal taxRate, int scale) {
+        if (faceValue == null || taxRate == null) {
+            throw new IllegalArgumentException("参数不能为null");
         }
-        if (UtilMap.getFloat(data, "size") > 6.0f && UtilMap.getBoolean(data, "isPdf")) {
-            image = pdfUrlConvertBase64(image);
-        }
-        // ppExt: 通用字段定义
-        List<Map> invoices = (List<Map>) txyInvoice.doMixedInvoiceOCR(image).get("MixedInvoiceItems");
-        List<McInvoiceDto> result = invoices.stream().map(item -> {
-            String kind = TXYConf.TYPE_INVOICE.get(item.get("Type").toString());
-            List<Map<String, String>> infos = (List<Map<String, String>>) item.get("SingleInvoiceInfos");
-
-            McInvoiceDto.assertSuccess(item, kind); // 响应断言
-            String invoiceName = findValue(infos, "发票名称");
-            if (kind.equals("全电发票")) {
-                kind = invoiceName.contains("增值税专用发票") ? "全电专用发票" : "全电普通发票";
-            }
-            if (kind.equals("增值税发票")) {
-                kind = invoiceName.contains("增值税专用发票") ? "增值税专用发票" : "增值税普通发票";
-                if (invoiceName.contains("增值税电子")) {
-                    kind = invoiceName.contains("专用发票") ? "增值税电子专用发票" : "增值税电子普通发票";
-                }
-            }
-            McInvoiceDto invoiceDto = McInvoiceDto.builder()
-                    .name(invoiceName)
-                    .kindName(kind)
-                    .kind(McInvoiceKind.getKindCode(kind))
-                    .code(findValue(infos, "发票代码", "票据代码")) // 发票, 非税发票
-                    // 储存唯一ID [发票, 火车票, 行程单]
-                    .serial(findValue(infos, "发票号码", "编号", "电子客票号码", "票据号码").replace("No", "")) // 发票, 非税发票
-                    .date(findValue(infos, "开票日期").replace("年", "-").replace("月", "-").replace("日", ""))
-                    .checkCode(findValue(infos, "校验码"))
-                    .amount(UtilNumber.replaceCurrencyCHYToDecimal(findValue(infos, "小写金额", "价税合计(小写)", "合计金额", "票价", "金额"))) // 发票, 全电票, 行程单, 火车票, 过路过桥费
-                    .excludingTax(UtilNumber.replaceCurrencyCHYToDecimal(findValue(infos, "合计金额", "金额", "票价", "小写金额"))) // [ppExt: 多明细行时, 优先取值合计] 行程单, 火车票, 定额发票
-                    .tax(UtilNumber.replaceCurrencyCHYToDecimal(findValue(infos, "合计税额"))) // 增值税发票
-                    .buyerName(guyuanNameRepalce(findValue(infos, "购买方名称", "交款人"))) // 发票, 非税发票
-                    .buyerTaxId(findValue(infos, "购买方识别号", "购买方统一社会信用代码/纳税人识别号", "交款人统一社会信用代码")) // 发票, 全电票, 非税发票
-                    .sellerName(guyuanNameRepalce(findValue(infos, "销售方名称", "填开单位"))) // 行程单
-                    .sellerTaxId(findValue(infos, "销售方识别号", "销售方统一社会信用代码/纳税人识别号", "销售单位代号")) // 发票, 全电票, 行程单
-                    .passengerName(findValue(infos, "旅客姓名", "姓名")) // 行程单, 火车票
-                    .seatType(findValue(infos, "座位等级", "席别")) // 行程单, 火车票
-                    .departurePort(findValue(infos, "始发地", "出发站", "入口")) // 行程单, 火车票, 过路过桥费
-                    .arrivePort(findValue(infos, "目的地", "到达站", "出口")) // 行程单, 火车票, 过路过桥费
-                    .trainNo(findValue(infos, "航班号", "车次", "车牌号")) // 行程单, 火车票, 出租车
-                    .insuranceCosts(UtilNumber.setBigDecimal((findValue(infos, "保险费")))) // 行程单
-                    .fuelCosts(UtilNumber.setBigDecimal((findValue(infos, "燃油附加费")))) // 行程单
-                    .constructionCosts(UtilNumber.setBigDecimal((findValue(infos, "民航发展基金")))) // 行程单
-                    .build();
-            // 价格不一致情况下, 通过合计返回
-            if (!UtilNumber.equalBigDecimal(invoiceDto.getAmount(), invoiceDto.getExcludingTax().add(invoiceDto.getTax()))) {
-                invoiceDto.setAmount(invoiceDto.getExcludingTax().add(invoiceDto.getTax()));
-            }
-            // 机票行程单
-            if (kind.equals(McInvoiceKind.JP.getDesc())) {
-                String date = findValue(infos, "日期").replace("年", "-").replace("月", "-").replace("日", " ");
-                invoiceDto.setDepartureTime(date + " " + findValue(infos, "时间"));
-            }
-            // 火车票
-            if (kind.equals(McInvoiceKind.HC.getDesc())) {
-                invoiceDto.setDepartureTime(findValue(infos, "出发时间").replace("年", "-").replace("月", "-").replace("日", " "));
-            }
-            // 出租车
-            if (kind.equals(McInvoiceKind.CZC.getDesc())) {
-                String date = findValue(infos, "日期").replace("年", "-").replace("月", "-").replace("日", " ");
-                invoiceDto.setDepartureTime(date + " " + findValue(infos, "上车"));
-            }
-            return invoiceDto;
-        }).collect(Collectors.toList());
-        return McR.success(McInvoiceDto.formatResponse(result));
+        BigDecimal denominator = BigDecimal.ONE.add(taxRate);
+        return faceValue.divide(denominator, scale, RoundingMode.HALF_UP)
+                .multiply(taxRate)
+                .setScale(scale, RoundingMode.HALF_UP);
     }
 
     /**
@@ -328,30 +276,37 @@ public class IVController {
             if (idList.size() > 0) {
                 McException.exceptionAccess(serial + "已存在, 请勿重复提交!");
             }
+            List<String> yzType=Arrays.asList("增值税普通发票",
+                    "增值税专用发票",
+                    "增值税电子专用发票",
+                    "增值税电子普通发票",
+                    "全电普通发票",
+                    "全电专用发票");
             // prd 仅仅识别 报销 用途的发票
-            if (dto.getType().contains("报销") && !dto.getKindName().contains("车票") && !dto.getKindName().contains("车发票") && !dto.getKindName().contains("定额发票")) {
-                String serialTips = serial + "有疑问";
-                try {
-                    // ppExt: 识别与验真后抬头对比 [全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值]
-                    Map rsp = txyInvoice.doVatInvoiceVerifyNew(dto.getKindName(), dto.getCode(), invoiceNo, dto.getDate(), String.valueOf(dto.getAmount()), dto.getCheckCode(), String.valueOf(dto.getExcludingTax()), serialTips);
-                    Map invoice = (Map) rsp.get("Invoice");
-                    McException.assertAccessException(!dto.getBuyerName().equals(guyuanNameRepalce(invoice.get("BuyerName").toString())), serialTips + ", 购买方名称不匹配!");
-                    McException.assertAccessException(!dto.getBuyerTaxId().equals(invoice.get("BuyerTaxCode")), serialTips + ", 购买方税号不匹配!");
-                    McException.assertAccessException(!dto.getSellerName().equals(guyuanNameRepalce(invoice.get("SellerName").toString())), serialTips + ", 销售方名称不匹配!");
-                    McException.assertAccessException(!dto.getSellerTaxId().equals(invoice.get("SellerTaxCode")), serialTips + ", 销售方税号不匹配!");
-                } catch (TencentCloudSDKException e) {
-                    log.error(e.getMessage(), e);
-                    // prd: 上传发票为假发票时,提示:该发票有疑问,请联系财务人员
-                    String message = e.getMessage();
-                    // ppExt: 已经是新版本接口, 过滤提示 [官方答复: 提示不会检测您是否使用的是新版,所有的用户都会提示, 忽略即可]
-                    if (message.contains("温馨提示")) {
-                        message = message.split("温馨提示")[0];
-                    }
-                    if (message.contains("发票不存在")) {
-                        message = "有疑问,请联系财务人员";
-                    }
-                    McException.exceptionAccess(serial + message);
+            if(!dto.getType().contains("报销")||!yzType.contains(dto.getKindName())){
+                return;
+            }
+            String serialTips = serial + "有疑问";
+            try {
+                // ppExt: 识别与验真后抬头对比 [全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值]
+                Map rsp = txyInvoice.doVatInvoiceVerifyNew(dto.getKindName(), dto.getCode(), invoiceNo, dto.getDate(), String.valueOf(dto.getAmount()), dto.getCheckCode(), String.valueOf(dto.getExcludingTax()), serialTips,dto.getSellerTaxId());
+                Map invoice = (Map) rsp.get("Invoice");
+                McException.assertAccessException(!dto.getBuyerName().equals(guyuanNameRepalce(invoice.get("BuyerName").toString())), serialTips + ", 购买方名称不匹配!");
+                McException.assertAccessException(!dto.getBuyerTaxId().equals(invoice.get("BuyerTaxCode")), serialTips + ", 购买方税号不匹配!");
+                McException.assertAccessException(!dto.getSellerName().equals(guyuanNameRepalce(invoice.get("SellerName").toString())), serialTips + ", 销售方名称不匹配!");
+                McException.assertAccessException(!dto.getSellerTaxId().equals(invoice.get("SellerTaxCode")), serialTips + ", 销售方税号不匹配!");
+            } catch (TencentCloudSDKException e) {
+                log.error(e.getMessage(), e);
+                // prd: 上传发票为假发票时,提示:该发票有疑问,请联系财务人员
+                String message = e.getMessage();
+                // ppExt: 已经是新版本接口, 过滤提示 [官方答复: 提示不会检测您是否使用的是新版,所有的用户都会提示, 忽略即可]
+                if (message.contains("温馨提示")) {
+                    message = message.split("温馨提示")[0];
+                }
+                if (message.contains("发票不存在")) {
+                    message = "有疑问,请联系财务人员";
                 }
+                McException.exceptionAccess(serial + message);
             }
         }));
         return McR.success();

+ 2 - 1
mjava-xzkj/src/main/java/com/malk/xzkj/service/TXYInvoice.java

@@ -28,8 +28,9 @@ public interface TXYInvoice {
      * @param invoiceCode         票代码(10或12 位),全电发票为空
      * @param checkCode           校验码后 6 位,增值税普通发票、增值税电子普通发票、增值税普通发票(卷式)、增值税电子普通发票(通行费)时必填;
      * @param excludingTax/amount 不含税金额,增值税专用发票、增值税电子专用发票、机动车销售统一发票、二手车销售统一发票、区块链发票时必填; 全电发票为价税合计(含税金额)
+     *        sellerTaxCode  销方税号,通用机打电子发票必填,区块链发票时必填
      */
-    Map doVatInvoiceVerifyNew(String invoiceKind, String invoiceCode, String invoiceNo, String invoiceDate, String amount, String checkCode, String excludingTax, String tips) throws TencentCloudSDKException;
+    Map doVatInvoiceVerifyNew(String invoiceKind, String invoiceCode, String invoiceNo, String invoiceDate, String amount, String checkCode, String excludingTax, String tips,String sellerTaxCode) throws TencentCloudSDKException;
 
     /**
      * 名片识别

+ 2 - 1
mjava-xzkj/src/main/java/com/malk/xzkj/service/impl/TXYImplInvoice.java

@@ -93,7 +93,7 @@ public class TXYImplInvoice implements TXYInvoice {
      * @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 {
+    public Map doVatInvoiceVerifyNew(String invoiceKind, String invoiceCode, String invoiceNo, String invoiceDate, String amount, String checkCode, String excludingTax, String tips,String sellerTaxCode) throws TencentCloudSDKException {
         Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
         ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
         OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);
@@ -118,6 +118,7 @@ public class TXYImplInvoice implements TXYInvoice {
             req.setAmount(null);
             req.setAmount(excludingTax);
         }
+        req.setSellerTaxCode(sellerTaxCode);
         log.debug("发票验真, {}, {}", invoiceKind, JSON.toJSONString(req));
         VatInvoiceVerifyNewResponse resp = client.VatInvoiceVerifyNew(req);
         String result = VatInvoiceVerifyNewResponse.toJsonString(resp);