package foundation.ai; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Objects; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import foundation.ai.dao.InvoiceVerificationDao; import foundation.ai.logic.OCRResultKingDee; import foundation.dao.Filter; import foundation.dao.Settings; import foundation.data.entity.EntitySet; import foundation.data.object.DataObject; import foundation.util.ContentBuilder; import foundation.util.MD5Utils; import foundation.util.Util; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; import sun.misc.BASE64Encoder; public class KingdeeAIProvider extends AIProvider { private static Logger logger; private static String HOST = "https://api.piaozone.com"; private static String CLIENT_ID = "Pa0umVUNzg6EiWSEpGht"; private static String CLIENT_SECRET = "a3cbabd08e684413a30aae1803c773d5"; private static String TOKEN_PATH = "/base/oauth/token"; protected static String AES_KEY = "goopyi5VTKD5WIgs"; public static int TimeOut_Second_Write = 10; public static int TimeOut_Second_Read = 10; public static boolean Debug = true; private static OkHttpClient httpClient = null; static { logger = LogManager.getLogger(KingdeeAIProvider.class); } @Override protected String getName() { return "金蝶AI"; } @Override public OCRResult executeAction(Operator operator, File file) throws Exception { boolean isReal = false, isBill = false; // 1. 得到图片的Base64 String base64 = imageToBase64(file); if (base64 == null) { logger.error("无法对图片{}进行Base64编码,无法进行AI识别", file); return null; } // 2. 获取access_token Response tokenResponse = getAccessToken(); if (!tokenResponse.isSuccessful()) { return new OCRResult(operator, "error"); } ResponseBody body = tokenResponse.body(); String bodyStr = body.string(); JSONObject tokenJson = JSONObject.parseObject(bodyStr); body.close(); // 3. 创建请求 OperateUrl operation = OperateUrl.parse(operator); Request request = new Request.Builder().url(HOST + operation.requestUrl + tokenJson.getString("access_token")) .post(RequestBody.create(MediaType.parse("text/plain"), base64)).build(); // 4. 发送请求 String value = ""; try { value = send(operation, request); } catch (Exception e) { e.printStackTrace(); value = "fail"; } // 5.分析校验结果 OCRResultKingDee resultKingDee = OCRResultKingDee.parseBatch(value); List invoiceVerificationList = resultKingDee.getInvoiceVerificationList(); if(invoiceVerificationList.size()> 0 || !resultKingDee.isSuccess()) { isReal = false; isBill = false; } // 5.1 发票唯一性校验 boolean checkDistinct = Settings.getBoolean("InvoiceDistinctCheck", false); if (checkDistinct) { for (InvoiceVerificationDao invoice : invoiceVerificationList) { boolean distincCheck = distinctCheck(invoice.getCode(), invoice.getNumber()); invoice.setDistinct(distincCheck); } } // 6. 返回结果 value = Util.ocrJson(value); OCRResult result = new OCRResult(operator, value); result.setErrcode(resultKingDee.getErrcode()); result.setDescription(resultKingDee.getDescription()); result.setTraceId(resultKingDee.getTraceId()); result.setIs_real(isReal); result.setIs_bill(isBill); result.setJsonArray(resultKingDee.getData()); result.setInvoiceList(invoiceVerificationList); return result; } @Override public OCRResult executeAction(Operator operator, Object paramObject) throws Exception { boolean isReal = false, isBill = false; // 1. 获取发票信息 JSONObject vatInvoiceVerify = (JSONObject) paramObject; if (vatInvoiceVerify == null || Util.isEmpty(vatInvoiceVerify)) { logger.error("未获取到相关发票信息,无法查询发票"); return null; } // 2.获取access_token Response tokenResponse = getAccessToken(); if (!tokenResponse.isSuccessful()) { return new OCRResult(operator, "error"); } ResponseBody body = tokenResponse.body(); String bodyStr = body.string(); JSONObject tokenJson = JSONObject.parseObject(bodyStr); body.close(); // 3. 创建请求 String value = ""; OperateUrl operation = OperateUrl.parse(operator); JSONObject jsonBody = new JSONObject(); jsonBody.put("invoiceCode", vatInvoiceVerify.getString("invoiceCode")); jsonBody.put("invoiceNo", vatInvoiceVerify.getString("invoiceNo")); jsonBody.put("invoiceDate", vatInvoiceVerify.getString("invoiceDate")); jsonBody.put("invoiceMoney", vatInvoiceVerify.getString("invoiceMoney")); jsonBody.put("totalAmount", vatInvoiceVerify.getString("totalAmount")); jsonBody.put("checkCode", vatInvoiceVerify.getString("checkCode")); jsonBody.put("isCreateUrl", vatInvoiceVerify.getString("isCreateUrl")); Request request = new Request.Builder().url(HOST + operation.requestUrl + tokenJson.getString("access_token")) .post(RequestBody.create(MediaType.parse("application/json"), jsonBody.toJSONString())).build(); // 4. 发送请求 try { value = send(operation, request); } catch (Exception e) { e.printStackTrace(); value = e.getMessage(); } // 5. 分析查询结果 OCRResultKingDee resultKingDee = OCRResultKingDee.parseOne(value); List invoiceVerificationList = resultKingDee.getInvoiceVerificationList(); // 5.1 发票唯一性校验 boolean checkDistinct = Settings.getBoolean("InvoiceDistinctCheck", false); if (checkDistinct) { for (InvoiceVerificationDao invoice : invoiceVerificationList) { boolean distincCheck = distinctCheck(invoice.getCode(), invoice.getNumber()); invoice.setDistinct(distincCheck); } } if (Util.isEmpty(invoiceVerificationList) || !resultKingDee.isSuccess()) { isReal = false; isBill = false; } // 6. 返回结果 value = Util.ocrJson(value); OCRResult result = new OCRResult(operator, value); result.setErrcode(resultKingDee.getErrcode()); result.setDescription(resultKingDee.getDescription()); result.setTraceId(resultKingDee.getTraceId()); result.setIs_real(isReal); result.setIs_bill(isBill); result.setJsonArray(resultKingDee.getData()); result.setInvoiceList(invoiceVerificationList); return result; } private String send(OperateUrl operation, Request request) throws IOException { httpClient = new OkHttpClient(); String json = null; Response response = httpClient.newCall(request).execute(); if (response.isSuccessful()) { try { json = response.body().string(); } catch (Exception e) { e.printStackTrace(); } finally { response.close(); } } return json; } private static Response getAccessToken() throws Exception { httpClient = new OkHttpClient(); long currentTimeStamp = System.currentTimeMillis(); String sign = MD5Utils.MD5Encode(CLIENT_ID + CLIENT_SECRET + currentTimeStamp, "UTF-8"); JSONObject body = new JSONObject(); // 1. set parameter body.put("client_id", CLIENT_ID); body.put("client_secret", CLIENT_SECRET); body.put("sign", sign); body.put("timestamp", currentTimeStamp); MediaType jsonMediaType = MediaType.get("application/json"); String bodyStr = JSON.toJSONString(body); Request request = new Request.Builder().url(HOST + TOKEN_PATH).post(RequestBody.create(jsonMediaType, bodyStr)) .build(); // 3. do sendRequest Response response = httpClient.newCall(request).execute(); return response; } private static String imageToBase64(File file) { byte[] data = null; InputStream in = null; try { // 1. bytes in = new FileInputStream(file); data = new byte[in.available()]; in.read(data); in.close(); // 2. encode BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(Objects.requireNonNull(data)); } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } public static boolean distinctCheck(String invoiceCode , String invoiceNumber) throws Exception { DataObject dataObject = DataObject.getInstance("so_implant_invoice_list"); Filter filter = new Filter(); ContentBuilder builder = new ContentBuilder(", "); builder.append(Util.quotedStr("input")); builder.append(Util.quotedStr("cancel")); builder.append(Util.quotedStr("close")); filter.add("so_implant_invoice.code", invoiceCode); filter.add("so_implant_invoice.number", invoiceNumber); filter.add("so_implant.state_code", "not in ", "(" + builder.toString() + ")"); EntitySet entitySet = dataObject.getBrowseEntitySet(filter); if (entitySet.size() > 0 ) { return false; } return true; } }