skyline před 2 roky
rodič
revize
758ab07873
19 změnil soubory, kde provedl 696 přidání a 2 odebrání
  1. 10 0
      common/src/main/java/com/kym/common/utils/HttpUtil.java
  2. 5 0
      entity/src/main/java/com/kym/entity/miniapp/ChargeOrder.java
  3. 90 0
      entity/src/main/java/com/kym/entity/miniapp/Invoice.java
  4. 33 0
      entity/src/main/java/com/kym/entity/miniapp/InvoiceOrder.java
  5. 162 0
      entity/src/main/java/com/kym/entity/wechat/FaPiao.java
  6. 74 0
      entity/src/main/java/com/kym/entity/wechat/InvoiceBaseInfo.java
  7. 77 0
      entity/src/main/java/com/kym/entity/wechat/TaxCodes.java
  8. 16 0
      mapper/src/main/java/com/kym/mapper/miniapp/InvoiceMapper.java
  9. 16 0
      mapper/src/main/java/com/kym/mapper/miniapp/InvoiceOrderMapper.java
  10. 3 2
      mapper/src/main/resources/mappers/miniapp/ChargeOrderMapper.xml
  11. 27 0
      mapper/src/main/resources/mappers/miniapp/InvoiceMapper.xml
  12. 16 0
      mapper/src/main/resources/mappers/miniapp/InvoiceOrderMapper.xml
  13. 18 0
      miniapp/src/main/java/com/kym/miniapp/controller/InvoiceController.java
  14. 18 0
      miniapp/src/main/java/com/kym/miniapp/controller/InvoiceOrderController.java
  15. 16 0
      service/src/main/java/com/kym/service/miniapp/InvoiceOrderService.java
  16. 16 0
      service/src/main/java/com/kym/service/miniapp/InvoiceService.java
  17. 20 0
      service/src/main/java/com/kym/service/miniapp/impl/InvoiceOrderServiceImpl.java
  18. 20 0
      service/src/main/java/com/kym/service/miniapp/impl/InvoiceServiceImpl.java
  19. 59 0
      service/src/main/java/com/kym/service/wechat/impl/WxPayServiceImpl.java

+ 10 - 0
common/src/main/java/com/kym/common/utils/HttpUtil.java

@@ -70,6 +70,16 @@ public class HttpUtil {
         return synchronizedCall(request);
     }
 
+    public static String post(String url, Headers headers) {
+        Request request = new Request.Builder()
+                .headers(headers)
+                .post(okhttp3.internal.Util.EMPTY_REQUEST)
+                .url(url)
+                .build();
+
+        return synchronizedCall(request);
+    }
+
     public static <T> T post(String url, Map params, Class<T> clz) {
 
         RequestBody requestBody = RequestBody.create(JSON, JSONObject.toJSONString(params));

+ 5 - 0
entity/src/main/java/com/kym/entity/miniapp/ChargeOrder.java

@@ -119,4 +119,9 @@ public class ChargeOrder extends BaseEntity implements Serializable {
      * 发票状态:0:未开票 1:已开票
      */
     private Integer invoiceStatus;
+
+    /**
+     * 发票id
+     */
+    private Integer invoiceId;
 }

+ 90 - 0
entity/src/main/java/com/kym/entity/miniapp/Invoice.java

@@ -0,0 +1,90 @@
+package com.kym.entity.miniapp;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.kym.entity.BaseEntity;
+import java.io.Serializable;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 发票记录表
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-09-15
+ */
+@Getter
+@Setter
+@TableName("t_invoice")
+public class Invoice extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long userId;
+
+    /**
+     * 充电订单号(EN+)
+     */
+    private String startChargeSeq;
+
+    /**
+     * 累积充电量(度)
+     */
+    private Double totalPower;
+
+    /**
+     * 累积总金额(元)
+     */
+    private Integer totalMoney;
+
+    /**
+     * 累积电费(元)
+     */
+    private Integer elecMoney;
+
+    /**
+     * 累积服务费(元)
+     */
+    private Integer serviceMoney;
+
+    /**
+     * 接收发票邮箱
+     */
+    private String email;
+
+    /**
+     * 发票类型:0-个人 1-企业
+     */
+    private Byte invoiceType;
+
+    /**
+     * 发票抬头
+     */
+    private String invoiceTitle;
+
+    /**
+     * 公司税号
+     */
+    private String taxId;
+
+    /**
+     * 发票金额(单位:分)
+     */
+    private Integer invoiceAmount;
+
+    /**
+     * 税额详情信息
+     */
+    private String taxInfo;
+
+    /**
+     * 开票人
+     */
+    private String biller;
+
+    /**
+     * 备注
+     */
+    private String remark;
+}

+ 33 - 0
entity/src/main/java/com/kym/entity/miniapp/InvoiceOrder.java

@@ -0,0 +1,33 @@
+package com.kym.entity.miniapp;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.kym.entity.BaseEntity;
+import java.io.Serializable;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 发票记录表
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-09-15
+ */
+@Getter
+@Setter
+@TableName("t_invoice_order")
+public class InvoiceOrder extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 发票id
+     */
+    private Long invoiceId;
+
+    /**
+     * 充电订单号(EN+)
+     */
+    private String startChargeSeq;
+}

+ 162 - 0
entity/src/main/java/com/kym/entity/wechat/FaPiao.java

@@ -0,0 +1,162 @@
+package com.kym.entity.wechat;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * @author skyline
+ * @description 微信区块链电子发票
+ * @date 2023-09-16 14:14
+ */
+@Data
+@Accessors(chain = true)
+public class FaPiao {
+
+    /**
+     * 微信支付分配的子商户号,服务商模式下必传
+     * 选填
+     */
+    private String sub_mchid;
+
+    /**
+     * 开票场景
+     * 可选取值:
+     * WITH_WECHATPAY: 微信支付场景
+     * WITHOUT_WECHATPAY: 非微信支付场景
+     */
+    private String scene;
+
+    /**
+     * 发票申请单号,唯一标识一次开票行为。当开票场景为WITHOUT_WECHATPAY时,
+     * 为调用【获取抬头填写链接】接口时指定的发票申请单号;当开票场景为WITH_WECHATPAY时,
+     * 为与本次开票关联的微信支付订单号,且必须是属于相应商户的订单(服务商模式下该订单必须属于子商户;
+     * 直连模式下该订单必须属于直连商户)
+     */
+    private String fapiao_apply_id;
+
+    /**
+     * 购买方信息,即发票抬头。若商户使用微信官方抬头,可从【获取用户填写的抬头】接口获取用户填写的抬头;也可自行收集发票抬头
+     */
+    private List<BuyerInformation> buyer_information;
+
+    /**
+     * 需要开具的发票信息。注意:同一个开票申请单最多申请5张发票
+     */
+    private List<FaPiaoInfomation> fapiao_information;
+
+
+    /**
+     * 购买方信息,即发票抬头。若商户使用微信官方抬头,可从【获取用户填写的抬头】接口获取用户填写的抬头;也可自行收集发票抬头
+     */
+    @Data
+    @Accessors(chain = true)
+    public class BuyerInformation{
+        /**
+         * INDIVIDUAL: 个人
+         * ORGANIZATION: 单位
+         * 必填
+         */
+        private String type;
+
+        /**
+         * 购买方名称(256)
+         * 必填
+         */
+        private String name;
+
+        /**
+         * 购买方纳税人识别号,购买方类型为ORGANIZATION时必须存在(32)
+         */
+        private String taxpayer_id;
+
+        /**
+         * 购买方地址(128)
+         */
+        private String address;
+
+        /**
+         * 购买方电话(32)
+         */
+        private String telephone;
+
+        /**
+         * 购买方开户银行(32)
+         */
+        private String bank_name;
+
+        /**
+         * 购买方银行账号(32)
+         */
+        private String bank_account;
+
+        /**
+         * 用户手机号。注意:该字段为密文字段,加解密算法请参见《微信支付V3版规范》
+         */
+        private String phone;
+
+        /**
+         * 用户邮箱地址。注意:该字段为密文字段,加解密算法请参见《微信支付V3版规范》
+         */
+        private String email;
+    }
+
+
+    @Data
+    @Accessors(chain = true)
+    public class FaPiaoInfomation{
+
+        /**
+         * 商户发票单号,唯一标识一张要开具的发票。只能是字母、数字、中划线-、下划线_、竖线|、星号*
+         * 这些英文半角字符,且该单号在每个商户下必须唯一
+         */
+        private String fapiao_id;
+
+        /**
+         * 总价税合计,所有发票行单行金额合计的累加,展示在发票的价税合计处,单位:分
+         * 注意:若是微信支付后开票,所有发票的总价税合计之和不能超过对应的微信支付单总金额;
+         * 若是非微信支付开票,所有发票的总价税合计之和不能超过【获取抬头填写链接】接口中指定的总金额
+         */
+        private int total_amount;
+
+        /**
+         * 发票行信息,单张发票的发票行不能超过8行
+         */
+        private List<IssueItem> items;
+
+        @Data
+        @Accessors(chain = true)
+        public class IssueItem {
+
+            /**
+             * 【税局侧规定的货物或应税劳务、服务税收分类编码】
+             * 税局侧规定的货物或应税劳务、服务税收分类编码。
+             * 可自行指定符合税务部门规定的货物或应税劳务、服务编码;
+             * 若使用在电子发票商户平台配置的商品类型,需要从接口【获取商户可开具的商品和服务税收分类编码对照表】获得商户已配置的编码;
+             * 若该行为折扣行,必须与被折扣行的编码相同。
+             */
+            private String taxCode;
+
+            /**
+             * 数量,展示在发票中间的数量列,单位为10^-8^,100000000表示数量为1。
+             * 若是折扣行或者没有数量概念,则默认为100000000
+             */
+            private String quantity;
+
+            /**
+             * 单行金额和税费的和,折扣行的金额为负数,非折扣行的金额为正数,单位:分
+             */
+            private int totalAmount;
+
+            /**
+             * 指定该发票行是否折扣行,折扣行必须是被折扣行的下一行
+             */
+            private boolean discount = false;
+
+        }
+
+    }
+
+
+}

+ 74 - 0
entity/src/main/java/com/kym/entity/wechat/InvoiceBaseInfo.java

@@ -0,0 +1,74 @@
+package com.kym.entity.wechat;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author skyline
+ * @description
+ * @date 2023-09-17 01:38
+ */
+@Data
+@Accessors(chain = true)
+public class InvoiceBaseInfo {
+
+    /**
+     *  商户配置的销售方信息,展示在电子发票的销售方中
+     */
+    private SellerInfo seller_information;
+
+    @Data
+    @Accessors(chain = true)
+    class SellerInfo{
+
+        /**
+         * 销售方名称
+         */
+        private String name;
+
+        /**
+         * 销售方纳税人识别号
+         */
+        private String taxpayer_id;
+
+        /**
+         * 销售方地址
+         */
+        private String address;
+
+        /**
+         * 销售方电话
+         */
+        private String telephone;
+
+        /**
+         * 销售方开户银行
+         */
+        private String bank_name;
+
+    }
+
+    /**
+     * 商户配置的开票附加信息,展示在电子发票下方
+     */
+    private ExtraInfo extra_information;
+
+    @Data
+    @Accessors(chain = true)
+    class ExtraInfo{
+
+        /**
+         * 收款人
+         */
+        private String payee;
+        /**
+         * 复核人
+         */
+        private String reviewer;
+        /**
+         * 开票人
+         */
+        private String drawer;
+    }
+
+}

+ 77 - 0
entity/src/main/java/com/kym/entity/wechat/TaxCodes.java

@@ -0,0 +1,77 @@
+package com.kym.entity.wechat;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * @author skyline
+ * @description 商品及税收分类编码
+ * @date 2023-09-16 23:22
+ */
+@Data
+@Accessors(chain = true)
+public class TaxCodes {
+
+    /**
+     * 本次查询的起始位置
+     */
+    private int offset;
+
+    /**
+     * 本次查询的最大数量
+     */
+    private int limit;
+
+    /**
+     * 本次查询到的商品及税收分类编码对照表
+     */
+    private List<TaxCodeItem> data;
+
+    /**
+     * 总记录数
+     */
+    private int total_count;
+
+
+    public class TaxCodeItem {
+        /**
+         * 由商户自定义的货物或应税劳务、服务名称
+         */
+        private String goods_name;
+
+        /**
+         * 企业侧维护的货物或应税劳务、服务编码。
+         * 若使用在电子发票商户平台配置的商品类型进行开票时,需要传该编号
+         */
+        private int goods_id;
+
+        /**
+         * 税局侧规定的货物或应税劳务、服务分类名称
+         */
+        private String goods_category;
+
+        /**
+         * 税局侧规定的货物或应税劳务、服务税收分类编码
+         */
+        private int tax_code;
+
+        /**
+         * 税率,单位为万分之一,如1300代表13%
+         */
+        private int tax_rate;
+
+        /**
+         * 税收优惠政策标识
+         * 可选取值:
+         * NO_FAVORABLE: 无优惠
+         * OUTSIDE_VAT: 不征税
+         * VAT_EXEMPT: 免税
+         * NORMAL_ZERO_RATED: 普通零税率
+         * EXPORT_ZERO_RATED: 出口零税率
+         */
+        private String tax_prefer_mark;
+
+    }
+}

+ 16 - 0
mapper/src/main/java/com/kym/mapper/miniapp/InvoiceMapper.java

@@ -0,0 +1,16 @@
+package com.kym.mapper.miniapp;
+
+import com.kym.entity.miniapp.Invoice;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 发票记录表 Mapper 接口
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-09-15
+ */
+public interface InvoiceMapper extends BaseMapper<Invoice> {
+
+}

+ 16 - 0
mapper/src/main/java/com/kym/mapper/miniapp/InvoiceOrderMapper.java

@@ -0,0 +1,16 @@
+package com.kym.mapper.miniapp;
+
+import com.kym.entity.miniapp.InvoiceOrder;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * <p>
+ * 发票记录表 Mapper 接口
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-09-15
+ */
+public interface InvoiceOrderMapper extends BaseMapper<InvoiceOrder> {
+
+}

+ 3 - 2
mapper/src/main/resources/mappers/miniapp/ChargeOrderMapper.xml

@@ -21,6 +21,8 @@
         <result column="order_status" property="orderStatus"/>
         <result column="charge_status" property="chargeStatus"/>
         <result column="stop_reason" property="stopReason"/>
+        <result column="invoice_status" property="invoiceStatus"/>
+        <result column="invoice_id" property="invoiceId"/>
         <result column="create_time" property="createTime"/>
         <result column="update_time" property="updateTime"/>
     </resultMap>
@@ -53,8 +55,7 @@
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id
-        , user_id, station_id, start_charge_seq, connector_id, start_time, end_time, soc, total_power, total_money, elec_money, service_money, sum_period, charge_detail, order_status, charge_status, stop_reason, create_time, update_time
+        id, user_id, station_id, start_charge_seq, connector_id, start_time, end_time, soc, total_power, total_money, elec_money, service_money, sum_period, charge_detail, order_status, charge_status, stop_reason, invoice_status,invoice_id,create_time, update_time
     </sql>
 
     <select id="listChargeOrders" resultMap="CustomChargeOrderMap"

+ 27 - 0
mapper/src/main/resources/mappers/miniapp/InvoiceMapper.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.kym.mapper.miniapp.InvoiceMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.kym.entity.miniapp.Invoice">
+        <result column="user_id" property="userId" />
+        <result column="start_charge_seq" property="startChargeSeq" />
+        <result column="total_power" property="totalPower" />
+        <result column="total_money" property="totalMoney" />
+        <result column="elec_money" property="elecMoney" />
+        <result column="service_money" property="serviceMoney" />
+        <result column="email" property="email" />
+        <result column="invoice_type" property="invoiceType" />
+        <result column="invoice_title" property="invoiceTitle" />
+        <result column="tax_id" property="taxId" />
+        <result column="invoice_amount" property="invoiceAmount" />
+        <result column="tax_info" property="taxInfo" />
+        <result column="biller" property="biller" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id,user_id, start_charge_seq, total_power, total_money, elec_money, service_money, email, invoice_type, invoice_title, tax_id, invoice_amount, tax_info, biller,remark,create_time,update_time
+    </sql>
+
+</mapper>

+ 16 - 0
mapper/src/main/resources/mappers/miniapp/InvoiceOrderMapper.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.kym.mapper.miniapp.InvoiceOrderMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.kym.entity.miniapp.InvoiceOrder">
+        <result column="invoice_id" property="invoiceId" />
+        <result column="start_charge_seq" property="startChargeSeq" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        invoice_id, start_charge_seq
+    </sql>
+
+</mapper>

+ 18 - 0
miniapp/src/main/java/com/kym/miniapp/controller/InvoiceController.java

@@ -0,0 +1,18 @@
+package com.kym.miniapp.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 发票记录表 前端控制器
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-09-15
+ */
+@RestController
+@RequestMapping("/invoice")
+public class InvoiceController {
+
+}

+ 18 - 0
miniapp/src/main/java/com/kym/miniapp/controller/InvoiceOrderController.java

@@ -0,0 +1,18 @@
+package com.kym.miniapp.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 发票记录表 前端控制器
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-09-15
+ */
+@RestController
+@RequestMapping("/invoice-order")
+public class InvoiceOrderController {
+
+}

+ 16 - 0
service/src/main/java/com/kym/service/miniapp/InvoiceOrderService.java

@@ -0,0 +1,16 @@
+package com.kym.service.miniapp;
+
+import com.kym.entity.miniapp.InvoiceOrder;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 发票记录表 服务类
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-09-15
+ */
+public interface InvoiceOrderService extends IService<InvoiceOrder> {
+
+}

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

@@ -0,0 +1,16 @@
+package com.kym.service.miniapp;
+
+import com.kym.entity.miniapp.Invoice;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 发票记录表 服务类
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-09-15
+ */
+public interface InvoiceService extends IService<Invoice> {
+
+}

+ 20 - 0
service/src/main/java/com/kym/service/miniapp/impl/InvoiceOrderServiceImpl.java

@@ -0,0 +1,20 @@
+package com.kym.service.miniapp.impl;
+
+import com.kym.entity.miniapp.InvoiceOrder;
+import com.kym.mapper.miniapp.InvoiceOrderMapper;
+import com.kym.service.miniapp.InvoiceOrderService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 发票记录表 服务实现类
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-09-15
+ */
+@Service
+public class InvoiceOrderServiceImpl extends ServiceImpl<InvoiceOrderMapper, InvoiceOrder> implements InvoiceOrderService {
+
+}

+ 20 - 0
service/src/main/java/com/kym/service/miniapp/impl/InvoiceServiceImpl.java

@@ -0,0 +1,20 @@
+package com.kym.service.miniapp.impl;
+
+import com.kym.entity.miniapp.Invoice;
+import com.kym.mapper.miniapp.InvoiceMapper;
+import com.kym.service.miniapp.InvoiceService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 发票记录表 服务实现类
+ * </p>
+ *
+ * @author skyline
+ * @since 2023-09-15
+ */
+@Service
+public class InvoiceServiceImpl extends ServiceImpl<InvoiceMapper, Invoice> implements InvoiceService {
+
+}

+ 59 - 0
service/src/main/java/com/kym/service/wechat/impl/WxPayServiceImpl.java

@@ -12,12 +12,16 @@ import com.kym.common.config.WxPayConfig;
 import com.kym.common.constant.ResponseEnum;
 import com.kym.common.exception.BusinessException;
 import com.kym.common.utils.CommUtil;
+import com.kym.common.utils.HttpUtil;
 import com.kym.common.utils.LambadaTools;
 import com.kym.common.utils.OrderUtils;
 import com.kym.entity.miniapp.Account;
 import com.kym.entity.miniapp.PayLog;
 import com.kym.entity.miniapp.RefundLog;
 import com.kym.entity.miniapp.WalletDetail;
+import com.kym.entity.wechat.FaPiao;
+import com.kym.entity.wechat.InvoiceBaseInfo;
+import com.kym.entity.wechat.TaxCodes;
 import com.kym.service.miniapp.*;
 import com.kym.service.wechat.WxPayService;
 import com.wechat.pay.java.core.Config;
@@ -36,6 +40,7 @@ import com.wechat.pay.java.service.refund.model.*;
 import jakarta.annotation.PostConstruct;
 import jakarta.servlet.http.HttpServletRequest;
 import lombok.SneakyThrows;
+import okhttp3.Headers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.core.io.ClassPathResource;
@@ -498,4 +503,58 @@ public class WxPayServiceImpl implements WxPayService {
             throw new BusinessException("验签失败");
         }
     }
+
+
+    /**
+     * 获取商户开票基础信息
+     */
+    private InvoiceBaseInfo baseInformation() {
+        var url = "https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/base-information";
+        Headers headers = Headers.of(
+                "Authorization", "",
+                "Accept", "application/json",
+                "Content-Type", "application/json"
+        );
+        var res = HttpUtil.post(url, headers);
+        return JSONObject.parseObject(res).toJavaObject(InvoiceBaseInfo.class);
+    }
+
+
+    /**
+     * 获取商户可开具的商品和服务税收分类编码对照表
+     */
+    private TaxCodes.TaxCodeItem getTaxCodes() {
+        var url = "https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/merchant/tax-codes";
+        Headers headers = Headers.of(
+                "Authorization", "",
+                "Accept", "application/json"
+        );
+        var params = """
+                {
+                    "offset" : %d,
+                    "limit" :%d
+                }
+                """.stripIndent().formatted(0, 100);
+        var res = HttpUtil.post(url, params, headers);
+        return JSONObject.parseObject(res).toJavaObject(TaxCodes.TaxCodeItem.class);
+    }
+
+
+    /**
+     * 申请发票
+     */
+    public void applyInvoice() {
+        var url = "https://api.mch.weixin.qq.com/v3/new-tax-control-fapiao/fapiao-applications";
+        Headers headers = Headers.of(
+                "Authorization", "",
+                "Accept", "application/json",
+                "Content-Type", "application/json",
+                "Wechatpay-Serial", "6A45EEB068369430B2FFD45EA29F641A8E18165F"
+        );
+
+        var invoiceId = OrderUtils.getOrderNo();
+        var fapiao = new FaPiao();
+        var res = HttpUtil.post(url, JSONObject.toJSONString(fapiao), headers);
+    }
+
 }