QiWangController.java 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963
  1. package com.malk.qiwang.Controller;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.fasterxml.jackson.databind.ObjectMapper;
  6. import com.malk.qiwang.Service.QiWangService;
  7. import com.malk.qiwang.Service.TXYInvoice;
  8. import com.malk.qiwang.entity.CompanyTitle;
  9. import com.malk.qiwang.entity.InvoiceLibrary;
  10. import com.malk.qiwang.model.McInvoiceDto;
  11. import com.malk.server.aliwork.YDConf;
  12. import com.malk.server.aliwork.YDParam;
  13. import com.malk.server.common.FilePath;
  14. import com.malk.server.common.McException;
  15. import com.malk.server.common.McR;
  16. import com.malk.server.dingtalk.DDR_New;
  17. import com.malk.service.aliwork.YDClient;
  18. import com.malk.service.dingtalk.DDClient;
  19. import com.malk.service.dingtalk.DDClient_Contacts;
  20. import com.malk.service.dingtalk.DDClient_Workflow;
  21. import com.malk.utils.*;
  22. import com.spire.pdf.PdfCompressionLevel;
  23. import com.spire.pdf.PdfDocument;
  24. import com.spire.pdf.PdfPageBase;
  25. import com.spire.pdf.exporting.PdfImageInfo;
  26. import com.spire.pdf.graphics.PdfBitmap;
  27. import com.tencentcloudapi.common.Credential;
  28. import com.tencentcloudapi.common.exception.TencentCloudSDKException;
  29. import lombok.SneakyThrows;
  30. import lombok.extern.slf4j.Slf4j;
  31. import net.coobird.thumbnailator.Thumbnails;
  32. import org.apache.commons.lang3.StringUtils;
  33. import org.apache.poi.util.IOUtils;
  34. import org.springframework.beans.factory.annotation.Autowired;
  35. import org.springframework.beans.factory.annotation.Value;
  36. import org.springframework.core.io.Resource;
  37. import org.springframework.core.io.UrlResource;
  38. import org.springframework.http.HttpHeaders;
  39. import org.springframework.http.MediaType;
  40. import org.springframework.http.ResponseEntity;
  41. import org.springframework.web.bind.annotation.*;
  42. import java.io.*;
  43. import java.math.BigDecimal;
  44. import java.net.HttpURLConnection;
  45. import java.net.URL;
  46. import java.nio.file.Files;
  47. import java.nio.file.Path;
  48. import java.nio.file.Paths;
  49. import java.time.LocalDate;
  50. import java.time.LocalDateTime;
  51. import java.util.*;
  52. import java.util.stream.Collectors;
  53. @RestController
  54. @Slf4j
  55. @RequestMapping("/qw")
  56. public class QiWangController {
  57. @Autowired
  58. private QiWangService qiWangService;
  59. @Autowired
  60. private DDClient ddClient;
  61. @Autowired
  62. private YDClient ydClient;
  63. @Autowired
  64. private TXYInvoice txyInvoice;
  65. @Value("${dingtalk.operator}")
  66. private String operator;
  67. @Value("${dingtalk.downloadPath}")
  68. private String downloadPath;
  69. @Autowired
  70. private DDClient_Workflow ddClientWorkflow ;
  71. @Autowired
  72. private DDClient_Contacts ddClient_contacts;
  73. private static final String bdurl = "D://qiwang//files//";
  74. private static final String url = "http://47.103.203.2:9092/qiwang/";
  75. // private static final String bdurl = "C:\\Users\\EDY\\Desktop\\项目\\琦王\\files\\";
  76. //private static final String url = "http://4784d4b1.r39.cpolar.top/qiwang/";
  77. @PostMapping("/test")
  78. public McR test(@RequestBody Map map) {
  79. log.info("map:{}", map);
  80. String processInstanceId = UtilMap.getString(map, "processInstanceId");
  81. // 获取审批实例信息
  82. Map processInstance = ddClientWorkflow.getProcessInstanceId(
  83. ddClient.getAccessToken(), processInstanceId);
  84. // System.out.println("processInstance====" + processInstance);
  85. String businessId = (String) processInstance.get("businessId");
  86. System.out.println(businessId);
  87. //
  88. // if (Objects.nonNull(processInstance)) {
  89. // List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
  90. // System.out.println("formComponentValues====" + formComponentValues);
  91. // 存储所有处理结果
  92. // List<Object> allResults = new ArrayList<>();
  93. //
  94. // // 遍历所有表单组件
  95. // for (Map formComponentValue : formComponentValues) {
  96. // String id = String.valueOf(formComponentValue.get("id"));
  97. //
  98. // // 查找 TableField_1A1CDMEN8DDS0 组件
  99. // if ("TableField_1A1CDMEN8DDS0".equals(id)) {
  100. // String tableFieldValue = String.valueOf(formComponentValue.get("value"));
  101. // System.out.println("原始value值: " + tableFieldValue);
  102. // }
  103. //
  104. // try {
  105. // if ("DDAttachment_OF8QX7XQWWW0".equals(id)) {
  106. // String attachmentListStr = UtilMap.getString(formComponentValue, "value");
  107. // List<Map> attachmentList = (List<Map>) JSONObject.parse(attachmentListStr);
  108. //
  109. // for (Map attachment : attachmentList) {
  110. //
  111. // String fileId = UtilMap.getString(attachment, "fileId");
  112. // String fileType = UtilMap.getString(attachment, "fileType");
  113. // String fileName = UtilMap.getString(attachment, "fileName");
  114. //
  115. // //下载钉盘文件
  116. // String filePath = downloadPath + fileId + "." + fileType;
  117. // downloadDdFile(processInstanceId, fileId, filePath);
  118. // String hz = "qw/files/" + fileId + "." + fileType;
  119. // Map fileMap = new HashMap();
  120. // fileMap.put("url", url + hz);
  121. //
  122. // // 处理每个附件并收集结果
  123. // McR<Object> result = processMixedInvoice(fileMap);
  124. // allResults.add(result.getData());
  125. //// allResults.add(fileMap);
  126. // }
  127. // }
  128. // } catch (Exception e) {
  129. // log.error("解析 TableField 数据失败", e);
  130. // return McR.error("300", "解析数据失败");
  131. // }
  132. // }
  133. // 处理完所有附件后,汇总结果
  134. // return McR.success() ;
  135. //
  136. // }
  137. return McR.success();
  138. }
  139. @PostMapping ("/test3")
  140. public McR test3(@RequestBody Map map) {
  141. log.info("map:{}", map);
  142. String processInstanceId = UtilMap.getString(map, "processInstanceId");
  143. // 获取审批实例信息
  144. Map processInstance = ddClientWorkflow.getProcessInstanceId(ddClient.getAccessToken(), processInstanceId);
  145. System.out.println("processInstance====" + processInstance);
  146. if (Objects.nonNull(processInstance)) {
  147. List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
  148. System.out.println("formComponentValues====" + formComponentValues);
  149. // 查找 TableField_1A1CDMEN8DDS0 组件
  150. for (Map formComponentValue : formComponentValues) {
  151. String id = String.valueOf(formComponentValue.get("id"));
  152. if ("TableField_1A1CDMEN8DDS0".equals(id)) {
  153. String tableFieldValue = String.valueOf(formComponentValue.get("value"));
  154. System.out.println("原始value值: " + tableFieldValue);
  155. try {
  156. // 解析子表数据
  157. List<Map> tableRows = (List<Map>) JSONObject.parse(tableFieldValue);
  158. // 收集所有行的结果
  159. List<Object> allResults = new ArrayList<>();
  160. // 遍历子表的每一行
  161. for (Map row : tableRows) {
  162. List<Map> rowValues = (List<Map>) row.get("rowValue");
  163. // 存储当前行的"是否有发票"状态和附件
  164. String hasInvoice = null;
  165. List<Map> attachmentList = null;
  166. // 先收集这一行的字段值
  167. for (Map rowItem : rowValues) {
  168. String key = String.valueOf(rowItem.get("key"));
  169. if ("DDSelectField_1ORUK0KIM5D6O".equals(key)) {
  170. hasInvoice = String.valueOf(rowItem.get("value"));
  171. }
  172. if ("DDAttachment_Z02OGR5QL8U8".equals(key)) {
  173. attachmentList = (List<Map>) rowItem.get("value");
  174. }
  175. }
  176. // 只有当"是否有发票"为"是"且有附件时,才处理
  177. if ("是".equals(hasInvoice) && attachmentList != null && !attachmentList.isEmpty()) {
  178. // 只处理这一行的第一个附件
  179. Map attachment = attachmentList.get(0);
  180. System.out.println("fileName: " + UtilMap.getString(attachment, "fileName"));
  181. System.out.println("fileId: " + UtilMap.getString(attachment, "fileId"));
  182. String fileId = UtilMap.getString(attachment, "fileId");
  183. String fileType = UtilMap.getString(attachment, "fileType");
  184. String fileName = UtilMap.getString(attachment, "fileName");
  185. // 下载钉盘文件
  186. String filePath = downloadPath + fileId + "." + fileType;
  187. downloadDdFile(processInstanceId, fileId, filePath);
  188. String hz = "qw/files/" + fileId + "." + fileType;
  189. Map fileMap = new HashMap();
  190. fileMap.put("url", url + hz);
  191. // 处理发票识别
  192. // McR<Object> result = processMixedInvoice(fileMap);
  193. allResults.add(fileMap);
  194. } else {
  195. // 如果这一行不符合条件,可以添加null或跳过
  196. // allResults.add(null); // 如果需要保持行数对应
  197. }
  198. }
  199. // 所有行处理完成后统一返回
  200. return McR.success(allResults);
  201. } catch (Exception e) {
  202. log.error("解析子表数据失败", e);
  203. return McR.error("300", "解析数据失败");
  204. }
  205. }
  206. }
  207. }
  208. return McR.success();
  209. }
  210. @PostMapping("/test4")
  211. public McR test4(@RequestBody Map map) {
  212. log.info("map:{}", map);
  213. String processInstanceId = UtilMap.getString(map, "processInstanceId");
  214. // 获取审批实例信息
  215. Map processInstance = ddClientWorkflow.getProcessInstanceId(ddClient.getAccessToken(), processInstanceId);
  216. // System.out.println("processInstance====" + processInstance);
  217. String userId = (String) processInstance.get("originatorUserId");
  218. System.out.println(userId);
  219. if (Objects.nonNull(processInstance)) {
  220. List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
  221. System.out.println("formComponentValues====" + formComponentValues);
  222. // 存储主表的 zt 和 je 值
  223. String zt = "是";
  224. String mainJe = null;
  225. // 先遍历收集主表字段值
  226. for (Map formComponentValue : formComponentValues) {
  227. String id = String.valueOf(formComponentValue.get("id"));
  228. if ("DDSelectField_4SITXLYUEO80".equals(id)) {
  229. zt = String.valueOf(formComponentValue.get("value"));
  230. }
  231. if ("MoneyField_3QZLY8BD3780".equals(id)) {
  232. mainJe = String.valueOf(formComponentValue.get("value"));
  233. }
  234. }
  235. // 判断主表状态
  236. if ("否".equals(zt)) {
  237. // 当为"否"时,直接返回 je 字段值
  238. Map<String, Object> result = new HashMap<>();
  239. result.put("je", mainJe);
  240. result.put("status", "否");
  241. Map body = new HashMap<>();
  242. body.put("processInstanceId",processInstanceId);
  243. body.put("text", result);
  244. body.put("commentUserId",userId);
  245. // body.put("file",fileMap);
  246. //
  247. String re =UtilHttp.doPost("https://api.dingtalk.com/v1.0/workflow/processInstances/comments",ddClient.initTokenHeader(),null,body);
  248. return McR.success(result);
  249. }
  250. // 当为"是"时,继续处理子表附件
  251. if ("是".equals(zt)) {
  252. // 查找 TableField_1A1CDMEN8DDS0 组件
  253. for (Map formComponentValue : formComponentValues) {
  254. String id = String.valueOf(formComponentValue.get("id"));
  255. if ("TableField_1A1CDMEN8DDS0".equals(id)) {
  256. String tableFieldValue = String.valueOf(formComponentValue.get("value"));
  257. System.out.println("原始value值: " + tableFieldValue);
  258. try {
  259. // 解析子表数据
  260. List<Map> tableRows = (List<Map>) JSONObject.parse(tableFieldValue);
  261. // 收集所有发票识别结果
  262. List<Object> allResults = new ArrayList<>();
  263. // 遍历子表的每一行
  264. for (Map row : tableRows) {
  265. List<Map> rowValues = (List<Map>) row.get("rowValue");
  266. // 先检查这一行的"是否有发票"字段值
  267. String hasInvoice = null;
  268. List<Map> attachmentList = null;
  269. for (Map rowItem : rowValues) {
  270. String key = String.valueOf(rowItem.get("key"));
  271. // 获取"是否有发票"字段的值
  272. if ("DDSelectField_1ORUK0KIM5D6O".equals(key)) {
  273. hasInvoice = String.valueOf(rowItem.get("value"));
  274. }
  275. // 获取附件字段
  276. if ("DDAttachment_Z02OGR5QL8U8".equals(key)) {
  277. attachmentList = (List<Map>) rowItem.get("value");
  278. }
  279. }
  280. // 只有当"是否有发票"为"是"时,才处理附件
  281. if ("是".equals(hasInvoice) && attachmentList != null && !attachmentList.isEmpty()) {
  282. // 遍历这一行的所有附件
  283. for (Map attachment : attachmentList) {
  284. System.out.println("fileName: " + UtilMap.getString(attachment, "fileName"));
  285. System.out.println("fileId: " + UtilMap.getString(attachment, "fileId"));
  286. String fileId = UtilMap.getString(attachment, "fileId");
  287. String fileType = UtilMap.getString(attachment, "fileType");
  288. String fileName = UtilMap.getString(attachment, "fileName");
  289. // 下载钉盘文件
  290. String filePath = downloadPath + fileId + "." + fileType;
  291. downloadDdFile(processInstanceId, fileId, filePath);
  292. String hz = "qw/files/" + fileId + "." + fileType;
  293. Map fileMap = new HashMap();
  294. fileMap.put("url", url + hz);
  295. // 处理发票识别并收集结果
  296. McR<Object> result = processMixedInvoice(fileMap);
  297. allResults.add(result.getData());
  298. }
  299. }
  300. }
  301. Map body = new HashMap<>();
  302. body.put("processInstanceId",processInstanceId);
  303. body.put("text", JSON.toJSONString(allResults));
  304. body.put("commentUserId",userId);
  305. String re =UtilHttp.doPost("https://api.dingtalk.com/v1.0/workflow/processInstances/comments",ddClient.initTokenHeader(),null,body);
  306. // 所有附件处理完成后统一返回
  307. return McR.success(allResults);
  308. } catch (Exception e) {
  309. log.error("解析子表数据失败", e);
  310. return McR.error("300", "解析数据失败");
  311. }
  312. }
  313. }
  314. }
  315. }
  316. return McR.success();
  317. }
  318. @PostMapping("/test2")
  319. public McR test2(@RequestBody Map map) {
  320. log.info("map:{}", map);
  321. // String procInstId = String.valueOf(map.get("procInstId"));
  322. String processInstanceId = UtilMap.getString(map, "processInstanceId");
  323. // 获取审批实例信息
  324. Map processInstance = ddClientWorkflow.getProcessInstanceId(ddClient.getAccessToken(), processInstanceId);
  325. System.out.println("processInstance====" + processInstance);
  326. // Map body = new HashMap<>();
  327. // body.put("processInstanceId",processInstanceId);
  328. // body.put("text", "发票信息如下:\n\n1. 电子发票(普通发票) | 全电普通发票 | 发票号码:26312000001701010876 | 开票日期:2026-03-20 | 金额:103.28 | 不含税:94.75 | 税额:8.53 | 购买方:罗庆宇(个人) | 销售方:上海聪雷贸易有限公司 | 税号:91310107MA1G0XPA4K\n\n2. 电子发票(普通发票) | 全电普通发票 | 发票号码:26442000003207012931 | 开票日期:2026-03-25 | 金额:239.00 | 不含税:211.50 | 税额:27.50 | 购买方:罗庆宇 | 销售方:广州延阳电子商务有限公司 | 税号:91440101MA5AWRGH4L\n\n3. 电子发票(普通发票) | 全电普通发票 | 发票号码:26332000002236540291 | 开票日期:2026-03-20 | 金额:518.00 | 不含税:458.41 | 税额:59.59 | 购买方:罗庆宇(个人) | 销售方:杭州亿奥网络科技有限公司 | 税号:91330108MA28MK7K08\n\n4. 电子发票(普通发票) | 全电普通发票 | 发票号码:26442000003052085371 | 开票日期:2026-03-21 | 金额:183.00 | 不含税:161.95 | 税额:21.05 | 购买方:罗庆宇 | 销售方:广州梓夕贸易有限公司 | 税号:91440101MA59M7J471");
  329. // body.put("commentUserId","16441447913471369");
  330. //// body.put("file",fileMap);
  331. //
  332. // String re =UtilHttp.doPost("https://api.dingtalk.com/v1.0/workflow/processInstances/comments",ddClient.initTokenHeader(),null,body);
  333. // System.out.println("re"+ re);
  334. // if (Objects.nonNull(processInstance)) {
  335. // Map formData = new HashMap<>();
  336. // String title = String.valueOf(processInstance.get("title"));
  337. // String type = "";
  338. // List<Map> formComponentValues = (List<Map>) processInstance.get("formComponentValues");
  339. // }
  340. return McR.success();
  341. }
  342. @GetMapping("/files/{fileId}")
  343. public ResponseEntity<Resource> getFileResource(
  344. @PathVariable String fileId,
  345. @RequestParam(defaultValue = "download") String option) throws IOException {
  346. // 根据fileId获取实际文件路径,这里简化处理,实际可能需要从数据库查询
  347. Path filePath = Paths.get(bdurl).resolve(fileId).normalize();
  348. // 检查文件是否存在
  349. if (!Files.exists(filePath)) {
  350. return ResponseEntity.notFound().build();
  351. }
  352. // 创建Resource对象
  353. Resource resource = new UrlResource(filePath.toUri());
  354. // 根据选项设置响应头
  355. HttpHeaders headers = new HttpHeaders();
  356. if ("preview".equalsIgnoreCase(option)) {
  357. // 预览模式 - 尝试确定内容类型
  358. String contentType = Files.probeContentType(filePath);
  359. // 强制修正 PDF 的 Content-Type
  360. if (filePath.toString().toLowerCase().endsWith(".pdf")) {
  361. contentType = "application/pdf";
  362. } else if (contentType == null) {
  363. contentType = "application/octet-stream";
  364. }
  365. headers.setContentType(MediaType.parseMediaType(contentType));
  366. headers.add("Content-Disposition", "inline; filename=\"" + resource.getFilename() + "\"");
  367. headers.add("X-Content-Type-Options", "nosniff"); // 防止浏览器忽略 Content-Type
  368. } else {
  369. // 下载模式 - 默认处理
  370. headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
  371. headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
  372. }
  373. return ResponseEntity.ok()
  374. .headers(headers)
  375. .contentLength(resource.contentLength())
  376. .body(resource);
  377. }
  378. @PostMapping("/test1")
  379. public McR test1(@RequestBody Map<String, String> data) throws TencentCloudSDKException {
  380. log.info("test: {}", data);
  381. McException.assertParamException_Null(data, "url");
  382. // String image = ydClient.convertTemporaryUrl(data.get("url"));
  383. String image = data.get("url");
  384. log.info("混票识别, 免登地址, {}", image);
  385. // 非PDF, 且内存大于3M, 压缩后上传
  386. if (UtilMap.getFloat(data, "size") > 3.0f && !UtilMap.getBoolean(data, "isPdf")) {
  387. image = imageUrlConvertBase64(image);
  388. }
  389. if (UtilMap.getFloat(data, "size") > 6.0f && UtilMap.getBoolean(data, "isPdf")) {
  390. image = pdfUrlConvertBase64(image);
  391. }
  392. List<Map> invoices = (List<Map>) txyInvoice.doRecognizeGeneralInvoice(image).get("MixedInvoiceItems");
  393. System.out.println("invoices===="+invoices);
  394. List<String> nos=new ArrayList<>();
  395. List<McInvoiceDto> result = invoices.stream().map(item -> {
  396. Map prop = UtilMap.getMap(UtilMap.getMap(item, "SingleInvoiceInfos"), UtilMap.getString(item, "SubType"));
  397. // List<Map<String, Object>> vatInvoiceItemInfos = UtilMap.getList(prop, "VatInvoiceItemInfos");
  398. // if (!vatInvoiceItemInfos.isEmpty()) {
  399. // String taxRate = UtilMap.getString(vatInvoiceItemInfos.get(0), "TaxRate");
  400. // System.out.println("TaxRate: " + taxRate); // 输出: 9%
  401. // }
  402. String taxRate = null;
  403. // List<Map<String, Object>> vatInvoiceItemInfos = UtilMap.getList(prop, "VatInvoiceItemInfos");
  404. // 优先使用 VatInvoiceItemInfos,如果为空则使用 VatElectronicItems
  405. List<Map<String, Object>> vatInvoiceItemInfos =
  406. UtilMap.getList(prop, "VatInvoiceItemInfos") != null && !UtilMap.getList(prop, "VatInvoiceItemInfos").isEmpty()
  407. ? UtilMap.getList(prop, "VatInvoiceItemInfos")
  408. : UtilMap.getList(prop, "VatElectronicItems");
  409. // if (!vatInvoiceItemInfos.isEmpty()) {
  410. // taxRate = UtilMap.getString(vatInvoiceItemInfos.get(0), "TaxRate");
  411. // }
  412. if (!vatInvoiceItemInfos.isEmpty()) {
  413. String originalTaxRate = UtilMap.getString(vatInvoiceItemInfos.get(0), "TaxRate");
  414. // 判断是否为有效数字(包括带%号的格式,如"9%")
  415. if (StringUtils.isNotBlank(originalTaxRate)) {
  416. // 移除百分号并尝试解析为数字
  417. String cleanedTaxRate = originalTaxRate.replace("%", "").trim();
  418. try {
  419. // 尝试转换为数字
  420. new BigDecimal(cleanedTaxRate);
  421. taxRate = originalTaxRate; // 保持原值(可能带%)
  422. } catch (NumberFormatException e) {
  423. // 如果不是数字(如"不征税"、"免税"等),赋值为"0"
  424. taxRate = "0";
  425. log.debug("税率格式异常,原始值: {}, 已设置为0", originalTaxRate);
  426. }
  427. } else {
  428. taxRate = "0";
  429. }
  430. } else {
  431. taxRate = "0";
  432. }
  433. System.out.println("prop====="+prop);
  434. String no=UtilMap.getString(prop, "Number");
  435. if(nos.contains(no)){
  436. return null;
  437. }
  438. nos.add(no);
  439. String kind = UtilMap.getString(item, "TypeDescription");
  440. String invoiceName = UtilMap.getString(item, "SubTypeDescription");
  441. if (kind.equals("全电发票")) {
  442. if(invoiceName.contains("铁路电子客票")){
  443. kind="火车票";
  444. } else if(invoiceName.contains("机票行程单")){
  445. kind="机票行程单";
  446. } else if (invoiceName.contains("专用发票")) {
  447. kind="全电专用发票";
  448. }else {
  449. kind="全电普通发票";
  450. }
  451. }
  452. if (kind.equals("增值税发票")) {
  453. if(invoiceName.contains("区块链电子发票")){
  454. kind="区块链电子发票";
  455. } else if(invoiceName.contains("增值税专用发票")){
  456. kind="增值税专用发票";
  457. } else if(invoiceName.contains("增值税普通发票")){
  458. kind="增值税普通发票";
  459. } else if (invoiceName.contains("增值税电子专用发票")) {
  460. kind="增值税电子专用发票";
  461. } else if (invoiceName.contains("增值税电子普通发票")) {
  462. kind="增值税电子普通发票";
  463. }else {
  464. kind="增值税普通发票";
  465. }
  466. }
  467. // ppExt: 通用字段定义
  468. McInvoiceDto invoiceDto = McInvoiceDto.builder()
  469. .name(UtilMap.getString(item, "SubTypeDescription"))
  470. .kindName(kind)
  471. .taxRate(taxRate)
  472. .kind(UtilMap.getInt(item, "Type"))
  473. .code(UtilMap.getString(prop, "Code"))
  474. .serial(UtilMap.getString(prop, "Number"))
  475. .date(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "Date")))
  476. .checkCode(UtilMap.getString(prop, "CheckCode"))
  477. // ppExt: 多明细行时, 优先取值合计 [全电票返回了subTotal字段, 但值为空] // 2025.5.12 去除小计金额,并去除发票编号重复数据
  478. .amount(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "Total", "Fare"))) // "SubTotal",
  479. .tax(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "Tax"))) // "SubTax",
  480. .excludingTax(UtilNumber.setBigDecimal(UtilMap.getString(prop, "PretaxAmount")))
  481. .buyerName(StringUtils.isBlank(guyuanNameRepalce(UtilMap.getString(prop, "Buyer")))?"上海能辉科技股份有限公司":guyuanNameRepalce(UtilMap.getString(prop, "Buyer")))
  482. // ppExt: 中央非税未返回税号官方说明: 非税发票理论是没有税号的,图片中属于信用代码
  483. .buyerTaxId(StringUtils.isBlank(UtilMap.getString(prop, "BuyerTaxID"))?"": UtilMap.getString(prop, "BuyerTaxID"))
  484. .sellerName(guyuanNameRepalce(UtilMap.getString_first(prop, "Seller", "Issuer"))) // 行程单: 填开单位
  485. .sellerTaxId(UtilMap.getString_first(prop, "SellerTaxID", "AgentCode")) // 行程单: 销售单位代号
  486. .passengerName(UtilMap.getString_first(prop, "Name", "UserName")) // 火车票, 行程单
  487. // 交通出行
  488. .seatType(UtilMap.getString(prop, "Seat"))
  489. .departureTime(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "DateGetOn")) + " " + UtilMap.getString(prop, "TimeGetOn"))
  490. .departurePort(UtilMap.getString_first(prop, "StationGetOn", "Entrance", "Place")) // 火车票: 出发车站, 过路过桥费: 入口, 出租车: 发票所在地
  491. .arrivePort(UtilMap.getString_first(prop, "StationGetOff", "Exit")) // 行程单, 火车票: 到达车站, 过路过桥费: 出口
  492. .trainNo(UtilMap.getString_first(prop, "TrainNumber", "LicensePlate")) // 火车票: 车次, 出租车: 车牌号
  493. .insuranceCosts(UtilNumber.setBigDecimal((UtilMap.getString(prop, "Insurance")))) // 行程单: 保险费
  494. .fuelCosts(UtilNumber.setBigDecimal((UtilMap.getString(prop, "FuelSurcharge")))) // 行程单: 燃油附加费
  495. .constructionCosts(UtilNumber.setBigDecimal((UtilMap.getString(prop, "AirDevelopmentFund")))) // 行程单: 民航发展基金
  496. .build();
  497. // ppExt: 机票行程单, 行程与座位信息在明细内
  498. if ("机票行程单".equals(kind)) {
  499. invoiceDto.setSellerName(UtilMap.getString_first(prop, "Issuer"));
  500. invoiceDto.setSellerTaxId(UtilMap.getString_first(prop, "Seller"));
  501. Map flight = (Map) UtilMap.getList(prop, "FlightItems").get(0);
  502. invoiceDto.setDepartureTime(UtilString.replaceDateZH_cn(UtilMap.getString(item, "DateGetOn")) + " " + UtilMap.getString(prop, "TimeGetOn"));
  503. invoiceDto.setDeparturePort(UtilMap.getString(flight, "StationGetOn"));
  504. invoiceDto.setArrivePort(UtilMap.getString(flight, "StationGetOff"));
  505. invoiceDto.setSeatType(UtilMap.getString(flight, "Seat"));
  506. }
  507. if ("出租车发票".equals(item.get("TypeDescription"))) {
  508. // 上下车时间
  509. invoiceDto.setDepartureTime(UtilMap.getString(prop, "TimeGetOn") + " ~ " + UtilMap.getString(prop, "TimeGetOff"));
  510. }
  511. return invoiceDto;
  512. }).filter(item -> item!=null).collect(Collectors.toList());
  513. return McR.success(McInvoiceDto.formatResponse(result));
  514. }
  515. @PostMapping("invoice-iv2")
  516. McR invoice_iv2(@RequestBody Map<String, String> data) throws TencentCloudSDKException {
  517. McException.assertParamException_Null(data, "url");
  518. String image = ydClient.convertTemporaryUrl(data.get("url"));
  519. log.info("混票识别, 免登地址, {}", image);
  520. // 非PDF, 且内存大于3M, 压缩后上传
  521. if (UtilMap.getFloat(data, "size") > 3.0f && !UtilMap.getBoolean(data, "isPdf")) {
  522. image = imageUrlConvertBase64(image);
  523. }
  524. if (UtilMap.getFloat(data, "size") > 6.0f && UtilMap.getBoolean(data, "isPdf")) {
  525. image = pdfUrlConvertBase64(image);
  526. }
  527. List<Map> invoices = (List<Map>) txyInvoice.doRecognizeGeneralInvoice(image).get("MixedInvoiceItems");
  528. List<String> nos=new ArrayList<>();
  529. List<McInvoiceDto> result = invoices.stream().map(item -> {
  530. Map prop = UtilMap.getMap(UtilMap.getMap(item, "SingleInvoiceInfos"), UtilMap.getString(item, "SubType"));
  531. String no=UtilMap.getString(prop, "Number");
  532. if(nos.contains(no)){
  533. return null;
  534. }
  535. nos.add(no);
  536. String kind = UtilMap.getString(item, "TypeDescription");
  537. String invoiceName = UtilMap.getString(item, "SubTypeDescription");
  538. if (kind.equals("全电发票")) {
  539. if(invoiceName.contains("铁路电子客票")){
  540. kind="火车票";
  541. } else if(invoiceName.contains("机票行程单")){
  542. kind="机票行程单";
  543. } else if (invoiceName.contains("专用发票")) {
  544. kind="全电专用发票";
  545. }else {
  546. kind="全电普通发票";
  547. }
  548. }
  549. if (kind.equals("增值税发票")) {
  550. if(invoiceName.contains("区块链电子发票")){
  551. kind="区块链电子发票";
  552. } else if(invoiceName.contains("增值税专用发票")){
  553. kind="增值税专用发票";
  554. } else if(invoiceName.contains("增值税普通发票")){
  555. kind="增值税普通发票";
  556. } else if (invoiceName.contains("增值税电子专用发票")) {
  557. kind="增值税电子专用发票";
  558. } else if (invoiceName.contains("增值税电子普通发票")) {
  559. kind="增值税电子普通发票";
  560. }else {
  561. kind="增值税普通发票";
  562. }
  563. }
  564. // ppExt: 通用字段定义
  565. McInvoiceDto invoiceDto = McInvoiceDto.builder()
  566. .name(UtilMap.getString(item, "SubTypeDescription"))
  567. .kindName(kind)
  568. .kind(UtilMap.getInt(item, "Type"))
  569. .code(UtilMap.getString(prop, "Code"))
  570. .serial(UtilMap.getString(prop, "Number"))
  571. .date(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "Date")))
  572. .checkCode(UtilMap.getString(prop, "CheckCode"))
  573. // ppExt: 多明细行时, 优先取值合计 [全电票返回了subTotal字段, 但值为空] // 2025.5.12 去除小计金额,并去除发票编号重复数据
  574. .amount(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "Total", "Fare"))) // "SubTotal",
  575. .tax(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "Tax"))) // "SubTax",
  576. .excludingTax(UtilNumber.setBigDecimal(UtilMap.getString(prop, "PretaxAmount")))
  577. .buyerName(StringUtils.isBlank(guyuanNameRepalce(UtilMap.getString(prop, "Buyer")))?"上海能辉科技股份有限公司":guyuanNameRepalce(UtilMap.getString(prop, "Buyer")))
  578. // ppExt: 中央非税未返回税号官方说明: 非税发票理论是没有税号的,图片中属于信用代码
  579. .buyerTaxId(StringUtils.isBlank(UtilMap.getString(prop, "BuyerTaxID"))?"": UtilMap.getString(prop, "BuyerTaxID"))
  580. .sellerName(guyuanNameRepalce(UtilMap.getString_first(prop, "Seller", "Issuer"))) // 行程单: 填开单位
  581. .sellerTaxId(UtilMap.getString_first(prop, "SellerTaxID", "AgentCode")) // 行程单: 销售单位代号
  582. .passengerName(UtilMap.getString_first(prop, "Name", "UserName")) // 火车票, 行程单
  583. // 交通出行
  584. .seatType(UtilMap.getString(prop, "Seat"))
  585. .departureTime(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "DateGetOn")) + " " + UtilMap.getString(prop, "TimeGetOn"))
  586. .departurePort(UtilMap.getString_first(prop, "StationGetOn", "Entrance", "Place")) // 火车票: 出发车站, 过路过桥费: 入口, 出租车: 发票所在地
  587. .arrivePort(UtilMap.getString_first(prop, "StationGetOff", "Exit")) // 行程单, 火车票: 到达车站, 过路过桥费: 出口
  588. .trainNo(UtilMap.getString_first(prop, "TrainNumber", "LicensePlate")) // 火车票: 车次, 出租车: 车牌号
  589. .insuranceCosts(UtilNumber.setBigDecimal((UtilMap.getString(prop, "Insurance")))) // 行程单: 保险费
  590. .fuelCosts(UtilNumber.setBigDecimal((UtilMap.getString(prop, "FuelSurcharge")))) // 行程单: 燃油附加费
  591. .constructionCosts(UtilNumber.setBigDecimal((UtilMap.getString(prop, "AirDevelopmentFund")))) // 行程单: 民航发展基金
  592. .build();
  593. // ppExt: 机票行程单, 行程与座位信息在明细内
  594. if ("机票行程单".equals(kind)) {
  595. invoiceDto.setSellerName(UtilMap.getString_first(prop, "Issuer"));
  596. invoiceDto.setSellerTaxId(UtilMap.getString_first(prop, "Seller"));
  597. Map flight = (Map) UtilMap.getList(prop, "FlightItems").get(0);
  598. invoiceDto.setDepartureTime(UtilString.replaceDateZH_cn(UtilMap.getString(item, "DateGetOn")) + " " + UtilMap.getString(prop, "TimeGetOn"));
  599. invoiceDto.setDeparturePort(UtilMap.getString(flight, "StationGetOn"));
  600. invoiceDto.setArrivePort(UtilMap.getString(flight, "StationGetOff"));
  601. invoiceDto.setSeatType(UtilMap.getString(flight, "Seat"));
  602. }
  603. if ("出租车发票".equals(item.get("TypeDescription"))) {
  604. // 上下车时间
  605. invoiceDto.setDepartureTime(UtilMap.getString(prop, "TimeGetOn") + " ~ " + UtilMap.getString(prop, "TimeGetOff"));
  606. }
  607. return invoiceDto;
  608. }).filter(item -> item!=null).collect(Collectors.toList());
  609. return McR.success(McInvoiceDto.formatResponse(result));
  610. }
  611. //校验查重
  612. @PostMapping("invoice-va")
  613. McR invoice_va(@RequestBody Map data) {
  614. McException.assertParamException_Null(data, "param");
  615. List<McInvoiceDto> invoices = JSON.parseArray(JSON.toJSONString(data.get("param")), McInvoiceDto.class);
  616. log.info("发票查重, 验真, {}", invoices);
  617. invoices.forEach(UtilMc.consumerWithIndex((item, index) -> {
  618. McInvoiceDto dto = (McInvoiceDto) item;
  619. String invoiceNo = dto.getSerial(); // 唯一标识, 发票号码
  620. String serial = "第【" + (index + 1) + "】张发票";
  621. validateBuyer(dto.getBuyerName(), serial + "有疑问");
  622. McException.assertAccessException(StringUtils.isBlank(invoiceNo), serial + ", 识别结果为空, 请检查!");
  623. YDParam ydParam = YDParam.builder()
  624. .formUuid("FORM-W2A66Z910O9B3LP9C6IYUDPRVWY62DO0YHIILY")
  625. .searchFieldJson(JSON.toJSONString(UtilMap.map("radioField_liihyrtb, textField_liihyrt8", "否", invoiceNo)))
  626. .build();
  627. List<String> idList = (List<String>) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form_id).getData();
  628. if (idList.size() > 0) {
  629. McException.exceptionAccess(serial + "已存在, 请勿重复提交!");
  630. }
  631. // prd 仅仅识别增值税普通发票
  632. // if (dto.getName().contains("普通发票")) {
  633. // String serialTips = serial + "有疑问";
  634. // try {
  635. // // ppExt: 识别与验真后抬头对比 [全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值]
  636. // Map rsp = txyInvoice.doVatInvoiceVerifyNew(dto.getKindName(), dto.getCode(), invoiceNo, dto.getDate(), String.valueOf(dto.getAmount()), dto.getCheckCode(), String.valueOf(dto.getExcludingTax()), serialTips);
  637. // Map invoice = (Map) rsp.get("Invoice");
  638. // McException.assertAccessException(!dto.getBuyerName().equals(guyuanNameRepalce(invoice.get("BuyerName").toString())), serialTips + ", 购买方名称不匹配!");
  639. // McException.assertAccessException(!dto.getBuyerTaxId().equals(invoice.get("BuyerTaxCode")), serialTips + ", 购买方税号不匹配!");
  640. // McException.assertAccessException(!dto.getSellerName().equals(guyuanNameRepalce(invoice.get("SellerName").toString())), serialTips + ", 销售方名称不匹配!");
  641. // McException.assertAccessException(!dto.getSellerTaxId().equals(invoice.get("SellerTaxCode")), serialTips + ", 销售方税号不匹配!");
  642. // } catch (TencentCloudSDKException e) {
  643. // log.error(e.getMessage(), e);
  644. // // prd: 上传发票为假发票时,提示:该发票有疑问,请联系财务人员
  645. // String message = e.getMessage();
  646. // // ppExt: 已经是新版本接口, 过滤提示 [官方答复: 提示不会检测您是否使用的是新版,所有的用户都会提示, 忽略即可]
  647. // if (message.contains("温馨提示")) {
  648. // message = message.split("温馨提示")[0];
  649. // }
  650. // if (message.contains("发票不存在")) {
  651. // message = "有疑问,请联系财务人员";
  652. // }
  653. // McException.exceptionAccess(serial + message);
  654. // }
  655. // }
  656. }));
  657. return McR.success();
  658. }
  659. /// url压缩转base64
  660. @SneakyThrows
  661. private String imageUrlConvertBase64(String imageUrl) {
  662. ByteArrayOutputStream out = new ByteArrayOutputStream();
  663. // scale(比例), outputQuality(质量)
  664. Thumbnails.fromURLs(Arrays.asList(new URL(imageUrl))).scale(0.5f).outputQuality(0.25f).toOutputStream(out);
  665. InputStream inputStream = new ByteArrayInputStream(out.toByteArray());
  666. //转换为base64
  667. byte[] bytes = IOUtils.toByteArray(inputStream);
  668. return Base64.getEncoder().encodeToString(bytes);
  669. }
  670. private static String guyuanNameRepalce(String name) {
  671. name=name.replaceAll(" ","");
  672. if (name.contains("谷元")) {
  673. return UtilString.replaceBracketIsWhole(name);
  674. } else {
  675. return UtilString.replaceBracketIsSemiangle(name);
  676. }
  677. }
  678. @Autowired
  679. private FilePath filePath;
  680. /// PDF压缩转base64
  681. @SneakyThrows
  682. private String pdfUrlConvertBase64(String pdfUrl) {
  683. String fileName = "tmp_" + new Date().getTime() + ".pdf";
  684. // 下载文件
  685. File file = UtilFile.mkdirIfNot(fileName, filePath.getPath().getTmp());
  686. UtilHttp.doDownload(pdfUrl, file);
  687. // PDF压缩
  688. PdfDocument doc = new PdfDocument(); // 创建PdfDocument类的对象
  689. doc.loadFromFile(file.getAbsolutePath()); // 加载PDF文档
  690. doc.getFileInfo().setIncrementalUpdate(false); // 禁用增量更新
  691. doc.setCompressionLevel(PdfCompressionLevel.Normal); // 将压缩级别设置为最佳
  692. // 遍历文档页面
  693. for (int i = 0; i < doc.getPages().getCount(); i++) {
  694. PdfPageBase page = doc.getPages().get(i); // 获取指定页面
  695. PdfImageInfo[] images = page.getImagesInfo(); // 获取每个页面的图像信息集合
  696. // 遍历集合中的所有项目
  697. if (images != null && images.length > 0)
  698. for (int j = 0; j < images.length; j++) {
  699. PdfImageInfo image = images[j]; // 获取指定图片
  700. PdfBitmap bp = new PdfBitmap(image.getImage());
  701. bp.setQuality(30); // 设置压缩质量
  702. page.replaceImage(j, bp); // 将原始图像替换为压缩图像
  703. }
  704. }
  705. // 将结果文档保存至另一个PDF文档中: 覆盖
  706. doc.saveToFile(file.getAbsolutePath());
  707. doc.close();
  708. // PDF转base64, 无需透出本地文件地址
  709. String base64 = UtilFile.fileToBase64(file.getAbsolutePath());
  710. // 删除临时PDF文件
  711. UtilFile.deleteFile(file.getAbsolutePath());
  712. return base64;
  713. }
  714. private void validateBuyer(String BuyerName, String tips) {
  715. List<String> corpNames = Arrays.asList(
  716. "谷元(上海)文化科技有限责任公司",
  717. "上海爱鱼文化传媒有限公司",
  718. "上海渔米可禧文化传媒有限公司",
  719. "上海巧豆文化传媒有限公司",
  720. "钰鸿文化创意(上海)有限公司",
  721. "上海攸元文化科技有限公司",
  722. "上海盈田演出经纪有限公司",
  723. "上海小蝠文化科技有限公司",
  724. "沐田居海(厦门)文化传媒有限公司",
  725. "北京元环文化科技有限责任公司",
  726. "厦门攸元文化科技有限公司",
  727. "厦门亨有文化科技有限公司",
  728. "厦门银雀思汀文化传媒有限公司",
  729. "上海渝泽信息科技有限公司",
  730. "厦门神谷飞流影视传媒有限公司",
  731. "厦门谷钛数字科技有限公司",
  732. "上海观情科技有限公司",
  733. "渔米可禧文化传媒(香港)有限公司",
  734. "杭州渔米可禧文化传媒有限公司");
  735. McException.assertAccessException(!corpNames.contains(BuyerName), tips + ", 购买方名称不合法!");
  736. }
  737. //下载钉钉OA审批单附件
  738. private void downloadDdFile(String processInstanceId,String fileId,String downloadPath){
  739. try {
  740. Map body = new HashMap();
  741. body.put("processInstanceId",processInstanceId);
  742. body.put("fileId",fileId);
  743. DDR_New ddrNew = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v1.0/workflow/processInstances/spaces/files/urls/download", ddClient.initTokenHeader(), null, body, DDR_New.class);
  744. //2、执行下载
  745. Map result = (Map) ddrNew.getResult();
  746. String downloadUri = UtilMap.getString(result, "downloadUri");
  747. downloadFile(downloadUri,downloadPath);
  748. }catch (Exception e){
  749. throw new RuntimeException(e);
  750. }
  751. }
  752. //文件下载到本地
  753. private void downloadFile(String downloadUri,String downloadPath){
  754. try {
  755. URL url = new URL(downloadUri);
  756. HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
  757. int responseCode = httpConn.getResponseCode();
  758. // 检查HTTP响应代码是否为200
  759. if (responseCode == HttpURLConnection.HTTP_OK) {
  760. InputStream inputStream = httpConn.getInputStream();
  761. FileOutputStream outputStream = new FileOutputStream(downloadPath);
  762. byte[] buffer = new byte[4096];
  763. int bytesRead = -1;
  764. while ((bytesRead = inputStream.read(buffer)) != -1) {
  765. outputStream.write(buffer, 0, bytesRead);
  766. }
  767. outputStream.close();
  768. inputStream.close();
  769. } else {
  770. System.out.println("无法下载文件。HTTP响应代码: " + responseCode);
  771. }
  772. httpConn.disconnect();
  773. }catch (Exception e){
  774. throw new RuntimeException(e);
  775. }
  776. }
  777. /**
  778. * 私有化方法:混票识别处理
  779. * @param data 包含url、size、isPdf的Map参数
  780. * @return 识别结果
  781. */
  782. private McR<Object> processMixedInvoice(Map<String, Object> data) throws TencentCloudSDKException {
  783. McException.assertParamException_Null(data, "url");
  784. String image = String.valueOf(data.get("url"));
  785. log.info("混票识别, 免登地址, {}", image);
  786. // 非PDF, 且内存大于3M, 压缩后上传
  787. if (UtilMap.getFloat(data, "size") > 3.0f && !UtilMap.getBoolean(data, "isPdf")) {
  788. image = imageUrlConvertBase64(image);
  789. }
  790. if (UtilMap.getFloat(data, "size") > 6.0f && UtilMap.getBoolean(data, "isPdf")) {
  791. image = pdfUrlConvertBase64(image);
  792. }
  793. List<Map> invoices = (List<Map>) txyInvoice.doRecognizeGeneralInvoice(image).get("MixedInvoiceItems");
  794. System.out.println("invoices====="+invoices);
  795. List<String> nos = new ArrayList<>();
  796. List<McInvoiceDto> result = invoices.stream().map(item -> {
  797. Map prop = UtilMap.getMap(UtilMap.getMap(item, "SingleInvoiceInfos"), UtilMap.getString(item, "SubType"));
  798. String no = UtilMap.getString(prop, "Number");
  799. if (nos.contains(no)) {
  800. return null;
  801. }
  802. nos.add(no);
  803. String kind = UtilMap.getString(item, "TypeDescription");
  804. String invoiceName = UtilMap.getString(item, "SubTypeDescription");
  805. if (kind.equals("全电发票")) {
  806. if (invoiceName.contains("铁路电子客票")) {
  807. kind = "火车票";
  808. } else if (invoiceName.contains("机票行程单")) {
  809. kind = "机票行程单";
  810. } else if (invoiceName.contains("专用发票")) {
  811. kind = "全电专用发票";
  812. } else {
  813. kind = "全电普通发票";
  814. }
  815. }
  816. if (kind.equals("增值税发票")) {
  817. if (invoiceName.contains("区块链电子发票")) {
  818. kind = "区块链电子发票";
  819. } else if (invoiceName.contains("增值税专用发票")) {
  820. kind = "增值税专用发票";
  821. } else if (invoiceName.contains("增值税普通发票")) {
  822. kind = "增值税普通发票";
  823. } else if (invoiceName.contains("增值税电子专用发票")) {
  824. kind = "增值税电子专用发票";
  825. } else if (invoiceName.contains("增值税电子普通发票")) {
  826. kind = "增值税电子普通发票";
  827. } else {
  828. kind = "增值税普通发票";
  829. }
  830. }
  831. McInvoiceDto invoiceDto = McInvoiceDto.builder()
  832. .name(UtilMap.getString(item, "SubTypeDescription"))
  833. .kindName(kind)
  834. .kind(UtilMap.getInt(item, "Type"))
  835. .code(UtilMap.getString(prop, "Code"))
  836. .serial(UtilMap.getString(prop, "Number"))
  837. .date(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "Date")))
  838. .checkCode(UtilMap.getString(prop, "CheckCode"))
  839. .amount(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "Total", "Fare")))
  840. .tax(UtilNumber.setBigDecimal(UtilMap.getString_first(prop, "Tax")))
  841. .excludingTax(UtilNumber.setBigDecimal(UtilMap.getString(prop, "PretaxAmount")))
  842. .buyerName(StringUtils.isBlank(guyuanNameRepalce(UtilMap.getString(prop, "Buyer")))
  843. ? "上海能辉科技股份有限公司" : guyuanNameRepalce(UtilMap.getString(prop, "Buyer")))
  844. .buyerTaxId(StringUtils.isBlank(UtilMap.getString(prop, "BuyerTaxID"))
  845. ? "" : UtilMap.getString(prop, "BuyerTaxID"))
  846. .sellerName(guyuanNameRepalce(UtilMap.getString_first(prop, "Seller", "Issuer")))
  847. .sellerTaxId(UtilMap.getString_first(prop, "SellerTaxID", "AgentCode"))
  848. .passengerName(UtilMap.getString_first(prop, "Name", "UserName"))
  849. .seatType(UtilMap.getString(prop, "Seat"))
  850. .departureTime(UtilString.replaceDateZH_cn(UtilMap.getString(prop, "DateGetOn"))
  851. + " " + UtilMap.getString(prop, "TimeGetOn"))
  852. .departurePort(UtilMap.getString_first(prop, "StationGetOn", "Entrance", "Place"))
  853. .arrivePort(UtilMap.getString_first(prop, "StationGetOff", "Exit"))
  854. .trainNo(UtilMap.getString_first(prop, "TrainNumber", "LicensePlate"))
  855. .insuranceCosts(UtilNumber.setBigDecimal(UtilMap.getString(prop, "Insurance")))
  856. .fuelCosts(UtilNumber.setBigDecimal(UtilMap.getString(prop, "FuelSurcharge")))
  857. .constructionCosts(UtilNumber.setBigDecimal(UtilMap.getString(prop, "AirDevelopmentFund")))
  858. .build();
  859. if ("机票行程单".equals(kind)) {
  860. invoiceDto.setSellerName(UtilMap.getString_first(prop, "Issuer"));
  861. invoiceDto.setSellerTaxId(UtilMap.getString_first(prop, "Seller"));
  862. Map flight = (Map) UtilMap.getList(prop, "FlightItems").get(0);
  863. invoiceDto.setDepartureTime(UtilString.replaceDateZH_cn(UtilMap.getString(item, "DateGetOn"))
  864. + " " + UtilMap.getString(prop, "TimeGetOn"));
  865. invoiceDto.setDeparturePort(UtilMap.getString(flight, "StationGetOn"));
  866. invoiceDto.setArrivePort(UtilMap.getString(flight, "StationGetOff"));
  867. invoiceDto.setSeatType(UtilMap.getString(flight, "Seat"));
  868. }
  869. if ("出租车发票".equals(item.get("TypeDescription"))) {
  870. invoiceDto.setDepartureTime(UtilMap.getString(prop, "TimeGetOn")
  871. + " ~ " + UtilMap.getString(prop, "TimeGetOff"));
  872. }
  873. return invoiceDto;
  874. }).filter(Objects::nonNull).collect(Collectors.toList());
  875. return McR.success(McInvoiceDto.formatResponse(result));
  876. }
  877. }