Просмотр исходного кода

:new: #2646 【微信支付】增加报关v3接口

leif Yi 3 лет назад
Родитель
Сommit
dfec57f200

+ 125 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationQueryRequest.java

@@ -0,0 +1,125 @@
+package com.github.binarywang.wxpay.bean.customs;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * @author xifenzhu
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class DeclarationQueryRequest implements Serializable {
+
+  private static final long serialVersionUID = -251403491989628142L;
+  /**
+   * <pre>
+   * 字段名:机构APPID
+   * 变量名:appid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "appid")
+  private String appid;
+
+  /**
+   * <pre>
+   * 字段名:商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信支付分配的商户号
+   *  示例值:1230000109
+   * </pre>
+   */
+  @SerializedName(value = "mchid")
+  private String mchid;
+
+  /**
+   * <pre>
+   * 字段名:订单类型
+   * 变量名:order_type
+   * 是否必填:是
+   * 类型:string(16)
+   * 描述:
+   *  4种订单号类型,选择一种
+   *  out_trade_no   商户订单号
+   *  transaction_id  微信支付订单号
+   *  sub_order_no  商户子订单号
+   *  sub_order_id  微信子订单号
+   *  示例值:out_trade_no
+   * </pre>
+   */
+  @SerializedName(value = "order_type")
+  private String orderType;
+
+  /**
+   * <pre>
+   * 字段名:订单号
+   * 变量名:order_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  根据订单号类型,传入不同的订单号码
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "order_no")
+  private String orderNo;
+
+  /**
+   * <pre>
+   * 字段名:海关
+   * 变量名:customs
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  海关代码, 枚举值参见参数规定-海关列表(https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter2_3.shtml#menu11)
+   *  示例值:SHANGHAI_ZS
+   * </pre>
+   */
+  @SerializedName(value = "customs")
+  private String customs;
+
+  /**
+   * <pre>
+   * 字段名:偏移量
+   * 变量名:offset
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  非0整数,该次请求资源的起始位置,从0开始计数。调用方选填,默认为0
+   *  示例值:0
+   * </pre>
+   */
+  @SerializedName(value = "offset")
+  private String offset;
+
+  /**
+   * <pre>
+   * 字段名:请求最大记录条数
+   * 变量名:limit
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  非0非负的整数,该次请求可返回的最大资源条数。调用方选填,默认值建议为20
+   *  示例值:20
+   * </pre>
+   */
+  @SerializedName(value = "limit")
+  private String limit;
+
+}

+ 337 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationQueryResult.java

@@ -0,0 +1,337 @@
+package com.github.binarywang.wxpay.bean.customs;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author xifenzhu
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class DeclarationQueryResult implements Serializable {
+
+  private static final long serialVersionUID = 7776809282150143165L;
+  /**
+   * <pre>
+   * 字段名:机构APPID
+   * 变量名:appid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "appid")
+  private String appid;
+
+  /**
+   * <pre>
+   * 字段名:商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信支付分配的商户号
+   *  示例值:1230000109
+   * </pre>
+   */
+  @SerializedName(value = "mchid")
+  private String mchid;
+
+  /**
+   * <pre>
+   * 字段名:微信支付返回的订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:1000320306201511078440737890
+   * </pre>
+   */
+  @SerializedName(value = "transaction_id")
+  private String transactionId;
+
+  /**
+   * <pre>
+   * 字段名:核验机构
+   * 变量名:verify_department
+   * 是否必填:是
+   * 类型:string(16)
+   * 描述:
+   *  核验机构代码
+   *  UNIONPAY:银联
+   *  NETSUNION:网联
+   *  OTHERS:其他
+   *  示例值:UNIONPAY
+   * </pre>
+   */
+  @SerializedName(value = "verify_department")
+  private String verifyDepartment;
+
+  /**
+   * <pre>
+   * 字段名:核验机构交易流水号
+   * 变量名:Verify_department_trade_id
+   * 是否必填:是
+   * 类型:string(64)
+   * 描述:
+   *  交易流水号,来自验核机构,如银联记录的交易流水号,供商户报备海关
+   *  示例值:2018112288340107038204310100000
+   * </pre>
+   */
+  @SerializedName(value = "verify_department_trade_id")
+  private String verifyDepartmentTradeId;
+
+  /**
+   * <pre>
+   * 字段名:偏移量
+   * 变量名:offset
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  非0整数,该次请求资源的起始位置,从0开始计数。调用方选填,默认为0
+   *  示例值:0
+   * </pre>
+   */
+  @SerializedName(value = "offset")
+  private Integer offset;
+
+  /**
+   * <pre>
+   * 字段名:请求最大记录条数
+   * 变量名:limit
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  非0非负的整数,该次请求可返回的最大资源条数。调用方选填,默认值建议为20
+   *  示例值:20
+   * </pre>
+   */
+  @SerializedName(value = "limit")
+  private Integer limit;
+
+  /**
+   * <pre>
+   * 字段名:查询结果总条数
+   * 变量名:total_count
+   * 是否必填:是
+   * 类型:int
+   * 描述:
+   *  查询结果总条数
+   *  示例值:1
+   * </pre>
+   */
+  @SerializedName(value = "total_count")
+  private Integer totalCount;
+
+  /**
+   * <pre>
+   * 字段名:报关数据包
+   * 变量名:data
+   * 是否必填:是
+   * 类型:array
+   * 描述:
+   *  报关单结果数组,具体内容参见下方描述
+   *  示例值:
+   * </pre>
+   */
+  @SerializedName(value = "data")
+  private List<DeclarationData> data;
+
+  /**
+   * 驳回原因详情
+   */
+  @Data
+  @Builder
+  @NoArgsConstructor
+  @AllArgsConstructor
+  @Accessors(chain = true)
+  public static class DeclarationData {
+    /**
+     * <pre>
+     * 字段名:商户子订单号
+     * 变量名:sub_order_no
+     * 是否必填:否
+     * 类型:string(32)
+     * 描述:
+     *  微信子订单号,如有拆单则返回
+     *  示例值:20150806125346
+     * </pre>
+     */
+    @SerializedName(value = "sub_order_no")
+    private String subOrderNo;
+
+    /**
+     * <pre>
+     * 字段名:微信子订单号
+     * 变量名:sub_order_id
+     * 是否必填:否
+     * 类型:string(32)
+     * 描述:
+     *  商户子订单号,如有拆单则必传
+     *  注意:仅适用于机构模式
+     *  示例值:20150806125346
+     * </pre>
+     */
+    @SerializedName(value = "sub_order_id")
+    private String subOrderId;
+
+    /**
+     * <pre>
+     * 字段名:商户海关备案号
+     * 变量名:merchant_customs_no
+     * 是否必填:是
+     * 类型:string(32)
+     * 描述:
+     *  商户在海关登记的备案号
+     *  示例值:123456
+     * </pre>
+     */
+    @SerializedName(value = "mch_customs_no")
+    private String merchantCustomsNo;
+
+    /**
+     * <pre>
+     * 字段名:海关
+     * 变量名:customs
+     * 是否必填:是
+     * 类型:string(32)
+     * 描述:
+     *  海关代码, 枚举值参见参数规定-海关列表(https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter2_3.shtml#menu11)
+     *  示例值:SHANGHAI_ZS
+     * </pre>
+     */
+    @SerializedName(value = "customs")
+    private String customs;
+
+    /**
+     * <pre>
+     * 字段名:关税
+     * 变量名:duty
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  关税,以分为单位,非必填项,不会提交给海关
+     *  示例值:888
+     * </pre>
+     */
+    @SerializedName(value = "duty")
+    private Integer duty;
+
+    /**
+     * <pre>
+     * 字段名:货币类型
+     * 变量名:fee_type
+     * 是否必填:否
+     * 类型:string(32)
+     * 描述:
+     *  微信支付订单支付时使用的币种,暂只支持人民币CNY,如有拆单则必传
+     *  示例值:CNY
+     * </pre>
+     */
+    @SerializedName(value = "fee_type")
+    private String feeType;
+
+    /**
+     * <pre>
+     * 字段名:子订单金额
+     * 变量名:order_fee
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  子订单金额,以分为单位,不能超过原订单金额,order_fee=transport_fee+product_fee(应付金额=物流费+商品价格),如有拆单则必传
+     *  示例值:888
+     * </pre>
+     */
+    @SerializedName(value = "order_fee")
+    private Integer orderFee;
+
+    /**
+     * <pre>
+     * 字段名:物流费用
+     * 变量名:transport_fee
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  物流费用,以分为单位,如有拆单则必传
+     *  示例值:888
+     * </pre>
+     */
+    @SerializedName(value = "transport_fee")
+    private Integer transportFee;
+
+    /**
+     * <pre>
+     * 字段名:商品费用
+     * 变量名:product_fee
+     * 是否必填:否
+     * 类型:int
+     * 描述:
+     *  商品费用,以分为单位,如有拆单则必传
+     *  示例值:888
+     * </pre>
+     */
+    @SerializedName(value = "product_fee")
+    private Integer productFee;
+
+    /**
+     * <pre>
+     * 字段名:报关状态
+     * 变量名:state
+     * 是否必填:是
+     * 类型:string(32)
+     * 描述:
+     *  申报结果状态码
+     *  PROCESSING:申报中
+     *  UNDECLARED:未申报
+     *  SUBMITTED:已修改未申报
+     *  SUCCESS:申报成功
+     *  FAIL:申报失败
+     *  EXCEPT:海关接口异常
+     *  示例值:PROCESSING
+     * </pre>
+     */
+    @SerializedName(value = "state")
+    private String state;
+
+    /**
+     * <pre>
+     * 字段名:报关结果说明
+     * 变量名:explanation
+     * 是否必填:是
+     * 类型:string(128)
+     * 描述:
+     *  申报结果说明,如果状态是失败或异常,显示失败原因
+     *  示例值:支付单已存在并且为非退单状态
+     * </pre>
+     */
+    @SerializedName(value = "explanation")
+    private String explanation;
+
+    /**
+     * <pre>
+     * 字段名:最后更新时间
+     * 变量名:modify_time
+     * 是否必填:是
+     * 类型:string(32)
+     * 描述:
+     *  最后更新时间,该时间取自微信服务器
+     *  示例值:2015-09-01T10:00:00+08:00
+     * </pre>
+     */
+    @SerializedName(value = "modify_time")
+    private String modifyTime;
+  }
+}

+ 191 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationRequest.java

@@ -0,0 +1,191 @@
+package com.github.binarywang.wxpay.bean.customs;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * @author xifenzhu
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class DeclarationRequest implements Serializable {
+
+  private static final long serialVersionUID = -170115210896346836L;
+  /**
+   * <pre>
+   * 字段名:机构APPID
+   * 变量名:appid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "appid")
+  private String appid;
+
+  /**
+   * <pre>
+   * 字段名:商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信支付分配的商户号
+   *  示例值:1230000109
+   * </pre>
+   */
+  @SerializedName(value = "mchid")
+  private String mchid;
+
+  /**
+   * <pre>
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-&#124;*@ ,且在同一个商户号下唯一
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "out_trade_no")
+  private String outTradeNo;
+
+  /**
+   * <pre>
+   * 字段名:微信支付返回的订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:1000320306201511078440737890
+   * </pre>
+   */
+  @SerializedName(value = "transaction_id")
+  private String transactionId;
+
+  /**
+   * <pre>
+   * 字段名:海关
+   * 变量名:customs
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  海关代码, 枚举值参见参数规定-海关列表(https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter2_3.shtml#menu11)
+   *  示例值:SHANGHAI_ZS
+   * </pre>
+   */
+  @SerializedName(value = "customs")
+  private String customs;
+
+  /**
+   * <pre>
+   * 字段名:商户海关备案号
+   * 变量名:merchant_customs_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户在海关登记的备案号
+   *  示例值:123456
+   * </pre>
+   */
+  @SerializedName(value = "merchant_customs_no")
+  private String merchantCustomsNo;
+
+  /**
+   * <pre>
+   * 字段名:关税
+   * 变量名:duty
+   * 是否必填:否
+   * 类型:int
+   * 描述:
+   *  关税,以分为单位,非必填项,不会提交给海关
+   *  示例值:888
+   * </pre>
+   */
+  @SerializedName(value = "duty")
+  private String duty;
+
+  /**
+   * <pre>
+   * 字段名:商户子订单号
+   * 变量名:sub_order_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户子订单号,如有拆单则必传
+   *  注意:仅适用于机构模式
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "sub_order_no")
+  private String subOrderNo;
+
+  /**
+   * <pre>
+   * 字段名:货币类型
+   * 变量名:fee_type
+   * 是否必填:否
+   * 类型:string(32)
+   * 描述:
+   *  微信支付订单支付时使用的币种,暂只支持人民币CNY,如有拆单则必传
+   *  示例值:CNY
+   * </pre>
+   */
+  @SerializedName(value = "fee_type")
+  private String feeType;
+
+  /**
+   * <pre>
+   * 字段名:子订单金额
+   * 变量名:order_fee
+   * 是否必填:否
+   * 类型:int
+   * 描述:
+   *  子订单金额,以分为单位,不能超过原订单金额,order_fee=transport_fee+product_fee(应付金额=物流费+商品价格),如有拆单则必传
+   *  示例值:888
+   * </pre>
+   */
+  @SerializedName(value = "order_fee")
+  private String orderFee;
+
+  /**
+   * <pre>
+   * 字段名:物流费用
+   * 变量名:transport_fee
+   * 是否必填:否
+   * 类型:int
+   * 描述:
+   *  物流费用,以分为单位,如有拆单则必传
+   *  示例值:888
+   * </pre>
+   */
+  @SerializedName(value = "transport_fee")
+  private String transportFee;
+
+  /**
+   * <pre>
+   * 字段名:商品费用
+   * 变量名:product_fee
+   * 是否必填:否
+   * 类型:int
+   * 描述:
+   *  商品费用,以分为单位,如有拆单则必传
+   *  示例值:888
+   * </pre>
+   */
+  @SerializedName(value = "product_fee")
+  private String productFee;
+}

+ 158 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationResult.java

@@ -0,0 +1,158 @@
+package com.github.binarywang.wxpay.bean.customs;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * @author xifengzhu
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class DeclarationResult implements Serializable {
+
+  private static final long serialVersionUID = -5895139329545995308L;
+  /**
+   * <pre>
+   * 字段名:机构APPID
+   * 变量名:appid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "appid")
+  private String appid;
+
+  /**
+   * <pre>
+   * 字段名:商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信支付分配的商户号
+   *  示例值:1230000109
+   * </pre>
+   */
+  @SerializedName(value = "mchid")
+  private String mchid;
+
+  /**
+   * <pre>
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-&#124;*@ ,且在同一个商户号下唯一
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "20150806125346")
+  private String outTradeNo;
+
+  /**
+   * <pre>
+   * 字段名:微信支付返回的订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:1000320306201511078440737890
+   * </pre>
+   */
+  @SerializedName(value = "transaction_id")
+  private String transactionId;
+
+  /**
+   * <pre>
+   * 字段名:报关状态
+   * 变量名:state
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  申报结果状态码
+   *  PROCESSING:申报中
+   *  UNDECLARED:未申报
+   *  SUBMITTED:已修改未申报
+   *  SUCCESS:申报成功
+   *  FAIL:申报失败
+   *  EXCEPT:海关接口异常
+   *  示例值:PROCESSING
+   * </pre>
+   */
+  @SerializedName(value = "state")
+  private String state;
+
+  /**
+   * <pre>
+   * 字段名:商户子订单号
+   * 变量名:sub_order_no
+   * 是否必填:否
+   * 类型:string(32)
+   * 描述:
+   *  微信子订单号,如有拆单则返回
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "sub_order_no")
+  private String subOrderNo;
+
+  /**
+   * <pre>
+   * 字段名:微信子订单号
+   * 变量名:sub_order_id
+   * 是否必填:否
+   * 类型:string(32)
+   * 描述:
+   *  商户子订单号,如有拆单则必传
+   *  注意:仅适用于机构模式
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "sub_order_id")
+  private String subOrderId;
+
+  /**
+   * <pre>
+   * 字段名:核验机构
+   * 变量名:verify_department
+   * 是否必填:是
+   * 类型:string(16)
+   * 描述:
+   *  核验机构代码
+   *  UNIONPAY:银联
+   *  NETSUNION:网联
+   *  OTHERS:其他
+   *  示例值:UNIONPAY
+   * </pre>
+   */
+  @SerializedName(value = "verify_department")
+  private String verifyDepartment;
+
+  /**
+   * <pre>
+   * 字段名:核验机构交易流水号
+   * 变量名:Verify_department_trade_id
+   * 是否必填:是
+   * 类型:string(64)
+   * 描述:
+   *  交易流水号,来自验核机构,如银联记录的交易流水号,供商户报备海关
+   *  示例值:2018112288340107038204310100000
+   * </pre>
+   */
+  @SerializedName(value = "verify_department_trade_id")
+  private String verifyDepartmentTradeId;
+}

+ 136 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/RedeclareRequest.java

@@ -0,0 +1,136 @@
+package com.github.binarywang.wxpay.bean.customs;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * @author xifengzhu
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class RedeclareRequest implements Serializable {
+  private static final long serialVersionUID = -5092107027805161479L;
+
+  /**
+   * <pre>
+   * 字段名:机构APPID
+   * 变量名:appid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "appid")
+  private String appid;
+
+  /**
+   * <pre>
+   * 字段名:商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信支付分配的商户号
+   *  示例值:1230000109
+   * </pre>
+   */
+  @SerializedName(value = "mchid")
+  private String mchid;
+
+  /**
+   * <pre>
+   * 字段名:微信订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  out_trade_no, transaction_id二选一传入
+   *  示例值:1000320306201511078440737890
+   * </pre>
+   */
+  @SerializedName(value = "transaction_id")
+  private String transactionId;
+
+  /**
+   * <pre>
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  out_trade_no, transaction_id二选一传入
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "out_trade_no")
+  private String outTradeNo;
+
+  /**
+   * <pre>
+   * 字段名:商户子订单号
+   * 变量名:sub_order_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户子订单号,如有拆单则必传
+   *  注意:仅适用于机构模式
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "sub_order_no")
+  private String subOrderNo;
+
+  /**
+   * <pre>
+   * 字段名:微信子订单号
+   * 变量名:sub_order_id
+   * 是否必填:否
+   * 类型:string(32)
+   * 描述:
+   *  商户子订单号,如有拆单则必传
+   *  注意:仅适用于机构模式
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "sub_order_id")
+  private String subOrderId;
+
+  /**
+   * <pre>
+   * 字段名:海关
+   * 变量名:customs
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  海关代码, 枚举值参见参数规定-海关列表(https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter2_3.shtml#menu11)
+   *  示例值:SHANGHAI_ZS
+   * </pre>
+   */
+  @SerializedName(value = "customs")
+  private String customs;
+
+  /**
+   * <pre>
+   * 字段名:商户海关备案号
+   * 变量名:merchant_customs_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户在海关登记的备案号
+   *  示例值:123456
+   * </pre>
+   */
+  @SerializedName(value = "merchant_customs_no")
+  private String merchantCustomsNo;
+}

+ 156 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/RedeclareResult.java

@@ -0,0 +1,156 @@
+package com.github.binarywang.wxpay.bean.customs;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * @author xifengzhu
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class RedeclareResult implements Serializable {
+
+  private static final long serialVersionUID = 8863516626598050095L;
+  /**
+   * <pre>
+   * 字段名:机构APPID
+   * 变量名:appid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "appid")
+  private String appid;
+
+  /**
+   * <pre>
+   * 字段名:商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信支付分配的商户号
+   *  示例值:1230000109
+   * </pre>
+   */
+  @SerializedName(value = "mchid")
+  private String mchid;
+
+  /**
+   * <pre>
+   * 字段名:微信订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信支付返回的订单号
+   *  示例值:1000320306201511078440737890
+   * </pre>
+   */
+  @SerializedName(value = "transaction_id")
+  private String transactionId;
+
+  /**
+   * <pre>
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "out_trade_no")
+  private String outTradeNo;
+
+  /**
+   * <pre>
+   * 字段名:商户子订单号
+   * 变量名:sub_order_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户子订单号,如有拆单则必传
+   *  注意:仅适用于机构模式
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "sub_order_no")
+  private String subOrderNo;
+
+  /**
+   * <pre>
+   * 字段名:微信子订单号
+   * 变量名:sub_order_id
+   * 是否必填:否
+   * 类型:string(32)
+   * 描述:
+   *  商户子订单号,如有拆单则必传
+   *  注意:仅适用于机构模式
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "sub_order_id")
+  private String subOrderId;
+
+  /**
+   * <pre>
+   * 字段名:报关状态
+   * 变量名:state
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  申报结果状态码
+   *  PROCESSING:申报中
+   *  UNDECLARED:未申报
+   *  SUBMITTED:已修改未申报
+   *  SUCCESS:申报成功
+   *  FAIL:申报失败
+   *  EXCEPT:海关接口异常
+   *  示例值:PROCESSING
+   * </pre>
+   */
+  @SerializedName(value = "state")
+  private String state;
+
+  /**
+   * <pre>
+   * 字段名:报关结果说明
+   * 变量名:explanation
+   * 是否必填:是
+   * 类型:string(128)
+   * 描述:
+   *  申报结果说明,如果状态是失败或异常,显示失败原因
+   *  示例值:支付单已存在并且为非退单状态
+   * </pre>
+   */
+  @SerializedName(value = "explanation")
+  private String explanation;
+
+  /**
+   * <pre>
+   * 字段名:最后更新时间
+   * 变量名:modify_time
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  最后更新时间,该时间取自微信服务器
+   *  示例值:2015-09-01T10:00:00+08:00
+   * </pre>
+   */
+  @SerializedName(value = "modify_time")
+  private String modifyTime;
+}

+ 156 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/VerifyCertificateRequest.java

@@ -0,0 +1,156 @@
+package com.github.binarywang.wxpay.bean.customs;
+
+import com.github.binarywang.wxpay.v3.SpecEncrypt;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author xifengzhu
+ */
+@Data
+public class VerifyCertificateRequest implements Serializable {
+  private static final long serialVersionUID = 721089103541592315L;
+  /**
+   * <pre>
+   * 字段名:机构APPID
+   * 变量名:appid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "appid")
+  private String appid;
+
+  /**
+   * <pre>
+   * 字段名:商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信支付分配的商户号
+   *  示例值:1230000109
+   * </pre>
+   */
+  @SerializedName(value = "mchid")
+  private String mchid;
+
+  /**
+   * <pre>
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-&#124;*@ ,且在同一个商户号下唯一
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "out_trade_no")
+  private String outTradeNo;
+
+  /**
+   * <pre>
+   * 字段名:微信支付返回的订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:1000320306201511078440737890
+   * </pre>
+   */
+  @SerializedName(value = "transaction_id")
+  private String transactionId;
+
+  /**
+   * <pre>
+   * 字段名:海关
+   * 变量名:customs
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  海关代码, 枚举值参见参数规定-海关列表(https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter2_3.shtml#menu11)
+   *  示例值:SHANGHAI_ZS
+   * </pre>
+   */
+  @SerializedName(value = "customs")
+  private String customs;
+
+  /**
+   * <pre>
+   * 字段名:商户海关备案号
+   * 变量名:merchant_customs_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户在海关登记的备案号
+   *  示例值:123456
+   * </pre>
+   */
+  @SerializedName(value = "merchant_customs_no")
+  private String merchantCustomsNo;
+
+  /**
+   * <pre>
+   * 字段名:商户子订单号
+   * 变量名:sub_order_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户子订单号,如有拆单则必传
+   *  注意:仅适用于机构模式
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "sub_order_no")
+  private String subOrderNo;
+
+  /**
+   * <pre>
+   * 字段名:证件类型
+   * 变量名:certificate_type
+   * 是否必填:是
+   * 类型:string(16)
+   * 描述:
+   *  请传固定值IDCARD,暂只支持大陆身份证
+   *  示例值:IDCARD
+   * </pre>
+   */
+  @SerializedName(value = "certificate_type")
+  private String certificateType;
+
+  /**
+   * <pre>
+   * 字段名:证件号
+   * 变量名:certificate_id
+   * 是否必填:是
+   * 类型:string
+   * 描述:
+   *  用户大陆身份证号,尾号为字母X的身份证号,请大写字母X。该字段需要进行加密
+   *  示例值:330821198809085211
+   * </pre>
+   */
+  @SerializedName(value = "certificate_id")
+  private String certificateId;
+
+  /**
+   * <pre>
+   * 字段名:证件姓名
+   * 变量名:certificate_name
+   * 是否必填:是
+   * 类型:string
+   * 描述:
+   *  证件姓名,字段值需要进行加密
+   *  示例值:330821198809085211
+   * </pre>
+   */
+  @SerializedName(value = "certificate_name")
+  private String certificateName;
+
+}

+ 93 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/VerifyCertificateResult.java

@@ -0,0 +1,93 @@
+package com.github.binarywang.wxpay.bean.customs;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * @author xifengzhu
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+public class VerifyCertificateResult implements Serializable {
+  private static final long serialVersionUID = -8578640869555299753L;
+  /**
+   * <pre>
+   * 字段名:机构APPID
+   * 变量名:appid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:wxd678efh567hg6787
+   * </pre>
+   */
+  @SerializedName(value = "appid")
+  private String appid;
+
+  /**
+   * <pre>
+   * 字段名:商户号
+   * 变量名:mchid
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信支付分配的商户号
+   *  示例值:1230000109
+   * </pre>
+   */
+  @SerializedName(value = "mchid")
+  private String mchid;
+
+  /**
+   * <pre>
+   * 字段名:商户订单号
+   * 变量名:out_trade_no
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-&#124;*@ ,且在同一个商户号下唯一
+   *  示例值:20150806125346
+   * </pre>
+   */
+  @SerializedName(value = "out_trade_no")
+  private String outTradeNo;
+
+  /**
+   * <pre>
+   * 字段名:微信支付返回的订单号
+   * 变量名:transaction_id
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  微信分配的公众账号ID
+   *  示例值:1000320306201511078440737890
+   * </pre>
+   */
+  @SerializedName(value = "transaction_id")
+  private String transactionId;
+
+  /**
+   * <pre>
+   * 字段名:身份核验结果
+   * 变量名:certificate_check_result
+   * 是否必填:是
+   * 类型:string(32)
+   * 描述:
+   *  订购人和支付人身份信息校验结果
+   *  SAME:身份信息校验匹配
+   *  DIFFERENT:身份信息校验不匹配
+   *  示例值:SAME
+   * </pre>
+   */
+  @SerializedName(value = "certificate_check_result")
+  private String certificateCheckResult;
+}

+ 77 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/CustomDeclarationService.java

@@ -0,0 +1,77 @@
+package com.github.binarywang.wxpay.service;
+
+import com.github.binarywang.wxpay.bean.customs.*;
+import com.github.binarywang.wxpay.exception.WxPayException;
+
+/**
+ * <pre>
+ * 微信支付 支付报关 API.
+ * Created by xifengzhu on 2022/05/05.
+ * </pre>
+ *
+ * @author <a href="https://github.com/xifengzhu">xifengzhu</a>
+ */
+public interface CustomDeclarationService {
+
+  static  String DECLARATION_BASE_URL = "https://apihk.mch.weixin.qq.com/global/v3/customs";
+
+  /**
+   * <pre>
+   * 报关API
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_1.shtml
+   * </pre>
+   *
+   * @param request
+   * @return 返回数据 declaration result
+   * @throws WxPayException the wx pay exception
+   */
+  DeclarationResult declare(DeclarationRequest request) throws WxPayException;
+
+  /**
+   * <pre>
+   * 报关查询API
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_3.shtml
+   * </pre>
+   *
+   * @param request
+   * @return 返回数据 declaration query result
+   * @throws WxPayException the wx pay exception
+   */
+  DeclarationQueryResult query(DeclarationQueryRequest request) throws WxPayException;
+
+  /**
+   * <pre>
+   * 身份信息校验API
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_2.shtml
+   * </pre>
+   *
+   * @param request
+   * @return 返回数据 verify certification result
+   * @throws WxPayException the wx pay exception
+   */
+  VerifyCertificateResult verifyCertificate(VerifyCertificateRequest request) throws WxPayException;
+
+  /**
+   * <pre>
+   * 报关信息修改API
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_5.shtml
+   * </pre>
+   *
+   * @param request
+   * @return 返回数据 declaration result
+   * @throws WxPayException the wx pay exception
+   */
+  DeclarationResult modify(DeclarationRequest request) throws WxPayException;
+
+  /**
+   * <pre>
+   * 报关重推API
+   * 文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_4.shtml
+   * </pre>
+   *
+   * @param request
+   * @return 返回数据 redeclaration result
+   * @throws WxPayException the wx pay exception
+   */
+  RedeclareResult redeclare(RedeclareRequest request) throws WxPayException;
+}

+ 110 - 0
weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java

@@ -0,0 +1,110 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.customs.*;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.CustomDeclarationService;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.error.WxRuntimeException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+
+/**
+ * <pre>
+ * 支付报关 实现.
+ * Created by xifengzhu on 2022/05/05.
+ * </pre>
+ *
+ * @author <a href="https://github.com/xifengzhu">xifengzhu</a>
+ */
+@RequiredArgsConstructor
+public class CustomDeclarationServiceImpl implements CustomDeclarationService {
+  private static final Gson GSON = new GsonBuilder().create();
+  private final WxPayService payService;
+
+  @Override
+  public DeclarationResult declare(DeclarationRequest request) throws WxPayException {
+    String response = this.payService.postV3(DECLARATION_BASE_URL.concat("/orders"), GSON.toJson(request));
+    return GSON.fromJson(response, DeclarationResult.class);
+  }
+
+  @Override
+  public DeclarationQueryResult query(DeclarationQueryRequest request) throws WxPayException {
+    String url = String.format("%s/orders?appid=%s&mchid=%s&order_type=%s&order_no=%s&customs=%s&offset=%s&limit=%s",
+      DECLARATION_BASE_URL,
+      request.getAppid(),
+      request.getMchid(),
+      request.getOrderType(),
+      request.getOrderNo(),
+      request.getCustoms(),
+      request.getOffset(),
+      request.getLimit()
+    );
+    String result = this.payService.getV3(url);
+    return GSON.fromJson(result, DeclarationQueryResult.class);
+  }
+
+  @Override
+  public VerifyCertificateResult verifyCertificate(VerifyCertificateRequest request) throws WxPayException {
+    this.encryptFields(request);
+    String response = this.payService.postV3WithWechatpaySerial(DECLARATION_BASE_URL.concat("/verify-certificate"), GSON.toJson(request));
+    return GSON.fromJson(response, VerifyCertificateResult.class);
+  }
+
+  @Override
+  public DeclarationResult modify(DeclarationRequest request) throws WxPayException {
+    String response = this.payService.patchV3(DECLARATION_BASE_URL.concat("/orders"), GSON.toJson(request));
+    return GSON.fromJson(response, DeclarationResult.class);
+  }
+
+  @Override
+  public RedeclareResult redeclare(RedeclareRequest request) throws WxPayException {
+    String response = this.payService.postV3(DECLARATION_BASE_URL.concat("/redeclare"), GSON.toJson(request));
+    return GSON.fromJson(response, RedeclareResult.class);
+  }
+
+  private void encryptFields(VerifyCertificateRequest request) throws WxPayException {
+    try {
+      request.setCertificateId(encryptOAEP(request.getCertificateId()));
+      request.setCertificateName(encryptOAEP(request.getCertificateName()));
+    } catch (Exception e) {
+      throw new WxPayException("敏感信息加密失败", e);
+    }
+  }
+
+  private X509Certificate getValidCertificate() {
+    return this.payService.getConfig().getVerifier().getValidCertificate();
+  }
+
+  private String encryptOAEP(String message)
+    throws IllegalBlockSizeException {
+    X509Certificate certificate = getValidCertificate();
+    try {
+      // 身份信息校验 RSA 加密,填充方案使用 `RSAES-PKCS1-v1_5`
+      // https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_2.shtml
+      Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+      cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
+
+      byte[] data = message.getBytes(StandardCharsets.UTF_8);
+      byte[] ciphertext = cipher.doFinal(data);
+      return Base64.getEncoder().encodeToString(ciphertext);
+    } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
+      throw new WxRuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
+    } catch (InvalidKeyException e) {
+      throw new IllegalArgumentException("无效的证书", e);
+    } catch (IllegalBlockSizeException | BadPaddingException e) {
+      throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
+    }
+  }
+}

+ 74 - 0
weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImplTest.java

@@ -0,0 +1,74 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.customs.*;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.CustomDeclarationService;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.testbase.ApiTestModule;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+@Slf4j
+@Test
+@Guice(modules = ApiTestModule.class)
+public class CustomDeclarationServiceImplTest {
+  private static final Gson GSON = new GsonBuilder().create();
+  @Inject
+  private WxPayService wxPayService;
+
+  @Test
+  public void testDeclare() throws WxPayException {
+    CustomDeclarationService customDeclarationService = new CustomDeclarationServiceImpl(wxPayService);
+    String requestParamStr = "{\"appid\":\"wx4275b35dac8f1bde\",\"mchid\":\"1623887211\",\"out_trade_no\":\"schiff32205031811186126779176\",\"transaction_id\":\"4200001480202205035540107159\",\"customs\":\"NINGBO\",\"merchant_customs_no\":\"4401230148\"}";
+    DeclarationRequest request = GSON.fromJson(requestParamStr, DeclarationRequest.class);
+
+    DeclarationResult result = customDeclarationService.declare(request);
+    System.out.println("result = " + result);
+  }
+
+  @Test
+  public void testQuery() throws WxPayException {
+    CustomDeclarationService customDeclarationService = new CustomDeclarationServiceImpl(wxPayService);
+    String requestParamStr = "{\"appid\":\"wx4275b35dac8f1bde\",\"mchid\":\"1623887211\",\"order_type\":\"transaction_id\",\"order_no\":\"4200001480202205035540107159\",\"customs\":\"NINGBO\",\"offset\":\"0\",\"limit\":\"20\"}";
+    DeclarationQueryRequest request = GSON.fromJson(requestParamStr, DeclarationQueryRequest.class);
+
+    DeclarationQueryResult result = customDeclarationService.query(request);
+    System.out.println("result = " + result);
+  }
+
+  @Test
+  public void testVerifyCertificate() throws WxPayException {
+    CustomDeclarationService customDeclarationService = new CustomDeclarationServiceImpl(wxPayService);
+    String requestParamStr = "{\"appid\":\"wx4275b35dac8f1bde\",\"mchid\":\"1623887211\",\"out_trade_no\":\"schiff32205031811186126779176\",\"transaction_id\":\"4200001480202205035540107159\",\"customs\":\"NINGBO\",\"merchant_customs_no\":\"4401230148\",\"certificate_type\":\"IDCARD\",\"certificate_id\":\"430223199101264838\",\"certificate_name\":\"易株强\"}";
+    VerifyCertificateRequest request = GSON.fromJson(requestParamStr, VerifyCertificateRequest.class);
+
+    VerifyCertificateResult result = customDeclarationService.verifyCertificate(request);
+    System.out.println("result = " + result);
+  }
+
+  @Test
+  public void testModify() throws WxPayException {
+    CustomDeclarationService customDeclarationService = new CustomDeclarationServiceImpl(wxPayService);
+
+    String requestParamStr = "{\"appid\":\"wx4275b35dac8f1bde\",\"mchid\":\"1623887211\",\"out_trade_no\":\"schiff32205031811186126779176\",\"transaction_id\":\"4200001480202205035540107159\",\"customs\":\"NINGBO\",\"merchant_customs_no\":\"4401230148\"}";
+
+    DeclarationRequest request = GSON.fromJson(requestParamStr, DeclarationRequest.class);
+
+    DeclarationResult result = customDeclarationService.modify(request);
+    System.out.println("result = " + result);
+  }
+
+  @Test
+  public void testRedeclare() throws WxPayException {
+    CustomDeclarationService customDeclarationService = new CustomDeclarationServiceImpl(wxPayService);
+    String requestParamStr = "{\"appid\":\"wx4275b35dac8f1bde\",\"mchid\":\"1623887211\",\"out_trade_no\":\"schiff32205031811186126779176\",\"transaction_id\":\"4200001480202205035540107159\",\"customs\":\"NINGBO\",\"merchant_customs_no\":\"4401230148\"}";
+    RedeclareRequest request = GSON.fromJson(requestParamStr, RedeclareRequest.class);
+
+    RedeclareResult result = customDeclarationService.redeclare(request);
+    System.out.println("result = " + result);
+  }
+}