TencentInvoice.java 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package com.muzhi.lemeng.common.tencent;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.tencentcloudapi.common.Credential;
  5. import com.tencentcloudapi.common.exception.TencentCloudSDKException;
  6. import com.tencentcloudapi.common.profile.ClientProfile;
  7. import com.tencentcloudapi.common.profile.HttpProfile;
  8. import com.tencentcloudapi.ocr.v20181119.OcrClient;
  9. import com.tencentcloudapi.ocr.v20181119.models.*;
  10. import lombok.extern.slf4j.Slf4j;
  11. import org.apache.commons.lang.StringUtils;
  12. import org.springframework.beans.factory.annotation.Value;
  13. import org.springframework.stereotype.Component;
  14. import java.time.LocalDateTime;
  15. import java.time.format.DateTimeFormatter;
  16. import java.util.HashMap;
  17. import java.util.Map;
  18. @Slf4j
  19. @Component
  20. public class TencentInvoice {
  21. private static String secretId;
  22. private static String secretKey;
  23. private static String region;
  24. // 创建一个非静态的 Setter 方法,加上 @Value
  25. // Spring 启动时会调用这个方法,将配置文件值传入
  26. @Value("${myapp.tengxun.secretId}")
  27. public void setSecretId(String value) {
  28. TencentInvoice.secretId = value; // 赋值给静态变量
  29. }
  30. @Value("${myapp.tengxun.secretKey}")
  31. public void setSecretKey(String value) {
  32. TencentInvoice.secretKey = value; // 赋值给静态变量
  33. }
  34. @Value("${myapp.tengxun.region}")
  35. public void setRegion(String value) {
  36. TencentInvoice.region = value; // 赋值给静态变量
  37. }
  38. // 创建请求描述
  39. private static ClientProfile doRequest(String endPoint) {
  40. HttpProfile httpProfile = new HttpProfile();
  41. httpProfile.setEndpoint(endPoint);
  42. ClientProfile clientProfile = new ClientProfile();
  43. clientProfile.setHttpProfile(httpProfile);
  44. return clientProfile;
  45. }
  46. /**
  47. * 通用票据识别(高级版)
  48. * REMARK 接口文档地址:https://cloud.tencent.com/document/product/866/37835
  49. *
  50. * @param invoiceUrl 发票文件公网URL
  51. */
  52. public static JSONObject doRecognizeGeneralInvoice(String invoiceUrl) throws TencentCloudSDKException{
  53. Credential cred = new Credential(secretId, secretKey);
  54. ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
  55. OcrClient client = new OcrClient(cred, region, clientProfile);
  56. RecognizeGeneralInvoiceRequest req = new RecognizeGeneralInvoiceRequest();
  57. if (invoiceUrl.startsWith("http")) {
  58. req.setImageUrl(invoiceUrl);
  59. } else {
  60. req.setImageBase64(invoiceUrl);
  61. }
  62. req.setEnableMultiplePage(true); // PDF多页识别, 仅支持返回文件前30页
  63. req.setEnableCutImage(false); // 返回切割图片base64
  64. RecognizeGeneralInvoiceResponse resp = client.RecognizeGeneralInvoice(req);
  65. String result = MixedInvoiceOCRResponse.toJsonString(resp);
  66. JSONObject jsonObject = JSON.parseObject(result);
  67. log.debug("请求响应, {}", result);
  68. return jsonObject;
  69. }
  70. /**
  71. * 发票验真[新版]
  72. * REMARK 接口文档地址:https://cloud.tencent.com/document/product/866/73674
  73. *
  74. * @param invoiceKind 票种类型
  75. * @param invoiceCode 发票代码
  76. * @param invoiceNo 发票号码
  77. * @param invoiceDate 开票日期
  78. * @param amount 价税合计金额
  79. * @param checkCode 校验码
  80. * @param excludingTax 不含税金额
  81. * @param gmfName 购买方名称
  82. * @param gmfNo 购买方纳税人识别号
  83. */
  84. public static JSONObject doVatInvoiceVerifyNew(String invoiceKind, String invoiceCode, String invoiceNo, String invoiceDate, String amount, String checkCode, String excludingTax, String gmfName, String gmfNo) throws TencentCloudSDKException {
  85. Credential cred = new Credential(secretId, secretKey);
  86. ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
  87. OcrClient client = new OcrClient(cred, region, clientProfile);
  88. // 一些特殊发票校验码只有5位, 兼容
  89. if (StringUtils.isNotBlank(checkCode) && checkCode.length() > 6) {
  90. checkCode = checkCode.substring(checkCode.length() - 6);
  91. }
  92. VatInvoiceVerifyNewRequest req = new VatInvoiceVerifyNewRequest();
  93. req.setInvoiceNo(invoiceNo);
  94. req.setInvoiceDate(invoiceDate);
  95. req.setInvoiceCode(invoiceCode);
  96. req.setCheckCode(checkCode);
  97. // ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
  98. if (invoiceKind.contains("全电")) {
  99. // 全电票, 需要价税合计且无发票代码与校验码
  100. req.setCheckCode(null);
  101. req.setInvoiceCode(null);
  102. req.setAmount(amount);
  103. } else {
  104. req.setAmount(null);
  105. req.setAmount(excludingTax);
  106. }
  107. log.debug("发票验真, {}, {}", invoiceKind, JSON.toJSONString(req));
  108. String result = null;
  109. String message = null;
  110. try {
  111. VatInvoiceVerifyNewResponse resp = client.VatInvoiceVerifyNew(req);
  112. result = VatInvoiceVerifyNewResponse.toJsonString(resp);
  113. }catch (TencentCloudSDKException e){
  114. e.printStackTrace();
  115. message = e.getMessage();
  116. log.error("发票验真失败: " + e.getMessage());
  117. }
  118. log.info("发票验真, {}, {}", invoiceKind, result);
  119. // 1. 获取当前日期时间对象
  120. LocalDateTime now = LocalDateTime.now();
  121. // 2. 定义格式化器 (yyyy-MM-dd HH:mm:ss)
  122. // 注意:HH 代表24小时制,mm 代表分钟,ss 代表秒
  123. DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
  124. // 3. 格式化输出
  125. String formattedDate = now.format(formatter);
  126. System.out.println("当前时间: " + formattedDate);
  127. Map invoiceMapResult = new HashMap();
  128. if (result != null){
  129. JSONObject jsonObject = JSON.parseObject(result);
  130. // 因全电票取值, 取值价税合计, 单独校验金额
  131. JSONObject invoice = jsonObject.getJSONObject("Invoice");
  132. if (invoiceCode == null){
  133. invoiceCode = "";
  134. }
  135. if (checkCode == null){
  136. checkCode = "";
  137. }
  138. String fpdm = invoice.getString("Code");
  139. System.out.println("发票代码: " + fpdm);
  140. String fphm = invoice.getString("Number");
  141. System.out.println("发票号码: " + fphm);
  142. String kprq = invoice.getString("Date");
  143. System.out.println("开票日期: " + kprq);
  144. float hsje = invoice.getFloat("AmountWithTax");
  145. System.out.println("含税金额: " + hsje);
  146. float bhsje = invoice.getFloat("AmountWithoutTax");
  147. System.out.println("不含税金额: " + bhsje);
  148. //将含税金额、不含税金额从文本转成数字
  149. float amountFloat = Float.parseFloat(amount);
  150. float excludingTaxFloat = Float.parseFloat(excludingTax);
  151. String gmfmc = invoice.getString("BuyerName");
  152. System.out.println("购方名称: " + gmfmc);
  153. String gmfnsrsbh = invoice.getString("BuyerTaxCode");
  154. System.out.println("购方纳税人识别号: " + gmfnsrsbh);
  155. if (invoiceCode.equals(fpdm) && invoiceNo.equals(fphm) && invoiceDate.equals(kprq) && amountFloat == hsje && excludingTaxFloat == bhsje && gmfmc.equals(gmfName) && gmfnsrsbh.equals(gmfNo)){
  156. invoiceMapResult.put("state", "验真成功");
  157. invoiceMapResult.put("message", "✅发票验真成功!执行时间:" + formattedDate);
  158. }else {
  159. invoiceMapResult.put("state", "验真失败");
  160. invoiceMapResult.put("message", "⚠️发票存在疑问!执行时间:" + formattedDate);
  161. }
  162. }else {
  163. invoiceMapResult.put("state", "验真失败");
  164. invoiceMapResult.put("message", "⚠️发票存在疑问!执行时间:" + formattedDate + "【失败原因:" + message + "】");
  165. }
  166. String jsonString = JSON.toJSONString(invoiceMapResult);
  167. JSONObject invoiceJsonObject = JSONObject.parseObject(jsonString);
  168. log.info("发票验真结果: {}", invoiceJsonObject);
  169. return invoiceJsonObject;
  170. }
  171. }