Bladeren bron

微信电子发票部分代码

skyline 2 jaren geleden
bovenliggende
commit
d3de93a951

+ 1 - 1
admin/src/main/resources/application-dev.yml

@@ -40,7 +40,7 @@ wechat:
     baseInformation: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/base-information
     taxCodes: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/tax-codes
     fapiaoApplications: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications
-    notifyUrl: https://dev-cloud.kuaiyuman.cn/admin/finance/fapiaoNotify
+    notifyUrl: https://dev-cloud.kuaiyuman.cn/api/invoice/notify
     devConfig: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/development-config
     fapiaoFiles: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications/%s/fapiao-files
     queryFapiao: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications/%s

+ 27 - 5
miniapp/src/main/java/com/kym/miniapp/controller/InvoiceController.java

@@ -3,11 +3,9 @@ package com.kym.miniapp.controller;
 import com.kym.common.R;
 import com.kym.entity.miniapp.params.ApplyInvoiceParams;
 import com.kym.service.miniapp.InvoiceService;
+import com.kym.service.wechat.WxPayService;
 import jakarta.servlet.http.HttpServletRequest;
-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.web.bind.annotation.*;
 
 /**
  * <p>
@@ -23,10 +21,22 @@ public class InvoiceController {
 
     private final InvoiceService invoiceService;
 
-    public InvoiceController(InvoiceService invoiceService) {
+    private final WxPayService wxPayService;
+
+    public InvoiceController(InvoiceService invoiceService, WxPayService wxPayService) {
         this.invoiceService = invoiceService;
+        this.wxPayService = wxPayService;
+    }
+
+    @GetMapping("test1")
+    R<?> test1(HttpServletRequest request) {
+        return R.success(wxPayService.devConfig());
     }
 
+    @GetMapping("test2")
+    R<?> test2(HttpServletRequest request) {
+        return R.success(wxPayService.getDevConfig());
+    }
 
     /**
      * 用户发票抬头填写完成通知
@@ -50,4 +60,16 @@ public class InvoiceController {
         return R.success(invoiceService.applyInvoice(params));
     }
 
+    /**
+     * 接收发票相关通知
+     *
+     * @param request
+     * @return
+     */
+    @PostMapping("/notify")
+    R<?> invoiceNotify(HttpServletRequest request) {
+//        wxPayService.invoiceNotify(request);
+        return R.success();
+    }
+
 }

+ 10 - 0
miniapp/src/main/resources/application-dev.yml

@@ -36,6 +36,16 @@ wechat:
     aesKey: #微信小程序消息服务器配置的EncodingAESKey
     msgDataFormat: JSON
 
+  fapiao:
+    baseInformation: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/base-information
+    taxCodes: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/tax-codes
+    fapiaoApplications: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications
+    notifyUrl: https://dev-cloud.kuaiyuman.cn/api/invoice/notify
+    devConfig: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/development-config
+    fapiaoFiles: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications/%s/fapiao-files
+    queryFapiao: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications/%s
+    titleUrl: https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/user-title/title-url
+
 spring:
   datasource:
     druid: #以下是全局默认值,可以全局更改

+ 1 - 0
service/src/main/java/com/kym/service/miniapp/InvoiceService.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.kym.entity.miniapp.Invoice;
 import com.kym.entity.miniapp.params.ApplyInvoiceParams;
 import com.kym.entity.wechat.TitleUrl;
+import jakarta.servlet.http.HttpServletRequest;
 
 /**
  * <p>

+ 17 - 4
service/src/main/java/com/kym/service/miniapp/impl/InvoiceServiceImpl.java

@@ -14,7 +14,9 @@ import com.kym.mapper.miniapp.InvoiceMapper;
 import com.kym.service.miniapp.ChargeOrderService;
 import com.kym.service.miniapp.InvoiceService;
 import com.kym.service.wechat.WxPayService;
+import jakarta.servlet.http.HttpServletRequest;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 
 /**
@@ -33,21 +35,32 @@ public class InvoiceServiceImpl extends ServiceImpl<InvoiceMapper, Invoice> impl
     private final ChargeOrderService chargeOrderService;
     private final WxPayService wxPayService;
 
-    public InvoiceServiceImpl(ChargeOrderService chargeOrderService, WxPayService wxPayService) {
+    public InvoiceServiceImpl(ChargeOrderService chargeOrderService, @Lazy WxPayService wxPayService) {
         this.chargeOrderService = chargeOrderService;
         this.wxPayService = wxPayService;
     }
 
 
+    /**
+     * 申请发票
+     * 业务流程:
+     * 1.校验订单
+     * 2.数据库写入invoice对象
+     * 3.api获取填写抬头的链接给前端
+     * 4.前端打开上一步返回的填写链接,客户填写抬头信息
+     * 5.接收抬头填写完成的通知,将抬头信息更新至第2步写入的invoice数据中
+     * 6.运营系统财务人员审核之后确认开票,请求api进行电子发票开票操作
+     *
+     * @param params
+     * @return
+     */
     @Override
     public TitleUrl applyInvoice(ApplyInvoiceParams params) {
-        // TODO: 2023-10-12 抬头信息去微信接口获取
-
         // orderDetails 获取申请开票的订单
         var userId = StpUtil.getLoginIdAsLong();
         var orders = chargeOrderService.getChargeOrdersBySeqs(params.getStartChargeSeqs());
 
-        // 校验订单是未开票
+        // 校验订单是未开票或者开票中
         var invoiced = orders.stream().filter(o -> o.getInvoiceStatus().equals(ChargeOrder.INVOICE_STATUS_开票中) || o.getInvoiceStatus().equals(ChargeOrder.INVOICE_STATUS_已开票)).toList();
         if (!invoiced.isEmpty()) {
             log.error("存在已开票的订单:{}", invoiced.stream().map(ChargeOrder::getStartChargeSeq).toArray());

+ 5 - 0
service/src/main/java/com/kym/service/wechat/WxPayService.java

@@ -31,6 +31,10 @@ public interface WxPayService {
     void wxNotify(HttpServletRequest request) throws IOException;
 
 
+    Object devConfig();
+
+    Object getDevConfig();
+
     //================================================================发票=====================================================================
     // TODO: 2023-10-12 补充数据
     TitleUrl titleUrl(Invoice invoice);
@@ -43,4 +47,5 @@ public interface WxPayService {
 
     void wxInvoiceNotify(HttpServletRequest request);
 
+    void invoiceNotify(HttpServletRequest request);
 }

+ 49 - 17
service/src/main/java/com/kym/service/wechat/impl/WxPayServiceImpl.java

@@ -28,6 +28,7 @@ import com.wechat.pay.java.core.http.DefaultHttpClientBuilder;
 import com.wechat.pay.java.core.http.HttpHeaders;
 import com.wechat.pay.java.core.http.JsonRequestBody;
 import com.wechat.pay.java.core.http.okhttp.OkHttpClientAdapter;
+import com.wechat.pay.java.core.notification.Notification;
 import com.wechat.pay.java.core.notification.NotificationConfig;
 import com.wechat.pay.java.core.notification.NotificationParser;
 import com.wechat.pay.java.core.notification.RequestParam;
@@ -530,6 +531,34 @@ public class WxPayServiceImpl implements WxPayService {
 
     //================================================================发票=====================================================================
 
+    /**
+     * 微信电子发票配置开发选项,例如回调地址、全部账单展示开发票入口开关
+     */
+    @Override
+    public Object devConfig() {
+        var headers = new HttpHeaders();
+        headers.addHeader("Accept", "application/json");
+        headers.addHeader("Content-Type", "application/json");
+        var params = JSONObject.of("callback_url", fapiaoConfig.getNotifyUrl(), "show_fapiao_cell", false);
+        var requestBody = new JsonRequestBody.Builder().body(params.toJSONString()).build();
+        var res = wxHttpClient.patch(headers, fapiaoConfig.getDevConfig(), requestBody, JSONObject.class);
+        LOGGER.info("微信电子发票开发设置:{}", res.toString());
+        return res.getServiceResponse();
+    }
+
+    /**
+     * 查询商户配置的开发选项
+     */
+    @Override
+    public Object getDevConfig() {
+        var headers = new HttpHeaders();
+        headers.addHeader("Accept", "application/json");
+        headers.addHeader("Content-Type", "application/json");
+        var res = wxHttpClient.get(headers, fapiaoConfig.getDevConfig(), JSONObject.class);
+        LOGGER.info("查询微信电子发票开发设置:{}", res.toString());
+        return res;
+    }
+
     /**
      * 获取用户抬头信息填写URL
      *
@@ -554,6 +583,7 @@ public class WxPayServiceImpl implements WxPayService {
 
     /**
      * 处理发票抬头填写完成通知
+     * event_type为FAPIAO.USER_APPLIED
      *
      * @param request
      */
@@ -684,6 +714,7 @@ public class WxPayServiceImpl implements WxPayService {
 
     /**
      * 微信开票结果通知
+     * event_tyoe为FAPIAO.ISSUED
      *
      * @param request
      * @return
@@ -708,27 +739,28 @@ public class WxPayServiceImpl implements WxPayService {
         }
     }
 
-
     /**
-     * 微信电子发票配置开发选项,例如回调地址、全部账单展示开发票入口开关
+     * 接收电子发票相关回调通知
+     * @param request
      */
-    void devConfig() {
-        var headers = new HttpHeaders();
-        headers.addHeader("Accept", "application/json");
-        headers.addHeader("Content-Type", "application/json");
-
-        var params = """
-                {
-                  "callback_url" : %s,
-                  "show_fapiao_cell" : false
-                }
-                """.stripIndent().formatted(fapiaoConfig.getNotifyUrl());
-        var requestBody = new JsonRequestBody.Builder().body(params).build();
-        var res = wxHttpClient.patch(headers, fapiaoConfig.getDevConfig(), requestBody, JSONObject.class);
-        LOGGER.info("微信电子发票开发设置:{}", res.toString());
-        // TODO: 2023-10-07 业务逻辑
+    @Override
+    public void invoiceNotify(HttpServletRequest request) {
+        var notifyRes = handleWxNotify(request);
+        var requestParam = (RequestParam) notifyRes[0];
+        Notification notification = JSONObject.parseObject(requestParam.getBody(), Notification.class);
+        switch (notification.getEventType()) {
+            // 发票抬头填写完成
+            case "FAPIAO.USER_APPLIED":
+                titleWriteNotice(request);
+                // 发票开具结果
+            case "FAPIAO.ISSUED":
+                wxInvoiceNotify(request);
+            default:
+                throw new IllegalStateException("Unexpected value: " + notification.getEventType());
+        }
     }
 
+
     // TODO: 2023-10-07 下载发票
     void downloadInvoice(String invoiceId) {
         var invoice = invoiceService.getById(invoiceId);