wzy 2 weken geleden
bovenliggende
commit
dd8c1b3b88

+ 78 - 5
mjava-siku/src/main/java/com/malk/siku/controller/SikuController.java

@@ -1,14 +1,22 @@
 package com.malk.siku.controller;
 
+import com.alibaba.fastjson.JSONObject;
 import com.malk.server.common.McR;
 import com.malk.siku.service.SikuService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
 
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.Map;
 
 @Slf4j
@@ -18,6 +26,9 @@ public class SikuController {
     @Autowired
     private SikuService sikuService;
 
+    @Value(value = "${mk.downloadFilePath}")
+    private String fileStoragePath;
+
     //保存每刻往来单位
     @PostMapping("/saveTradingPartner")
     public McR saveTradingPartner(@RequestBody Map map) {
@@ -34,11 +45,73 @@ public class SikuController {
         return sikuService.saveYpClient(map);
     }*/
 
+    /**
+     * 开票申请单导入和更新
+     * @param map
+     * @return
+     */
+    @PostMapping("/saveYpApplication")
+    public McR saveYpApplication(@RequestBody Map map){
+        return sikuService.saveYpApplication(map);
+    }
+
     //每刻云票回款回调
     @PostMapping("/receive/callback")
     public McR callback(@RequestBody Map map){
-        log.info("每刻云票回款回调:{}",map);
+        log.info("每刻云票回款回调:{}", JSONObject.toJSONString(map));
 
         return McR.success();
     }
+
+    //每刻云票开票回调
+    @PostMapping("/application/callback")
+    public McR callback2(@RequestBody Map map){
+        log.info("每刻云票开票回调:{}",JSONObject.toJSONString(map));
+
+        sikuService.invoiceWriteBack(map);
+
+        return McR.success();
+    }
+
+    @GetMapping("/files/{fileId}")
+    public ResponseEntity<Resource> getFileResource(
+            @PathVariable String fileId,
+            @RequestParam(defaultValue = "download") String option) throws IOException {
+
+        // 根据fileId获取实际文件路径,这里简化处理,实际可能需要从数据库查询
+        Path filePath = Paths.get(fileStoragePath).resolve(fileId).normalize();
+
+        // 检查文件是否存在
+        if (!Files.exists(filePath)) {
+            return ResponseEntity.notFound().build();
+        }
+
+        // 创建Resource对象
+        Resource resource =  new UrlResource(filePath.toUri());
+
+        // 根据选项设置响应头
+        HttpHeaders headers = new HttpHeaders();
+        if ("preview".equalsIgnoreCase(option)) {
+            // 预览模式 - 尝试确定内容类型
+            String contentType = Files.probeContentType(filePath);
+            // 强制修正 PDF 的 Content-Type
+            if (filePath.toString().toLowerCase().endsWith(".pdf")) {
+                contentType = "application/pdf";
+            } else if (contentType == null) {
+                contentType = "application/octet-stream";
+            }
+            headers.setContentType(MediaType.parseMediaType(contentType));
+            headers.add("Content-Disposition", "inline; filename=\"" + resource.getFilename() + "\"");
+            headers.add("X-Content-Type-Options", "nosniff"); // 防止浏览器忽略 Content-Type
+        } else {
+            // 下载模式 - 默认处理
+            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
+            headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\"");
+        }
+
+        return ResponseEntity.ok()
+                .headers(headers)
+                .contentLength(resource.contentLength())
+                .body(resource);
+    }
 }

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

@@ -6,4 +6,8 @@ import java.util.Map;
 
 public interface SikuService {
     McR saveTradingPartner(Map map);
+
+    McR saveYpApplication(Map map);
+
+    void invoiceWriteBack(Map map);
 }

+ 137 - 5
mjava-siku/src/main/java/com/malk/siku/service/impl/SikuServiceImpl.java

@@ -6,16 +6,20 @@ import com.malk.server.aliwork.YDParam;
 import com.malk.server.common.McR;
 import com.malk.service.aliwork.YDClient;
 import com.malk.siku.service.SikuService;
-import com.malk.siku.utils.MkUtil;
+import com.malk.siku.utils.MkBxUtil;
+import com.malk.siku.utils.MkYpUtil;
 import com.malk.utils.UtilHttp;
 import com.malk.utils.UtilMap;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.*;
 
 @Slf4j
 @Service
@@ -66,10 +70,138 @@ public class SikuServiceImpl implements SikuService {
         Map body = new HashMap();
         body.put("partnerList", Arrays.asList(partner));
 
-        Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://ng.maycur.com/api/openapi/tradingPartner/batch/save", MkUtil.initTokenHeader(), null, body));
+        Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://ng.maycur.com/api/openapi/tradingPartner/batch/save", MkBxUtil.initTokenHeader(), null, body));
 
         log.info("Result:",result);
 
         return McR.success();
     }
+
+    @Override
+    public McR saveYpApplication(Map map) {
+        String formInstId = UtilMap.getString(map, "formInstId");
+
+        Map formData = ydClient.queryData(YDParam.builder()
+                .formInstanceId(formInstId)
+                .build(), YDConf.FORM_QUERY.retrieve_id).getFormData();
+
+        Map application = new HashMap();
+        application.put("formSubTypeBizCode","KPSQD");//单据编码(云票系统内维护的)
+        application.put("bizCode", UtilMap.getString(formData,"serialNumberField_mknspz75"));//外部系统中的开票申请单业务编码。必须系统内唯一,用于判断开票申请单是否已导入。
+        Map clientLegalEntityOaDto = new HashMap();//客户开票信息对象
+        clientLegalEntityOaDto.put("invoiceTitle",UtilMap.getString(formData,"selectField_mkxmix7e"));//名称
+        clientLegalEntityOaDto.put("dutyParagraph",UtilMap.getString(formData,"textField_mm2wj87l"));//税号
+        clientLegalEntityOaDto.put("account",UtilMap.getString(formData,"textField_mm2wj87u"));//账号
+        clientLegalEntityOaDto.put("bankBranchName",UtilMap.getString(formData,"textField_mm2wj87t"));//银行
+        application.put("clientLegalEntityOaDto",clientLegalEntityOaDto);
+        application.put("legalEntityBizCode",UtilMap.getString(formData,"textField_mm2wj87x"));//公司主体code(后续传税号)
+        application.put("estimatedDate",System.currentTimeMillis());//预计开票时间
+        String fplx = UtilMap.getString(formData, "selectField_mkdnuvem");//发票类型
+        String estimatedInvoiceType = "";
+        switch (fplx){
+            case "应/免税普票":estimatedInvoiceType = "ELECTRONIC_VAT";break;//增值税普通发票(电子)
+            case "专票":estimatedInvoiceType = "ELECTRONIC_SPACIAL_VAT";break;//增值税电子专用发票
+            case "红冲":break;
+            case "形式发票":break;
+            case "收据":break;
+            default:break;
+        }
+        application.put("estimatedInvoiceType",estimatedInvoiceType);//发票类型
+
+        application.put("phoneNumber",UtilMap.getString(formData,"textField_mkdo0azf"));//收票人电话
+        application.put("email",UtilMap.getString(formData,"textField_mkdo0azn"));//收票邮箱
+        application.put("applicationComment",UtilMap.getString(formData,"textareaField_mkdo0aze"));//开票备注
+
+        Map item = new HashMap();
+        item.put("productBizCode","1001");//产品bizcode
+        item.put("invoiceName",UtilMap.getString(formData,"textField_mkgarw4d"));//开票名称
+        item.put("taxPercent",UtilMap.getDouble(formData,"numberField_mkgkboht"));//税率
+        item.put("quantity",1);//数量
+        item.put("forexName","CNY");//币种
+        item.put("exchangeRate",1);//外汇汇率
+        item.put("priceWithTax",UtilMap.getDouble(formData,"numberField_mkdo0azb"));//含税单价
+        item.put("taxClassShortCode",UtilMap.getString(formData,"textField_mm49zsli"));//税收分类编码
+
+        application.put("items",Arrays.asList(item));
+
+        Map result = MkYpUtil.application_oa(Arrays.asList(application));
+
+        return McR.success();
+    }
+
+    @Override
+    public void invoiceWriteBack(Map map) {
+        //获取发票信息
+        Map calloutParams = UtilMap.getMap(map, "calloutParams");
+        Map bizData = UtilMap.getMap(calloutParams, "bizData");
+
+        String bizCode = UtilMap.getString(bizData, "bizCode");//发票号码
+        String invoiceNumber = UtilMap.getString(bizData, "invoiceNumber");//发票号码
+        String pdfUrl = UtilMap.getString(bizData, "pdfUrl");//pdf文件下载地址
+        String downloadPageUrl = UtilMap.getString(bizData, "downloadPageUrl");//发票下载页面链接
+        List<Map> detailItems = (List<Map>) UtilMap.getList(bizData, "detailItems");
+        List<Map> documentCorrelates = UtilMap.getList(detailItems.get(0), "documentCorrelates");
+        String lsh = UtilMap.getString(documentCorrelates.get(0), "bizCode");//开票申请单编号
+
+        //回写宜搭
+        Map formData = new HashMap();
+        formData.put("radioField_mkxripcc","开票成功");
+        formData.put("textField_mkxripc6",invoiceNumber);
+        formData.put("textField_mm3aixk0",downloadPageUrl);
+
+        if (Strings.isNotBlank(pdfUrl)){
+            String fileName = invoiceNumber + ".pdf";
+            String downloadPath = "d:\\" + fileName;
+            downloadFile(pdfUrl,downloadPath);//下载pdf发票
+
+            String downloadUri = "http://localhost:8080/api/siku/files/"+fileName+"?option=download" + fileName;
+            String previewUri = "http://localhost:8080/api/siku/files/"+fileName+"?option=preview" + fileName;
+
+            Map attachmentField = new HashMap();
+            attachmentField.put("downloadUrl",downloadUri);
+            attachmentField.put("name",fileName);
+            attachmentField.put("previewUrl",previewUri);
+            attachmentField.put("url",downloadUri);
+            attachmentField.put("ext","pdf");
+            formData.put("attachmentField_mkxripc5",Arrays.asList(attachmentField));
+        }
+
+        ydClient.operateData(YDParam.builder()
+                .formInstanceId(bizCode)
+                .searchCondition(JSONObject.toJSONString(UtilMap.map("serialNumberField_mknspz75",lsh)))
+                .formUuid("FORM-A9A47B0365DB437F8F4C8E01B4468220K7GU")
+                .formDataJson(JSONObject.toJSONString(formData))
+                .build(), YDConf.FORM_OPERATION.upsert);
+    }
+
+    //文件下载到本地
+    private void downloadFile(String downloadUri,String downloadPath){
+        try {
+            URL url = new URL(downloadUri);
+
+            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
+            int responseCode = httpConn.getResponseCode();
+
+            // 检查HTTP响应代码是否为200
+            if (responseCode == HttpURLConnection.HTTP_OK) {
+                InputStream inputStream = httpConn.getInputStream();
+                FileOutputStream outputStream = new FileOutputStream(downloadPath);
+
+                byte[] buffer = new byte[4096];
+                int bytesRead = -1;
+
+                while ((bytesRead = inputStream.read(buffer)) != -1) {
+                    outputStream.write(buffer, 0, bytesRead);
+                }
+
+                outputStream.close();
+                inputStream.close();
+            } else {
+                System.out.println("无法下载文件。HTTP响应代码: " + responseCode);
+            }
+            httpConn.disconnect();
+        }catch (Exception e){
+            throw new RuntimeException(e);
+        }
+    }
 }

+ 14 - 11
mjava-siku/src/main/java/com/malk/siku/utils/MkUtil.java

@@ -13,17 +13,20 @@ import java.util.HashMap;
 import java.util.Map;
 
 /**
- * 每刻
+ * 每刻报销
  */
 @Slf4j
-public class MkUtil {
+public class MkBxUtil {
 
-    @Value("${mk.appCode}")
+    @Value("${mk.bx.appCode}")
     private final static String appCode = "AP52Y01LHHTAP9";
 
-    @Value("${mk.appSecret}")
+    @Value("${mk.bx.appSecret}")
     private final static String appSecret = "N4WuERLteAUPaWebnsHy";
 
+//    private final static String host = "ng-uat.maycur.com";//测试环境
+    private final static String host = "ng.maycur.com";//生产环境
+
     private final Object $lock = new Object[0];
 
     private static final Long EXPIRES_IN = 1800000L;
@@ -32,8 +35,8 @@ public class MkUtil {
 
             Map header = new HashMap();
 
-            String tokenId = UtilToken.get("invalid-tokenId-mk");
-            String entCode = UtilToken.get("invalid-entCode-mk");
+            String tokenId = UtilToken.get("invalid-tokenId-mkbx");
+            String entCode = UtilToken.get("invalid-entCode-mkbx");
 
             if (StringUtils.isNotBlank(tokenId) && StringUtils.isNotBlank(entCode)) {
                 header.put("tokenId",tokenId);
@@ -49,18 +52,18 @@ public class MkUtil {
                 body.put("secret",getSecret(appCode,appSecret,timeMillis));
                 body.put("timestamp",timeMillis);
 
-                Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://ng.maycur.com/api/openapi/auth/login", null, null, body));
+                Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/openapi/auth/login", null, null, body));
 
                 Map data = UtilMap.getMap(result, "data");
 
                 tokenId = UtilMap.getString(data, "tokenId");
                 entCode = UtilMap.getString(data, "entCode");
 
-                log.info("每刻tokenId, {}", tokenId);
-                log.info("每刻entCode, {}", entCode);
+                log.info("每刻报销tokenId, {}", tokenId);
+                log.info("每刻报销entCode, {}", entCode);
 
-                UtilToken.put("invalid-tokenId-mk", tokenId, EXPIRES_IN);
-                UtilToken.put("invalid-entCode-mk", entCode, EXPIRES_IN);
+                UtilToken.put("invalid-tokenId-mkbx", tokenId, EXPIRES_IN);
+                UtilToken.put("invalid-entCode-mkbx", entCode, EXPIRES_IN);
 
                 header.put("tokenId",tokenId);
                 header.put("entCode",entCode);

+ 22 - 9
mjava-siku/src/main/java/com/malk/siku/utils/MkYpUtil.java

@@ -18,11 +18,14 @@ import java.util.Map;
 @Slf4j
 public class MkYpUtil {
 
-    @Value("${mk.appCode}")
-    private final static String appCode = "AP52Y01LHHTAP9";
+    @Value("${mk.yp.appCode}")
+    private final static String appCode = "AP53EP1SVDS1N9";
 
-    @Value("${mk.appSecret}")
-    private final static String appSecret = "N4WuERLteAUPaWebnsHy";
+    @Value("${mk.yp.appSecret}")
+    private final static String appSecret = "qF4nm3nPnyXYcrWcr5jl";
+
+    private final static String host = "pms-uat.maycur.com";//测试环境
+//    private final static String host = "pms.maycur.com";//生产环境
 
     private final Object $lock = new Object[0];
 
@@ -36,8 +39,8 @@ public class MkYpUtil {
             String entCode = UtilToken.get("invalid-entCode-mkyp");
 
             if (StringUtils.isNotBlank(tokenId) && StringUtils.isNotBlank(entCode)) {
-                header.put("yptokenId",tokenId);
-                header.put("ypentCode",entCode);
+                header.put("tokenId",tokenId);
+                header.put("entCode",entCode);
 
                 return header;
             } else {
@@ -49,7 +52,7 @@ public class MkYpUtil {
                 body.put("secret",getSecret(appCode,appSecret,timeMillis));
                 body.put("timestamp",timeMillis);
 
-                Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://pms.maycur.com/api/common/openapi/auth/login", null, null, body));
+                Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/common/openapi/auth/login", null, null, body));
 
                 Map data = UtilMap.getMap(result, "data");
 
@@ -62,14 +65,24 @@ public class MkYpUtil {
                 UtilToken.put("invalid-tokenId-mkyp", tokenId, EXPIRES_IN);
                 UtilToken.put("invalid-entCode-mkyp", entCode, EXPIRES_IN);
 
-                header.put("yptokenId",tokenId);
-                header.put("ypentCode",entCode);
+                header.put("tokenId",tokenId);
+                header.put("entCode",entCode);
 
                 return header;
             }
 
     }
 
+
+    public static Map application_oa(Object body){
+        Map result = (Map) JSONObject.parse(UtilHttp.doPost("https://" + host + "/api/ar/openapi/application_oa/batch", MkYpUtil.initTokenHeader(), null, body,(Map) null));
+//        Map result = (Map) JSONObject.parse(UtilHttp.doRequest(UtilHttp.METHOD.POST, "https://" + host + "/api/ar/openapi/application_oa/batch", MkYpUtil.initTokenHeader(), null, body));
+
+        log.info("Result:{}",result);
+
+        return result;
+    }
+
     private static String getSecret(String appCode, String appSecret, long timeMillis){
         log.info("time:{}",timeMillis);
 

+ 9 - 2
mjava-siku/src/main/resources/application-dev.yml

@@ -26,6 +26,13 @@ aliwork:
   systemToken: Y2D66JB1A0B2OMK6OMB29AB8VMP43KJ7UCDKMG46
 
 mk:
-  appCode: AP52Y01LHHTAP9
-  appSecret: N4WuERLteAUPaWebnsHy
+  #每刻报销-生产环境
+  bx:
+    appCode: AP52Y01LHHTAP9
+    appSecret: N4WuERLteAUPaWebnsHy
+  #每刻云票-测试环境
+  yp:
+    appCode: AP53EP1SVDS1N9
+    appSecret: qF4nm3nPnyXYcrWcr5jl
+  downloadFilePath: d:\\
 

+ 8 - 2
mjava-siku/src/main/resources/application-prod.yml

@@ -26,6 +26,12 @@ aliwork:
   systemToken: Y2D66JB1A0B2OMK6OMB29AB8VMP43KJ7UCDKMG46
 
 mk:
-  appCode: AP52Y01LHHTAP9
-  appSecret: N4WuERLteAUPaWebnsHy
+  #每刻报销-生产环境
+  bx:
+    appCode: AP52Y01LHHTAP9
+    appSecret: N4WuERLteAUPaWebnsHy
+  #每刻云票-测试环境
+  yp:
+    appCode: AP53EP1SVDS1N9
+    appSecret: qF4nm3nPnyXYcrWcr5jl
 

+ 1 - 1
mjava-siku/src/main/resources/application.yml

@@ -1,6 +1,6 @@
 spring:
   profiles:
-    active: prod
+    active: dev
   servlet:
     multipart:
       max-file-size: 100MB

+ 11 - 2
mjava-siku/src/test/java/com.malk.siku/SkTest.java

@@ -13,8 +13,15 @@ import org.springframework.test.context.junit4.SpringRunner;
 public class SkTest {
     @Test
     public void getSecret(){
-        String appCode="AP52Y01LHHTAP9";
-        String appSecret="N4WuERLteAUPaWebnsHy";
+        //每刻报销-生产环境
+        /*String appCode="AP52Y01LHHTAP9";
+        String appSecret="N4WuERLteAUPaWebnsHy";*/
+
+
+
+        //每刻云票-测试环境
+        String appCode="AP53EP1SVDS1N9";
+        String appSecret="qF4nm3nPnyXYcrWcr5jl";
 
         long timeMillis = System.currentTimeMillis();
         log.info("time:{}",timeMillis);
@@ -24,4 +31,6 @@ public class SkTest {
     }
 
 
+
+
 }