diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationQueryRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationQueryRequest.java new file mode 100644 index 0000000000..beaa3f2604 --- /dev/null +++ b/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; + /** + *
+ * 字段名:机构APPID + * 变量名:appid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:wxd678efh567hg6787 + *+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+ * 字段名:商户号 + * 变量名:mchid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信支付分配的商户号 + * 示例值:1230000109 + *+ */ + @SerializedName(value = "mchid") + private String mchid; + + /** + *
+ * 字段名:订单类型 + * 变量名:order_type + * 是否必填:是 + * 类型:string(16) + * 描述: + * 4种订单号类型,选择一种 + * out_trade_no 商户订单号 + * transaction_id 微信支付订单号 + * sub_order_no 商户子订单号 + * sub_order_id 微信子订单号 + * 示例值:out_trade_no + *+ */ + @SerializedName(value = "order_type") + private String orderType; + + /** + *
+ * 字段名:订单号 + * 变量名:order_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 根据订单号类型,传入不同的订单号码 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "order_no") + private String orderNo; + + /** + *
+ * 字段名:海关 + * 变量名:customs + * 是否必填:是 + * 类型:string(32) + * 描述: + * 海关代码, 枚举值参见参数规定-海关列表(https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter2_3.shtml#menu11) + * 示例值:SHANGHAI_ZS + *+ */ + @SerializedName(value = "customs") + private String customs; + + /** + *
+ * 字段名:偏移量 + * 变量名:offset + * 是否必填:是 + * 类型:int + * 描述: + * 非0整数,该次请求资源的起始位置,从0开始计数。调用方选填,默认为0 + * 示例值:0 + *+ */ + @SerializedName(value = "offset") + private String offset; + + /** + *
+ * 字段名:请求最大记录条数 + * 变量名:limit + * 是否必填:是 + * 类型:int + * 描述: + * 非0非负的整数,该次请求可返回的最大资源条数。调用方选填,默认值建议为20 + * 示例值:20 + *+ */ + @SerializedName(value = "limit") + private String limit; + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationQueryResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationQueryResult.java new file mode 100644 index 0000000000..e84370ca11 --- /dev/null +++ b/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; + /** + *
+ * 字段名:机构APPID + * 变量名:appid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:wxd678efh567hg6787 + *+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+ * 字段名:商户号 + * 变量名:mchid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信支付分配的商户号 + * 示例值:1230000109 + *+ */ + @SerializedName(value = "mchid") + private String mchid; + + /** + *
+ * 字段名:微信支付返回的订单号 + * 变量名:transaction_id + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:1000320306201511078440737890 + *+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + + /** + *
+ * 字段名:核验机构 + * 变量名:verify_department + * 是否必填:是 + * 类型:string(16) + * 描述: + * 核验机构代码 + * UNIONPAY:银联 + * NETSUNION:网联 + * OTHERS:其他 + * 示例值:UNIONPAY + *+ */ + @SerializedName(value = "verify_department") + private String verifyDepartment; + + /** + *
+ * 字段名:核验机构交易流水号 + * 变量名:Verify_department_trade_id + * 是否必填:是 + * 类型:string(64) + * 描述: + * 交易流水号,来自验核机构,如银联记录的交易流水号,供商户报备海关 + * 示例值:2018112288340107038204310100000 + *+ */ + @SerializedName(value = "verify_department_trade_id") + private String verifyDepartmentTradeId; + + /** + *
+ * 字段名:偏移量 + * 变量名:offset + * 是否必填:是 + * 类型:int + * 描述: + * 非0整数,该次请求资源的起始位置,从0开始计数。调用方选填,默认为0 + * 示例值:0 + *+ */ + @SerializedName(value = "offset") + private Integer offset; + + /** + *
+ * 字段名:请求最大记录条数 + * 变量名:limit + * 是否必填:是 + * 类型:int + * 描述: + * 非0非负的整数,该次请求可返回的最大资源条数。调用方选填,默认值建议为20 + * 示例值:20 + *+ */ + @SerializedName(value = "limit") + private Integer limit; + + /** + *
+ * 字段名:查询结果总条数 + * 变量名:total_count + * 是否必填:是 + * 类型:int + * 描述: + * 查询结果总条数 + * 示例值:1 + *+ */ + @SerializedName(value = "total_count") + private Integer totalCount; + + /** + *
+ * 字段名:报关数据包 + * 变量名:data + * 是否必填:是 + * 类型:array + * 描述: + * 报关单结果数组,具体内容参见下方描述 + * 示例值: + *+ */ + @SerializedName(value = "data") + private List
+ * 字段名:商户子订单号 + * 变量名:sub_order_no + * 是否必填:否 + * 类型:string(32) + * 描述: + * 微信子订单号,如有拆单则返回 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "sub_order_no") + private String subOrderNo; + + /** + *
+ * 字段名:微信子订单号 + * 变量名:sub_order_id + * 是否必填:否 + * 类型:string(32) + * 描述: + * 商户子订单号,如有拆单则必传 + * 注意:仅适用于机构模式 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "sub_order_id") + private String subOrderId; + + /** + *
+ * 字段名:商户海关备案号 + * 变量名:merchant_customs_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户在海关登记的备案号 + * 示例值:123456 + *+ */ + @SerializedName(value = "mch_customs_no") + private String merchantCustomsNo; + + /** + *
+ * 字段名:海关 + * 变量名:customs + * 是否必填:是 + * 类型:string(32) + * 描述: + * 海关代码, 枚举值参见参数规定-海关列表(https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter2_3.shtml#menu11) + * 示例值:SHANGHAI_ZS + *+ */ + @SerializedName(value = "customs") + private String customs; + + /** + *
+ * 字段名:关税 + * 变量名:duty + * 是否必填:否 + * 类型:int + * 描述: + * 关税,以分为单位,非必填项,不会提交给海关 + * 示例值:888 + *+ */ + @SerializedName(value = "duty") + private Integer duty; + + /** + *
+ * 字段名:货币类型 + * 变量名:fee_type + * 是否必填:否 + * 类型:string(32) + * 描述: + * 微信支付订单支付时使用的币种,暂只支持人民币CNY,如有拆单则必传 + * 示例值:CNY + *+ */ + @SerializedName(value = "fee_type") + private String feeType; + + /** + *
+ * 字段名:子订单金额 + * 变量名:order_fee + * 是否必填:否 + * 类型:int + * 描述: + * 子订单金额,以分为单位,不能超过原订单金额,order_fee=transport_fee+product_fee(应付金额=物流费+商品价格),如有拆单则必传 + * 示例值:888 + *+ */ + @SerializedName(value = "order_fee") + private Integer orderFee; + + /** + *
+ * 字段名:物流费用 + * 变量名:transport_fee + * 是否必填:否 + * 类型:int + * 描述: + * 物流费用,以分为单位,如有拆单则必传 + * 示例值:888 + *+ */ + @SerializedName(value = "transport_fee") + private Integer transportFee; + + /** + *
+ * 字段名:商品费用 + * 变量名:product_fee + * 是否必填:否 + * 类型:int + * 描述: + * 商品费用,以分为单位,如有拆单则必传 + * 示例值:888 + *+ */ + @SerializedName(value = "product_fee") + private Integer productFee; + + /** + *
+ * 字段名:报关状态 + * 变量名:state + * 是否必填:是 + * 类型:string(32) + * 描述: + * 申报结果状态码 + * PROCESSING:申报中 + * UNDECLARED:未申报 + * SUBMITTED:已修改未申报 + * SUCCESS:申报成功 + * FAIL:申报失败 + * EXCEPT:海关接口异常 + * 示例值:PROCESSING + *+ */ + @SerializedName(value = "state") + private String state; + + /** + *
+ * 字段名:报关结果说明 + * 变量名:explanation + * 是否必填:是 + * 类型:string(128) + * 描述: + * 申报结果说明,如果状态是失败或异常,显示失败原因 + * 示例值:支付单已存在并且为非退单状态 + *+ */ + @SerializedName(value = "explanation") + private String explanation; + + /** + *
+ * 字段名:最后更新时间 + * 变量名:modify_time + * 是否必填:是 + * 类型:string(32) + * 描述: + * 最后更新时间,该时间取自微信服务器 + * 示例值:2015-09-01T10:00:00+08:00 + *+ */ + @SerializedName(value = "modify_time") + private String modifyTime; + } +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationRequest.java new file mode 100644 index 0000000000..89b1b79654 --- /dev/null +++ b/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; + /** + *
+ * 字段名:机构APPID + * 变量名:appid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:wxd678efh567hg6787 + *+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+ * 字段名:商户号 + * 变量名:mchid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信支付分配的商户号 + * 示例值:1230000109 + *+ */ + @SerializedName(value = "mchid") + private String mchid; + + /** + *
+ * 字段名:商户订单号 + * 变量名:out_trade_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + + /** + *
+ * 字段名:微信支付返回的订单号 + * 变量名:transaction_id + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:1000320306201511078440737890 + *+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + + /** + *
+ * 字段名:海关 + * 变量名:customs + * 是否必填:是 + * 类型:string(32) + * 描述: + * 海关代码, 枚举值参见参数规定-海关列表(https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter2_3.shtml#menu11) + * 示例值:SHANGHAI_ZS + *+ */ + @SerializedName(value = "customs") + private String customs; + + /** + *
+ * 字段名:商户海关备案号 + * 变量名:merchant_customs_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户在海关登记的备案号 + * 示例值:123456 + *+ */ + @SerializedName(value = "merchant_customs_no") + private String merchantCustomsNo; + + /** + *
+ * 字段名:关税 + * 变量名:duty + * 是否必填:否 + * 类型:int + * 描述: + * 关税,以分为单位,非必填项,不会提交给海关 + * 示例值:888 + *+ */ + @SerializedName(value = "duty") + private String duty; + + /** + *
+ * 字段名:商户子订单号 + * 变量名:sub_order_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户子订单号,如有拆单则必传 + * 注意:仅适用于机构模式 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "sub_order_no") + private String subOrderNo; + + /** + *
+ * 字段名:货币类型 + * 变量名:fee_type + * 是否必填:否 + * 类型:string(32) + * 描述: + * 微信支付订单支付时使用的币种,暂只支持人民币CNY,如有拆单则必传 + * 示例值:CNY + *+ */ + @SerializedName(value = "fee_type") + private String feeType; + + /** + *
+ * 字段名:子订单金额 + * 变量名:order_fee + * 是否必填:否 + * 类型:int + * 描述: + * 子订单金额,以分为单位,不能超过原订单金额,order_fee=transport_fee+product_fee(应付金额=物流费+商品价格),如有拆单则必传 + * 示例值:888 + *+ */ + @SerializedName(value = "order_fee") + private String orderFee; + + /** + *
+ * 字段名:物流费用 + * 变量名:transport_fee + * 是否必填:否 + * 类型:int + * 描述: + * 物流费用,以分为单位,如有拆单则必传 + * 示例值:888 + *+ */ + @SerializedName(value = "transport_fee") + private String transportFee; + + /** + *
+ * 字段名:商品费用 + * 变量名:product_fee + * 是否必填:否 + * 类型:int + * 描述: + * 商品费用,以分为单位,如有拆单则必传 + * 示例值:888 + *+ */ + @SerializedName(value = "product_fee") + private String productFee; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/DeclarationResult.java new file mode 100644 index 0000000000..06f604f742 --- /dev/null +++ b/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; + /** + *
+ * 字段名:机构APPID + * 变量名:appid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:wxd678efh567hg6787 + *+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+ * 字段名:商户号 + * 变量名:mchid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信支付分配的商户号 + * 示例值:1230000109 + *+ */ + @SerializedName(value = "mchid") + private String mchid; + + /** + *
+ * 字段名:商户订单号 + * 变量名:out_trade_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一 + * 示例值:wxd678efh567hg6787 + *+ */ + @SerializedName(value = "20150806125346") + private String outTradeNo; + + /** + *
+ * 字段名:微信支付返回的订单号 + * 变量名:transaction_id + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:1000320306201511078440737890 + *+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + + /** + *
+ * 字段名:报关状态 + * 变量名:state + * 是否必填:是 + * 类型:string(32) + * 描述: + * 申报结果状态码 + * PROCESSING:申报中 + * UNDECLARED:未申报 + * SUBMITTED:已修改未申报 + * SUCCESS:申报成功 + * FAIL:申报失败 + * EXCEPT:海关接口异常 + * 示例值:PROCESSING + *+ */ + @SerializedName(value = "state") + private String state; + + /** + *
+ * 字段名:商户子订单号 + * 变量名:sub_order_no + * 是否必填:否 + * 类型:string(32) + * 描述: + * 微信子订单号,如有拆单则返回 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "sub_order_no") + private String subOrderNo; + + /** + *
+ * 字段名:微信子订单号 + * 变量名:sub_order_id + * 是否必填:否 + * 类型:string(32) + * 描述: + * 商户子订单号,如有拆单则必传 + * 注意:仅适用于机构模式 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "sub_order_id") + private String subOrderId; + + /** + *
+ * 字段名:核验机构 + * 变量名:verify_department + * 是否必填:是 + * 类型:string(16) + * 描述: + * 核验机构代码 + * UNIONPAY:银联 + * NETSUNION:网联 + * OTHERS:其他 + * 示例值:UNIONPAY + *+ */ + @SerializedName(value = "verify_department") + private String verifyDepartment; + + /** + *
+ * 字段名:核验机构交易流水号 + * 变量名:Verify_department_trade_id + * 是否必填:是 + * 类型:string(64) + * 描述: + * 交易流水号,来自验核机构,如银联记录的交易流水号,供商户报备海关 + * 示例值:2018112288340107038204310100000 + *+ */ + @SerializedName(value = "verify_department_trade_id") + private String verifyDepartmentTradeId; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/RedeclareRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/RedeclareRequest.java new file mode 100644 index 0000000000..d3645d13da --- /dev/null +++ b/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; + + /** + *
+ * 字段名:机构APPID + * 变量名:appid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:wxd678efh567hg6787 + *+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+ * 字段名:商户号 + * 变量名:mchid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信支付分配的商户号 + * 示例值:1230000109 + *+ */ + @SerializedName(value = "mchid") + private String mchid; + + /** + *
+ * 字段名:微信订单号 + * 变量名:transaction_id + * 是否必填:是 + * 类型:string(32) + * 描述: + * out_trade_no, transaction_id二选一传入 + * 示例值:1000320306201511078440737890 + *+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + + /** + *
+ * 字段名:商户订单号 + * 变量名:out_trade_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * out_trade_no, transaction_id二选一传入 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + + /** + *
+ * 字段名:商户子订单号 + * 变量名:sub_order_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户子订单号,如有拆单则必传 + * 注意:仅适用于机构模式 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "sub_order_no") + private String subOrderNo; + + /** + *
+ * 字段名:微信子订单号 + * 变量名:sub_order_id + * 是否必填:否 + * 类型:string(32) + * 描述: + * 商户子订单号,如有拆单则必传 + * 注意:仅适用于机构模式 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "sub_order_id") + private String subOrderId; + + /** + *
+ * 字段名:海关 + * 变量名:customs + * 是否必填:是 + * 类型:string(32) + * 描述: + * 海关代码, 枚举值参见参数规定-海关列表(https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter2_3.shtml#menu11) + * 示例值:SHANGHAI_ZS + *+ */ + @SerializedName(value = "customs") + private String customs; + + /** + *
+ * 字段名:商户海关备案号 + * 变量名:merchant_customs_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户在海关登记的备案号 + * 示例值:123456 + *+ */ + @SerializedName(value = "merchant_customs_no") + private String merchantCustomsNo; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/RedeclareResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/RedeclareResult.java new file mode 100644 index 0000000000..25e09d7c07 --- /dev/null +++ b/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; + /** + *
+ * 字段名:机构APPID + * 变量名:appid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:wxd678efh567hg6787 + *+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+ * 字段名:商户号 + * 变量名:mchid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信支付分配的商户号 + * 示例值:1230000109 + *+ */ + @SerializedName(value = "mchid") + private String mchid; + + /** + *
+ * 字段名:微信订单号 + * 变量名:transaction_id + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信支付返回的订单号 + * 示例值:1000320306201511078440737890 + *+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + + /** + *
+ * 字段名:商户订单号 + * 变量名:out_trade_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + + /** + *
+ * 字段名:商户子订单号 + * 变量名:sub_order_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户子订单号,如有拆单则必传 + * 注意:仅适用于机构模式 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "sub_order_no") + private String subOrderNo; + + /** + *
+ * 字段名:微信子订单号 + * 变量名:sub_order_id + * 是否必填:否 + * 类型:string(32) + * 描述: + * 商户子订单号,如有拆单则必传 + * 注意:仅适用于机构模式 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "sub_order_id") + private String subOrderId; + + /** + *
+ * 字段名:报关状态 + * 变量名:state + * 是否必填:是 + * 类型:string(32) + * 描述: + * 申报结果状态码 + * PROCESSING:申报中 + * UNDECLARED:未申报 + * SUBMITTED:已修改未申报 + * SUCCESS:申报成功 + * FAIL:申报失败 + * EXCEPT:海关接口异常 + * 示例值:PROCESSING + *+ */ + @SerializedName(value = "state") + private String state; + + /** + *
+ * 字段名:报关结果说明 + * 变量名:explanation + * 是否必填:是 + * 类型:string(128) + * 描述: + * 申报结果说明,如果状态是失败或异常,显示失败原因 + * 示例值:支付单已存在并且为非退单状态 + *+ */ + @SerializedName(value = "explanation") + private String explanation; + + /** + *
+ * 字段名:最后更新时间 + * 变量名:modify_time + * 是否必填:是 + * 类型:string(32) + * 描述: + * 最后更新时间,该时间取自微信服务器 + * 示例值:2015-09-01T10:00:00+08:00 + *+ */ + @SerializedName(value = "modify_time") + private String modifyTime; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/VerifyCertificateRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/VerifyCertificateRequest.java new file mode 100644 index 0000000000..767a4ce8d8 --- /dev/null +++ b/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; + /** + *
+ * 字段名:机构APPID + * 变量名:appid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:wxd678efh567hg6787 + *+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+ * 字段名:商户号 + * 变量名:mchid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信支付分配的商户号 + * 示例值:1230000109 + *+ */ + @SerializedName(value = "mchid") + private String mchid; + + /** + *
+ * 字段名:商户订单号 + * 变量名:out_trade_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + + /** + *
+ * 字段名:微信支付返回的订单号 + * 变量名:transaction_id + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:1000320306201511078440737890 + *+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + + /** + *
+ * 字段名:海关 + * 变量名:customs + * 是否必填:是 + * 类型:string(32) + * 描述: + * 海关代码, 枚举值参见参数规定-海关列表(https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter2_3.shtml#menu11) + * 示例值:SHANGHAI_ZS + *+ */ + @SerializedName(value = "customs") + private String customs; + + /** + *
+ * 字段名:商户海关备案号 + * 变量名:merchant_customs_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户在海关登记的备案号 + * 示例值:123456 + *+ */ + @SerializedName(value = "merchant_customs_no") + private String merchantCustomsNo; + + /** + *
+ * 字段名:商户子订单号 + * 变量名:sub_order_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户子订单号,如有拆单则必传 + * 注意:仅适用于机构模式 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "sub_order_no") + private String subOrderNo; + + /** + *
+ * 字段名:证件类型 + * 变量名:certificate_type + * 是否必填:是 + * 类型:string(16) + * 描述: + * 请传固定值IDCARD,暂只支持大陆身份证 + * 示例值:IDCARD + *+ */ + @SerializedName(value = "certificate_type") + private String certificateType; + + /** + *
+ * 字段名:证件号 + * 变量名:certificate_id + * 是否必填:是 + * 类型:string + * 描述: + * 用户大陆身份证号,尾号为字母X的身份证号,请大写字母X。该字段需要进行加密 + * 示例值:330821198809085211 + *+ */ + @SerializedName(value = "certificate_id") + private String certificateId; + + /** + *
+ * 字段名:证件姓名 + * 变量名:certificate_name + * 是否必填:是 + * 类型:string + * 描述: + * 证件姓名,字段值需要进行加密 + * 示例值:330821198809085211 + *+ */ + @SerializedName(value = "certificate_name") + private String certificateName; + +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/VerifyCertificateResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/customs/VerifyCertificateResult.java new file mode 100644 index 0000000000..d97049cb46 --- /dev/null +++ b/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; + /** + *
+ * 字段名:机构APPID + * 变量名:appid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:wxd678efh567hg6787 + *+ */ + @SerializedName(value = "appid") + private String appid; + + /** + *
+ * 字段名:商户号 + * 变量名:mchid + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信支付分配的商户号 + * 示例值:1230000109 + *+ */ + @SerializedName(value = "mchid") + private String mchid; + + /** + *
+ * 字段名:商户订单号 + * 变量名:out_trade_no + * 是否必填:是 + * 类型:string(32) + * 描述: + * 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*@ ,且在同一个商户号下唯一 + * 示例值:20150806125346 + *+ */ + @SerializedName(value = "out_trade_no") + private String outTradeNo; + + /** + *
+ * 字段名:微信支付返回的订单号 + * 变量名:transaction_id + * 是否必填:是 + * 类型:string(32) + * 描述: + * 微信分配的公众账号ID + * 示例值:1000320306201511078440737890 + *+ */ + @SerializedName(value = "transaction_id") + private String transactionId; + + /** + *
+ * 字段名:身份核验结果 + * 变量名:certificate_check_result + * 是否必填:是 + * 类型:string(32) + * 描述: + * 订购人和支付人身份信息校验结果 + * SAME:身份信息校验匹配 + * DIFFERENT:身份信息校验不匹配 + * 示例值:SAME + *+ */ + @SerializedName(value = "certificate_check_result") + private String certificateCheckResult; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/CustomDeclarationService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/CustomDeclarationService.java new file mode 100644 index 0000000000..f2980fed43 --- /dev/null +++ b/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; + +/** + *
+ * 微信支付 支付报关 API. + * Created by xifengzhu on 2022/05/05. + *+ * + * @author xifengzhu + */ +public interface CustomDeclarationService { + + static String DECLARATION_BASE_URL = "https://apihk.mch.weixin.qq.com/global/v3/customs"; + + /** + *
+ * 报关API + * 文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_1.shtml + *+ * + * @param request + * @return 返回数据 declaration result + * @throws WxPayException the wx pay exception + */ + DeclarationResult declare(DeclarationRequest request) throws WxPayException; + + /** + *
+ * 报关查询API + * 文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_3.shtml + *+ * + * @param request + * @return 返回数据 declaration query result + * @throws WxPayException the wx pay exception + */ + DeclarationQueryResult query(DeclarationQueryRequest request) throws WxPayException; + + /** + *
+ * 身份信息校验API + * 文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_2.shtml + *+ * + * @param request + * @return 返回数据 verify certification result + * @throws WxPayException the wx pay exception + */ + VerifyCertificateResult verifyCertificate(VerifyCertificateRequest request) throws WxPayException; + + /** + *
+ * 报关信息修改API + * 文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_5.shtml + *+ * + * @param request + * @return 返回数据 declaration result + * @throws WxPayException the wx pay exception + */ + DeclarationResult modify(DeclarationRequest request) throws WxPayException; + + /** + *
+ * 报关重推API + * 文档地址: https://pay.weixin.qq.com/wiki/doc/api/wxpay/ch/declarecustom_ch/chapter3_4.shtml + *+ * + * @param request + * @return 返回数据 redeclaration result + * @throws WxPayException the wx pay exception + */ + RedeclareResult redeclare(RedeclareRequest request) throws WxPayException; +} diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImpl.java new file mode 100644 index 0000000000..d25ed7c0a2 --- /dev/null +++ b/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; + +/** + *
+ * 支付报关 实现. + * Created by xifengzhu on 2022/05/05. + *+ * + * @author xifengzhu + */ +@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字节"); + } + } +} diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/CustomDeclarationServiceImplTest.java new file mode 100644 index 0000000000..6a219ee2f3 --- /dev/null +++ b/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); + } +}