🆕 #2257【微信支付】增加微信签约代扣相关接口

This commit is contained in:
po 2021-08-13 17:53:01 +08:00 committed by GitHub
parent ed6bd016f5
commit 3f42a162c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 3014 additions and 0 deletions

View File

@ -0,0 +1,193 @@
package com.github.binarywang.wxpay.bean.request;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;
import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/**
* @author chenliang
* @date 2021-08-02 5:12 下午
*
* <pre>
* 微信h5纯签约入参
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
@XStreamAlias("xml")
public class WxH5EntrustRequest extends BaseWxPayRequest {
/**
* <pre>
* 协议模板ID
* plan_id
*
* String(28)
* 12535
* 协议模板ID分为首次签约支付中签约重新签约
* </pre>
*/
@Required
@XStreamAlias("plan_id")
private String planId;
/**
* <pre>
* 签约协议号
* contract_code
*
* String(32)
* 100000
* 商户侧签约协议号由商户生成只能是数字大小写字母组成
* </pre>
*/
@Required
@XStreamAlias("contract_code")
private String contractCode;
/**
* <pre>
* 请求序列号
* request_serial
*
* int(64)
* 1000
* 商户请求签约时的序列号要求唯一性禁止使用0开头的用户排序纯数字
* </pre>
*/
@Required
@XStreamAlias("request_serial")
private Long requestSerial;
/**
* <pre>
* 用户账户展示名称
* contract_display_account
*
* string(32)
* 微信代扣
* 签约用户的名称用户页面展示不支持符号表情
* </pre>
*/
@Required
@XStreamAlias("contract_display_account")
private String contractDisplayAccount;
/**
* <pre>
* 回调通知URL
* notify_url
*
* string(256)
* https://weixin.qq.com
* 用于接收签约成功消息的回调通知地址
* </pre>
*/
@Required
@XStreamAlias("notify_url")
private String notifyUrl;
/**
* <pre>
* 版本号
* sign
*
* string(8)
* 1.0
* 固定值1.0
* </pre>
*/
@Required
@XStreamAlias("version")
private String version;
/**
* <pre>
* 时间戳
* timestamp
*
* string(10)
* 1414488825
* 系统当前时间10位
* </pre>
*/
@Required
@XStreamAlias("timestamp")
private String timestamp;
/**
* <pre>
* 客户端IP
* clientip
*
* string(32)
* 127.0.0.1
* 用户客户端的IP地址
* </pre>
*/
@Required
@XStreamAlias("clientip")
private String clientIp;
/**
* <pre>
* 回调应用appid
* return_appid
*
* string(32)
* wxcbda96de0b16
* 用来控制签约页面结束后的返回路径
* 当指定该字段是签约成功将返回return_appid指定的APP应用如果不填且签约发起的浏览器ua可被微信识别
* 则挑战到浏览器否则留在微信
* </pre>
*/
@XStreamAlias("return_appid")
private String returnAppid;
/**
* <pre>
* 商户测用户标识
* outerid
*
* string(32)
* *(10000001)
* 用于多账号签约值与contract_display_account一样就行
* </pre>
*/
@XStreamAlias("outerid")
private String outerId;
/**
* 是否需要nonce_str
*/
@Override
protected boolean needNonceStr() {
return false;
}
@Override
protected void checkConstraints() throws WxPayException {
}
@Override
protected void storeMap(Map<String, String> map) {
map.put("plan_id", planId);
map.put("contract_code", contractCode);
map.put("request_serial", String.valueOf(requestSerial));
map.put("contract_display_account", contractDisplayAccount);
map.put("notify_url", notifyUrl);
map.put("version", version);
map.put("timestamp", timestamp);
map.put("clientip", clientIp);
map.put("return_appid", returnAppid);
map.put("outerid", outerId);
}
}

View File

@ -0,0 +1,179 @@
package com.github.binarywang.wxpay.bean.request;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.SerializedName;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;
import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/**
* @author chenliang
* @date 2021-08-02 5:13 下午
* <pre>
* 小程序纯签约入参
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
@XStreamAlias("xml")
public class WxMaEntrustRequest extends BaseWxPayRequest {
/**
* <pre>
* 协议模板ID
* plan_id
*
* String(28)
* 12535
* 协议模板ID分为首次签约支付中签约重新签约
* </pre>
*/
@Required
@SerializedName(value = "plan_id")
@XStreamAlias("plan_id")
private String planId;
/**
* <pre>
* 签约协议号
* contract_code
*
* String(32)
* 100000
* 商户侧签约协议号由商户生成只能是数字大小写字母组成
* </pre>
*/
@Required
@SerializedName(value = "contract_code")
@XStreamAlias("contract_code")
private String contractCode;
/**
* <pre>
* 请求序列号
* request_serial
*
* int(64)
* 1000
* 商户请求签约时的序列号要求唯一性禁止使用0开头的用户排序纯数字
* </pre>
*/
@Required
@SerializedName(value = "request_serial")
@XStreamAlias("request_serial")
private Long requestSerial;
/**
* <pre>
* 用户账户展示名称
* contract_display_account
*
* string(32)
* 微信代扣
* 签约用户的名称用户页面展示不支持符号表情
* </pre>
*/
@Required
@SerializedName(value = "contract_display_account")
@XStreamAlias("contract_display_account")
private String contractDisplayAccount;
/**
* <pre>
* 回调通知URL
* notify_url
*
* string(256)
* https://weixin.qq.com
* 用于接收签约成功消息的回调通知地址
* </pre>
*/
@Required
@SerializedName(value = "notify_url")
@XStreamAlias("notify_url")
private String notifyUrl;
/**
* <pre>
* 版本号
* sign
*
* string(8)
* 1.0
* 固定值1.0
* </pre>
*/
@Required
@XStreamAlias("version")
private String version;
/**
* <pre>
* 时间戳
* timestamp
*
* string(10)
* 1414488825
* 系统当前时间10位
* </pre>
*/
@Required
@XStreamAlias("timestamp")
private String timestamp;
/**
* <pre>
* 商户侧用户标识
* outerId
*
* String
* *(141448825)
* 用户在商户侧的标识
* </pre>
*/
@XStreamAlias("outerid")
private String outerId;
@Override
protected void checkConstraints() throws WxPayException {
}
/**
* 是否需要nonce_str
*/
@Override
protected boolean needNonceStr() {
return false;
}
@Override
protected void storeMap(Map<String, String> map) {
map.put("plan_id", planId);
map.put("contract_code", contractCode);
map.put("request_serial", String.valueOf(requestSerial));
map.put("contract_display_account", contractDisplayAccount);
map.put("notify_url", notifyUrl);
map.put("timestamp", timestamp);
map.put("outerid", outerId);
}
@Override
public String toString() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
Gson gson = gsonBuilder.create();
return gson.toJson(this);
}
}

View File

@ -0,0 +1,179 @@
package com.github.binarywang.wxpay.bean.request;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;
import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
import java.util.Objects;
/**
* @author chenliang
* @date 2021-08-02 5:17 下午
*
* <pre>
* 公众号纯签约入参
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
@XStreamAlias("xml")
public class WxMpEntrustRequest extends BaseWxPayRequest {
/**
* <pre>
* 协议模板ID
* plan_id
*
* String(28)
* 12535
* 协议模板ID分为首次签约支付中签约重新签约
* </pre>
*/
@Required
@XStreamAlias("plan_id")
private String planId;
/**
* <pre>
* 签约协议号
* contract_code
*
* String(32)
* 100000
* 商户侧签约协议号由商户生成只能是数字大小写字母组成
* </pre>
*/
@Required
@XStreamAlias("contract_code")
private String contractCode;
/**
* <pre>
* 请求序列号
* request_serial
*
* int(64)
* 1000
* 商户请求签约时的序列号要求唯一性禁止使用0开头的用户排序纯数字
* </pre>
*/
@Required
@XStreamAlias("request_serial")
private Long requestSerial;
/**
* <pre>
* 用户账户展示名称
* contract_display_account
*
* string(32)
* 微信代扣
* 签约用户的名称用户页面展示不支持符号表情
* </pre>
*/
@Required
@XStreamAlias("contract_display_account")
private String contractDisplayAccount;
/**
* <pre>
* 回调通知URL
* notify_url
*
* string(256)
* https://weixin.qq.com
* 用于接收签约成功消息的回调通知地址
* </pre>
*/
@Required
@XStreamAlias("notify_url")
private String notifyUrl;
/**
* <pre>
* 版本号
* sign
*
* string(8)
* 1.0
* 固定值1.0
* </pre>
*/
@Required
@XStreamAlias("version")
private String version;
/**
* <pre>
* 时间戳
* timestamp
*
* string(10)
* 1414488825
* 系统当前时间10位
* </pre>
*/
@Required
@XStreamAlias("timestamp")
private String timestamp;
/**
* <pre>
* 返回web
* return_web
*
* int
* 1
* 用来控制签约页面结束后的返回路径不传签约后留在微信内1 表示返回签约页面的referrer url,
* 不填或获取不到referrer则不返回跳转referrer url 时会自动带上from_wxpay=1
* </pre>
*/
@XStreamAlias("return_web")
private Integer returnWeb;
/**
* <pre>
* 商户测的用户标识
* outerid
*
* String()
* *(101000203)
* 用于多账户签约同一个模板下要保持一致取值和contractDisplayAccount取一样就行
* </pre>
*/
@XStreamAlias("outerid")
private String outerId;
@Override
protected void checkConstraints() throws WxPayException {
}
/**
* 是否需要nonce_str
*/
@Override
protected boolean needNonceStr() {
return false;
}
@Override
protected void storeMap(Map<String, String> map) {
map.put("plan_id", planId);
map.put("contract_code", contractCode);
map.put("request_serial", String.valueOf(requestSerial));
map.put("contract_display_account", contractDisplayAccount);
map.put("notify_url", notifyUrl);
map.put("version", version);
map.put("timestamp", timestamp);
if (Objects.nonNull(returnWeb)) {
map.put("return_web", String.valueOf(returnWeb));
}
map.put("outerid", outerId);
}
}

View File

@ -0,0 +1,368 @@
package com.github.binarywang.wxpay.bean.request;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;
import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/**
* @author chenliang
* @date 2021-08-02 5:18 下午
* <pre>
* 支付中签约入参
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
@XStreamAlias("xml")
public class WxPayEntrustRequest extends BaseWxPayRequest {
/**
* <pre>
* 签约商户号
* contract_mchid
*
* String(32)
* 1200009811
* 签约商户号必须与mch_id一致
* </pre>
*/
@Required
@XStreamAlias("contract_mchid")
private String contractMchId;
/**
* <pre>
* 签约APPID
* contract_appid
*
* String(32)
* wxcbda96de0b165486
* 签约公众号必须与APPID一致
* </pre>
*/
@Required
@XStreamAlias("contract_appid")
private String contractAppId;
/**
* <pre>
* 商户订单号
* out_trade_no
*
* String(32)
* 123456
* 商户系统内部的订单号32字符内可包含字母
* </pre>
*/
@Required
@XStreamAlias("out_trade_no")
private String outTradeNo;
/**
* <pre>
* 设备号
* device_info
*
* String(32)
* 013467007045764
* 终端设备号若为PC网页或公众号内则传WEB
* </pre>
*/
@XStreamAlias("device_info")
private String deviceInfo;
/**
* <pre>
* 商品描述
* body
*
* String(128)
* ipad mini 16G 白色
* 商品支付单简要描述
* </pre>
*/
@Required
@XStreamAlias("body")
private String body;
/**
* <pre>
* 商品详情
* detail
*
* String(8192)
* ipad mini 16G 白色
* 商品名称明细列表
* </pre>
*/
@XStreamAlias("detail")
private String detail;
/**
* <pre>
* 附加数据
* attach
*
* String(127)
* online/dev/dev1
* 商家数据包
* </pre>
*/
@XStreamAlias("attach")
private String attach;
/**
* <pre>
* 回调通知url
* notify_url
*
* String(256)
* https://weixin.qq.com
* 回调通知地址
* </pre>
*/
@Required
@XStreamAlias("notify_url")
private String notifyUrl;
/**
* <pre>
* 总金额
* total_fee
*
* int
* 888
* 订单总金额单位分
* </pre>
*/
@Required
@XStreamAlias("total_fee")
private Integer totalFee;
/**
* <pre>
* 终端ip
* spbill_create_ip
*
* String(16)
* 127.0.0.1
* 用户的客户端IP
* </pre>
*/
@Required
@XStreamAlias("spbill_create_ip")
private String spbillCreateIp;
/**
* <pre>
* 交易起始时间
* time_start
*
* String(14)
* 20201025171529
* 订单生成时间格式yyyyMMddHHmmss
* </pre>
*/
@XStreamAlias("time_start")
private String timeStart;
/**
* <pre>
* 交易结束时间
* time_expire
*
* String(14)
* 20201025171529
* 订单失效时间格式yyyyMMddHHmmss
* </pre>
*/
@XStreamAlias("time_expire")
private String timeExpire;
/**
* <pre>
* 商品标记
* goods_tag
*
* String(32)
* wxg
* 商品标记代金券或立减优惠功能参数
* </pre>
*/
@XStreamAlias("goods_tag")
private String goodsTag;
/**
* <pre>
* 交易类型
* trade_type
*
* String(16)
* JSAPI
* JSAPI,MWEB
* </pre>
*/
@Required
@XStreamAlias("trade_type")
private String tradeType;
/**
* <pre>
* 商品ID
* product_id
*
* String(32)
* 12234355463434643
* 二维码支付必传二维码中包含商品ID
* </pre>
*/
@XStreamAlias("product_id")
private String productId;
/**
* <pre>
* 指定支付方式
* limit_pay
*
* String(32)
* no_credit
* no_credit--指定不能使用信用卡支付
* </pre>
*/
@XStreamAlias("limit_pay")
private String limitPay;
/**
* <pre>
* 用户表示
* openid
*
* String(128)
* oUpF4sdsidj3Jds89
* tradetype=JSAPI 则必传
* </pre>
*/
@XStreamAlias("openid")
private String openId;
/**
* <pre>
* 协议模板ID
* plan_id
*
* String(28)
* 12535
* 协议模板ID分为首次签约支付中签约重新签约
* </pre>
*/
@Required
@XStreamAlias("plan_id")
private String planId;
/**
* <pre>
* 签约协议号
* contract_code
*
* String(32)
* 100000
* 商户侧签约协议号由商户生成只能是数字大小写字母组成
* </pre>
*/
@Required
@XStreamAlias("contract_code")
private String contractCode;
/**
* <pre>
* 请求序列号
* request_serial
*
* int(64)
* 1000
* 商户请求签约时的序列号要求唯一性禁止使用0开头的用户排序纯数字
* </pre>
*/
@Required
@XStreamAlias("request_serial")
private Long requestSerial;
/**
* <pre>
* 用户账户展示名称
* contract_display_account
*
* string(32)
* 微信代扣
* 签约用户的名称用户页面展示不支持符号表情
* </pre>
*/
@Required
@XStreamAlias("contract_display_account")
private String contractDisplayAccount;
/**
* <pre>
* 签约信息通知URL
* contract_notify_url
*
* string(32)
* https://yoursite.com
* 签约信息回调通知URL
* </pre>
*/
@Required
@XStreamAlias("contract_notify_url")
private String contractNotifyUrl;
/**
* <pre>
* 商户测的用户标识
* contract_outerid
*
* string(32)
* *(12000002)
* 用于多账户签约值与contract_display_account相同即可同一模板下唯一
* </pre>
*/
@XStreamAlias("contract_outerid")
private String contractOuterId;
@Override
protected void checkConstraints() throws WxPayException {
}
@Override
protected void storeMap(Map<String, String> map) {
map.put("contract_mchid", contractMchId);
map.put("contract_appid", contractAppId);
map.put("out_trade_no", outTradeNo);
map.put("device_info", deviceInfo);
map.put("body", body);
map.put("detail", detail);
map.put("attach", attach);
map.put("notify_url", notifyUrl);
map.put("total_fee", totalFee.toString());
map.put("spbill_create_ip", spbillCreateIp);
map.put("time_start", timeStart);
map.put("time_expire", timeExpire);
map.put("goods_tag", goodsTag);
map.put("trade_type", tradeType);
map.put("product_id", productId);
map.put("limit_pay", limitPay);
map.put("openid", openId);
map.put("plan_id", planId);
map.put("contract_code", contractCode);
map.put("request_serial", requestSerial.toString());
map.put("contract_display_account", contractDisplayAccount);
map.put("contract_notify_url", contractNotifyUrl);
map.put("contract_outerid", contractOuterId);
}
}

View File

@ -0,0 +1,65 @@
package com.github.binarywang.wxpay.bean.request;
import com.google.gson.annotations.SerializedName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author chenliang
* @date 2021-08-02 5:20 下午
*
* <pre>
* 微信预扣款请求参数
* </pre>
*/
@Data
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
public class WxPreWithholdRequest implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 委托代扣协议ID
*/
@SerializedName(value = "contract_id")
private String contractId;
/**
* 直连商户号
*/
@SerializedName(value = "mchid")
private String mchId;
/**
* 公众号ID
*/
@SerializedName(value = "appid")
private String appId;
/**
* 预计扣款的金额信息
*/
@SerializedName(value = "estimated_amount")
private EstimateAmount estimateAmount;
@Data
public static class EstimateAmount implements Serializable {
/**
* 预计扣费金额
*/
private Integer amount;
/**
* 人民币CNY
* 非必填
*/
private String currency;
}
}

View File

@ -0,0 +1,105 @@
package com.github.binarywang.wxpay.bean.request;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;
import me.chanjar.weixin.common.annotation.Required;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import java.util.Objects;
/**
* @author chenliang
* @date 2021-08-02 5:23 下午
* <pre>
* 微信签约状态查询入参
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
@XStreamAlias("xml")
public class WxSignQueryRequest extends BaseWxPayRequest {
//方式1. 使用contract_id查
/**
* <pre>
* 字段名委托代扣协议ID.
* 变量名contract_id
* 是否必填二选一
* 类型String(32)
* 示例值1000005698
* 签约成功后由微信返回
* </pre>
*/
@XStreamAlias("contract_id")
private String contractId;
/**
* <pre>
* 字段名接口版本号.
* 变量名version
* 是否必填
* 类型String(8)
* 示例值1.0
* 固定填写1.0
* </pre>
*/
@Required
@XStreamAlias("version")
private String version;
//方式2. 使用plan_id和contract_code查
/**
* <pre>
* 字段名模板ID.
* 变量名plan_id
* 是否必填二选一
* 类型int
* 示例值123
* 代扣模板ID
* </pre>
*/
@XStreamAlias("plan_id")
private Integer planId;
/**
* <pre>
* 字段名签约协议号.
* 变量名contract_code
* 是否必填二选一
* 类型String(32)
* 示例值12332343
* 商户侧唯一
* </pre>
*/
@XStreamAlias("contract_code")
private String contractCode;
@Override
protected boolean needNonceStr() {
return false;
}
@Override
protected void checkConstraints() throws WxPayException {
if (StringUtils.isNotBlank(contractId) &&
(Objects.nonNull(planId) || StringUtils.isNotBlank(contractCode))) {
throw new WxPayException("contractId 和 planId&contractCode 不能同时存在或同时为空,必须二选一");
}
}
@Override
protected void storeMap(Map<String, String> map) {
map.put("contract_id", contractId);
map.put("version", version);
if (Objects.nonNull(planId)) {
map.put("plan_id", planId.toString());
}
map.put("contract_code", contractCode);
}
}

View File

@ -0,0 +1,122 @@
package com.github.binarywang.wxpay.bean.request;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;
import me.chanjar.weixin.common.annotation.Required;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import java.util.Objects;
/**
* @author chenliang
* @date 2021-08-02 5:24 下午
*
* <pre>
* 微信api申请解约
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
@XStreamAlias("xml")
public class WxTerminatedContractRequest extends BaseWxPayRequest {
//方式1. 使用contract_id查
/**
* <pre>
* 字段名委托代扣协议ID.
* 变量名contract_id
* 是否必填二选一
* 类型String(32)
* 示例值1000005698
* 签约成功后由微信返回
* </pre>
*/
@XStreamAlias("contract_id")
private String contractId;
/**
* <pre>
* 字段名解约备注.
* 变量名contract_termination_remark
* 是否必填
* 类型String(256)
* 示例值解约原因
* 例如签约信息有误须重新签约
* </pre>
*/
@Required
@XStreamAlias("contract_termination_remark")
private String contractTerminationRemark;
/**
* <pre>
* 字段名接口版本号.
* 变量名version
* 是否必填
* 类型String(8)
* 示例值1.0
* 固定填写1.0
* </pre>
*/
@Required
@XStreamAlias("version")
private String version;
//方式2. 使用plan_id和contract_code查
/**
* <pre>
* 字段名模板ID.
* 变量名plan_id
* 是否必填二选一
* 类型int
* 示例值123
* 代扣模板ID
* </pre>
*/
@XStreamAlias("plan_id")
private Integer planId;
/**
* <pre>
* 字段名签约协议号.
* 变量名contract_code
* 是否必填二选一
* 类型String(32)
* 示例值12332343
* 商户侧唯一
* </pre>
*/
@XStreamAlias("contract_code")
private String contractCode;
@Override
protected void checkConstraints() throws WxPayException {
if (StringUtils.isNotBlank(contractId) &&
(Objects.nonNull(planId) || StringUtils.isNotBlank(contractCode))) {
throw new WxPayException("contractId 和 planId&contractCode 不能同时存在或同时为空,必须二选一");
}
}
@Override
protected boolean needNonceStr() {
return false;
}
@Override
protected void storeMap(Map<String, String> map) {
map.put("contract_id", contractId);
map.put("contract_termination_remark", contractTerminationRemark);
map.put("version", version);
if (Objects.nonNull(planId)) {
map.put("plan_id", planId.toString());
}
map.put("contract_code", contractCode);
}
}

View File

@ -0,0 +1,64 @@
package com.github.binarywang.wxpay.bean.request;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
/**
* @author chenliang
* @date 2021-08-02 5:25 下午
*
* <pre>代扣订单查询参数</pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
@XStreamAlias("xml")
public class WxWithholdOrderQueryRequest extends BaseWxPayRequest {
/**
* <pre>
* 字段名微信订单号.
* 变量名transaction_id
* 是否必填二选一
* 类型String(32)
* 示例值1000005698
* 微信生成的单号支付通知中返回
* </pre>
*/
@XStreamAlias("transaction_id")
private String transactionId;
/**
* <pre>
* 字段名商户订单号.
* 变量名out_trade_no
* 是否必填二选一
* 类型String(32)
* 示例值1000005698
* 商户系统内部订单号
* </pre>
*/
@XStreamAlias("out_trade_no")
private String outTradeNo;
@Override
protected void checkConstraints() throws WxPayException {
if (StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(outTradeNo)) {
throw new WxPayException("transactionId 和 outTradeNo 不能同时存在或同时为空,必须二选一");
}
}
@Override
protected void storeMap(Map<String, String> map) {
map.put("transaction_id", transactionId);
map.put("out_trade_no", outTradeNo);
}
}

View File

@ -0,0 +1,194 @@
package com.github.binarywang.wxpay.bean.request;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.*;
import me.chanjar.weixin.common.annotation.Required;
import java.util.Map;
/**
* @author chenliang
* @date 2021-08-02 5:26 下午
*
* <pre>
* 发起微信委托代扣参数
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Builder(builderMethodName = "newBuilder")
@NoArgsConstructor
@AllArgsConstructor
@XStreamAlias("xml")
public class WxWithholdRequest extends BaseWxPayRequest {
/**
* <pre>
* 商品描述
* body
*
* String(128)
* ipad mini 16G 白色
* 商品支付单简要描述
* </pre>
*/
@Required
@XStreamAlias("body")
private String body;
/**
* <pre>
* 商品详情
* detail
*
* String(8192)
* ipad mini 16G 白色
* 商品名称明细列表
* </pre>
*/
@XStreamAlias("detail")
private String detail;
/**
* <pre>
* 附加数据
* attach
*
* String(127)
* online/dev/dev1
* 商家数据包
* </pre>
*/
@XStreamAlias("attach")
private String attach;
/**
* <pre>
* 商户订单号
* out_trade_no
*
* String(32)
* 123456
* 商户系统内部的订单号32字符内可包含字母
* </pre>
*/
@Required
@XStreamAlias("out_trade_no")
private String outTradeNo;
/**
* <pre>
* 总金额
* total_fee
*
* int
* 888
* 订单总金额单位分
* </pre>
*/
@Required
@XStreamAlias("total_fee")
private Integer totalFee;
/**
* <pre>
* 货币类型
* fee_type
*
* String(16)
* CNY
* 默认人民币CNY
* </pre>
*/
@XStreamAlias("fee_type")
private String feeType;
/**
* <pre>
* 终端ip
* spbill_create_ip
*
* String(16)
* 127.0.0.1
* 用户的客户端IP
* </pre>
*/
@XStreamAlias("spbill_create_ip")
private String spbillCreateIp;
/**
* <pre>
* 商品标记
* goods_tag
*
* String(32)
* wxg
* 商品标记代金券或立减优惠功能参数
* </pre>
*/
@XStreamAlias("goods_tag")
private String goodsTag;
/**
* <pre>
* 回调通知url
* notify_url
*
* String(256)
* https://weixin.qq.com
* 回调通知地址
* </pre>
*/
@Required
@XStreamAlias("notify_url")
private String notifyUrl;
/**
* <pre>
* 交易类型
* trade_type
*
* String(16)
* JSAPI
* JSAPI,MWEB
* </pre>
*/
@Required
@XStreamAlias("trade_type")
private String tradeType;
/**
* <pre>
* 委托代扣协议ID
* contract_id
*
* String(32)
* Wx234324808503234483920
* 签约成功后微信返回的委托代扣协议ID
* </pre>
*/
@Required
@XStreamAlias("contract_id")
private String contractId;
@Override
protected void checkConstraints() throws WxPayException {
}
@Override
protected void storeMap(Map<String, String> map) {
map.put("body", body);
map.put("detail", detail);
map.put("attach", attach);
map.put("out_trade_no", outTradeNo);
map.put("total_fee", totalFee.toString());
map.put("fee_type", feeType);
map.put("spbill_create_ip", spbillCreateIp);
map.put("goods_tag", goodsTag);
map.put("notify_url", notifyUrl);
map.put("trade_type", tradeType);
map.put("contract_id", contractId);
}
}

View File

@ -0,0 +1,43 @@
package com.github.binarywang.wxpay.bean.result;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
import java.io.Serializable;
/**
* @author chenliang
* @date 2021-08-02 5:37 下午
*
* <pre>
* h5纯签约后结果
* </pre>
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WxH5EntrustResult extends BaseWxPayResult implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 业务结果描述
*/
@XStreamAlias("result_msg")
private String resultMsg;
/**
* 跳转url
*/
@XStreamAlias("redirect_url")
private String redirectUrl;
@Override
protected void loadXml(Document d) {
resultMsg = readXmlString(d, "result_msg");
redirectUrl = readXmlString(d, "redirect_url");
}
}

View File

@ -0,0 +1,190 @@
package com.github.binarywang.wxpay.bean.result;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.google.common.collect.Lists;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* @author chenliang
* @date 2021-08-02 5:38 下午
*
* <pre>
* 支付中签约返回结果
* </pre>
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WxPayEntrustResult extends BaseWxPayResult implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 预签约结果
*/
@XStreamAlias("contract_result_code")
private String contractResultCode;
/**
* 预约签约错误码
*/
@XStreamAlias("contract_err_code")
private String contractErrCode;
/**
* 预签约错误描述
*/
@XStreamAlias("contract_err_code_des")
private String contractErrCodeDes;
/**
* 预支付ID
*/
@XStreamAlias("prepay_id")
private String prepayId;
/**
* 交易类型
*/
@XStreamAlias("trade_type")
private String tradeType;
/**
* 二维码链接
* 非必传
*/
@XStreamAlias("code_url")
private String codeUrl;
/**
* 模板ID
* 非必传
*/
@XStreamAlias("plan_id")
private Integer planId;
/**
* 请求序列号
* 非必传
*/
@XStreamAlias("request_serial")
private Integer requestSerial;
/**
* 签约协议号
* 非必传
*/
@XStreamAlias("contract_code")
private String contractCode;
/**
* 用户账户展示名称
* 非必传
*/
@XStreamAlias("contract_display_account")
private String contractDisplayAccount;
/**
* 支付跳转链接
* 非必传
*/
@XStreamAlias("mweb_url")
private String mwebUrl;
/**
* 商户订单号
*/
@XStreamAlias("out_trade_no")
private String outTradeNo;
@Override
protected void loadXml(Document d) {
contractResultCode = readXmlString(d, "contract_result_code");
contractErrCode = readXmlString(d, "contract_err_code");
contractErrCodeDes = readXmlString(d, "contract_err_code_des");
prepayId = readXmlString(d, "prepay_id");
tradeType = readXmlString(d, "trade_type");
codeUrl = readXmlString(d, "code_url");
planId = readXmlInteger(d, "plan_id");
requestSerial = readXmlInteger(d, "request_serial");
contractCode = readXmlString(d, "contract_code");
contractDisplayAccount = readXmlString(d, "contract_display_account");
mwebUrl = readXmlString(d, "mweb_url");
outTradeNo = readXmlString(d, "out_trade_no");
}
/**
* 校验返回结果签名.
*
* @param wxPayService the wx pay service
* @param signType 签名类型
* @param checkSuccess 是否同时检查结果是否成功
* @throws WxPayException the wx pay exception
*/
@Override
public void checkResult(WxPayService wxPayService, String signType, boolean checkSuccess) throws WxPayException {
//校验返回结果签名
Map<String, String> map = toMap();
if (getSign() != null && !SignUtils.checkSign(map, signType, wxPayService.getConfig().getMchKey())) {
this.getLogger().debug("校验结果签名失败,参数:{}", map);
throw new WxPayException("参数格式校验错误!");
}
//校验结果是否成功
if (checkSuccess) {
List<String> successStrings = Lists.newArrayList(WxPayConstants.ResultCode.SUCCESS, "");
if (!successStrings.contains(StringUtils.trimToEmpty(getReturnCode()).toUpperCase())
|| !successStrings.contains(StringUtils.trimToEmpty(getResultCode()).toUpperCase())) {
StringBuilder errorMsg = new StringBuilder();
if (getReturnCode() != null) {
errorMsg.append("返回代码:").append(getReturnCode());
}
if (getReturnMsg() != null) {
errorMsg.append(",返回信息:").append(getReturnMsg());
}
if (getResultCode() != null) {
errorMsg.append(",结果代码:").append(getResultCode());
}
if (getErrCode() != null) {
errorMsg.append(",错误代码:").append(getErrCode());
}
if (getErrCodeDes() != null) {
errorMsg.append(",错误详情:").append(getErrCodeDes());
}
if (getContractErrCode() != null) {
errorMsg.append(",预签约错误代码:").append(getContractErrCode());
}
if (getContractErrCodeDes() != null) {
errorMsg.append(",预签约错误描述:").append(getContractErrCodeDes());
}
if (getContractResultCode() != null) {
errorMsg.append(",预签约结果:").append(getContractResultCode());
}
this.getLogger().warn("\n结果业务代码异常返回结果{},\n{}", map, errorMsg.toString());
throw WxPayException.from(this);
}
}
}
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
}

View File

@ -0,0 +1,123 @@
package com.github.binarywang.wxpay.bean.result;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import org.w3c.dom.Document;
import java.io.Serializable;
/**
* @author chenliang
* @date 2021-08-02 5:40 下午
*
* <pre>
* 微信签约查询返回结果
* </pre>
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WxSignQueryResult extends BaseWxPayResult implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 委托代扣协议ID
*/
@XStreamAlias("contractId")
private String contractId;
/**
* 模板ID
*/
@XStreamAlias("plan_id")
private String planId;
/**
* 请求序列号
*/
@XStreamAlias("request_serial")
private Integer requestSerial;
/**
* 签约协议号
*/
@XStreamAlias("contract_code")
private String contractCode;
/**
* 用户账户展示名称
*/
@XStreamAlias("contract_display_account")
private String contractDisplayAccount;
/**
* 协议状态
*/
@XStreamAlias("contract_state")
private Integer contractState;
/**
* 协议签署时间
*/
@XStreamAlias("contract_signed_time")
private String contractSignedTime;
/**
* 协议到期时间
*/
@XStreamAlias("contract_expired_time")
private String contractExpiredTime;
/**
* 协议解约时间
* 非必传
*/
@XStreamAlias("contract_terminated_time")
private String contractTerminatedTime;
/**
* 协议解约方式
* 非必传
*/
@XStreamAlias("contract_terminated_mode")
private Integer contractTerminatedMode;
/**
* 解约备注
* 非必传
*/
@XStreamAlias("contract_termination_remark")
private String contractTerminationRemark;
/**
* 用户表示
*/
@XStreamAlias("openid")
private String openId;
@Override
protected void loadXml(Document d) {
contractId = readXmlString(d, "contract_id");
planId = readXmlString(d, "plan_id");
requestSerial = readXmlInteger(d, "request_serial");
contractCode = readXmlString(d, "contract_code");
contractDisplayAccount = readXmlString(d, "contract_display_account");
contractState = readXmlInteger(d, "contract_state");
contractSignedTime = readXmlString(d, "contract_signed_time");
contractExpiredTime = readXmlString(d, "contrace_Expired_time");
contractTerminatedTime = readXmlString(d, "contract_terminated_time");
contractTerminatedMode = readXmlInteger(d, "contract_terminate_mode");
contractTerminationRemark = readXmlString(d, "contract_termination_remark");
openId = readXmlString(d, "openid");
}
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
}

View File

@ -0,0 +1,127 @@
package com.github.binarywang.wxpay.bean.result;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.w3c.dom.Document;
/**
* @author chenliang
* @date 2021-08-02 4:59 下午
* <pre>
* 微信签约/解约 回调结果
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@XStreamAlias("xml")
public class WxSignStatusNotifyResult extends BaseWxPayResult {
private static final long serialVersionUID = 1L;
/**
* 签约协议号
*/
@XStreamAlias("contract_code")
private String contractCode;
/**
* 模板ID
*/
@XStreamAlias("plan_id")
private String planId;
/**
* 用户表示
*/
@XStreamAlias("openid")
private String openId;
/**
* 变更类型 ADD签约DELETE解约
*/
@XStreamAlias("change_type")
private String changeType;
/**
* 操作时间
*/
@XStreamAlias("operate_time")
private String operateTime;
/**
* 委托代扣协议ID
*/
@XStreamAlias("contract_id")
private String contractId;
/**
* 协议到期时间ADD会有长期有效忽略
* 非必传
*/
@XStreamAlias("contract_expired_time")
private String contractExpiredTime;
/**
* DELETE时返回0: 未解约1有效期过期自动解约2用户主动解约3商户api解约4商户平台解约5用户账号注销
* 非必传
*/
@XStreamAlias("contract_termination_mode")
private Integer contractTerminationMode;
/**
* 请求序列号
*/
@XStreamAlias("request_serial")
private Integer requestSerial;
@Override
public void checkResult(WxPayService wxPayService, String signType, boolean checkSuccess) throws WxPayException {
//防止伪造成功通知
if (WxPayConstants.ResultCode.SUCCESS.equals(getReturnCode()) && getSign() == null) {
throw new WxPayException("伪造的通知!");
}
super.checkResult(wxPayService, signType, checkSuccess);
}
/**
* From xml wx sign notify result.
*
* @param xmlString the xml string
* @return the wx sign result
*/
public static WxSignStatusNotifyResult fromXML(String xmlString) {
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxSignStatusNotifyResult.class);
WxSignStatusNotifyResult result = (WxSignStatusNotifyResult) xstream.fromXML(xmlString);
result.setXmlString(xmlString);
return result;
}
@Override
protected void loadXml(Document d) {
contractCode = readXmlString(d, "contract_code");
planId = readXmlString(d, "plan_id");
openId = readXmlString(d, "openid");
changeType = readXmlString(d, "change_type");
operateTime = readXmlString(d, "operate_time");
contractId = readXmlString(d, "contract_id");
contractExpiredTime = readXmlString(d, "contract_expired_time");
contractTerminationMode = readXmlInteger(d, "contract_termination_mode");
requestSerial = readXmlInteger(d, "request_serial");
}
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
}

View File

@ -0,0 +1,57 @@
package com.github.binarywang.wxpay.bean.result;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import org.w3c.dom.Document;
import java.io.Serializable;
/**
* @author chenliang
* @date 2021-08-02 5:41 下午
*
* <pre>
* 主动解约返回值
* </pre>
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WxTerminationContractResult extends BaseWxPayResult implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 委托代扣协议ID
*/
@XStreamAlias("contractId")
private String contractId;
/**
* 模板ID
*/
@XStreamAlias("plan_id")
private String planId;
/**
* 签约协议号
*/
@XStreamAlias("contract_code")
private String contractCode;
@Override
protected void loadXml(Document d) {
contractId = readXmlString(d, "contract_id");
planId = readXmlString(d, "plan_id");
contractCode = readXmlString(d, "contract_code");
}
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
}

View File

@ -0,0 +1,234 @@
package com.github.binarywang.wxpay.bean.result;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyCoupon;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.converter.WxPayOrderNotifyResultConverter;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import me.chanjar.weixin.common.util.xml.XStreamInitializer;
import org.w3c.dom.Document;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author chenliang
* @date 2021-08-02 5:09 下午
*
* <pre>
* 微信代扣扣款回调结果
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@XStreamAlias("xml")
public class WxWithholdNotifyResult extends BaseWxPayResult {
private static final long serialVersionUID = 1L;
/**
* 设备号
* 非必传
*/
@XStreamAlias("device_info")
private String deviceInfo;
/**
* 用户标识
*/
@XStreamAlias("openid")
private String openId;
/**
* 用户子标识
* 非必传
*/
@XStreamAlias("sub_openid")
private String subOpenId;
/**
* 是否关注公众号
* 非必传
*/
@XStreamAlias("is_subscribe")
private String isSubscribe;
/**
* 付款银行
*/
@XStreamAlias("bank_type")
private String bankType;
/**
* 总金额
*/
@XStreamAlias("total_fee")
private Integer totalFee;
/**
* 货币类型
* 非必传
*/
@XStreamAlias("fee_type")
private String feeType;
/**
* 现金支付金额
*/
@XStreamAlias("cash_fee")
private Integer cashFee;
/**
* 现金支付货币类型
* 非必传
*/
@XStreamAlias("cash_fee_type")
private String cashFeeType;
/**
* 交易状态
* SUCCESS 支付成功REFUND转入退款NOTPAY未支付CLOSED已关闭ACCEPT已接收PAY_FAIL:支付失败
*/
@XStreamAlias("trade_state")
private String tradeState;
/**
* 代金券或立减优惠金额
* 非必传
*/
@XStreamAlias("coupon_fee")
private Integer couponFee;
/**
* 代金券或立减优惠使用数量
*/
@XStreamAlias("coupon_count")
private Integer couponCount;
private List<WxPayOrderNotifyCoupon> couponList;
/**
* 微信支付单号
*/
@XStreamAlias("transaction_id")
private String transactionId;
/**
* 商户订单号
*/
@XStreamAlias("out_trade_no")
private String outTradeNo;
/**
* 商家数据包
*/
@XStreamAlias("attach")
private String attach;
/**
* 支付完成时间
*/
@XStreamAlias("time_end")
private String timeEnd;
/**
* 委托代扣协议ID
*/
@XStreamAlias("contract_id")
private String contractId;
@Override
public void checkResult(WxPayService wxPayService, String signType, boolean checkSuccess) throws WxPayException {
//防止伪造成功通知
if (WxPayConstants.ResultCode.SUCCESS.equals(getReturnCode()) && getSign() == null) {
throw new WxPayException("伪造的通知!");
}
super.checkResult(wxPayService, signType, checkSuccess);
}
/**
* From xml wx withhold notify result.
*
* @param xmlString the xml string
* @return the wx withhold result
*/
public static WxWithholdNotifyResult fromXML(String xmlString) {
XStream xstream = XStreamInitializer.getInstance();
xstream.processAnnotations(WxWithholdNotifyResult.class);
xstream.registerConverter(new WxPayOrderNotifyResultConverter(xstream.getMapper(), xstream.getReflectionProvider()));
WxWithholdNotifyResult result = (WxWithholdNotifyResult) xstream.fromXML(xmlString);
result.setXmlString(xmlString);
return result;
}
@Override
public Map<String, String> toMap() {
Map<String, String> resultMap = SignUtils.xmlBean2Map(this);
if (this.getCouponCount() != null && this.getCouponCount() > 0) {
for (int i = 0; i < this.getCouponCount(); i++) {
WxPayOrderNotifyCoupon coupon = couponList.get(i);
resultMap.putAll(coupon.toMap(i));
}
}
return resultMap;
}
@Override
protected void loadXml(Document d) {
deviceInfo = readXmlString(d, "device_info");
openId = readXmlString(d, "openid");
isSubscribe = readXmlString(d, "is_subscribe");
subOpenId = readXmlString(d, "sub_openid");
bankType = readXmlString(d, "bank_type");
totalFee = readXmlInteger(d, "total_fee");
feeType = readXmlString(d, "fee_type");
cashFee = readXmlInteger(d, "cash_fee");
cashFeeType = readXmlString(d, "cash_fee_type");
couponFee = readXmlInteger(d, "coupon_fee");
couponCount = readXmlInteger(d, "coupon_count");
transactionId = readXmlString(d, "transaction_id");
outTradeNo = readXmlString(d, "out_trade_no");
attach = readXmlString(d, "attach");
timeEnd = readXmlString(d, "time_end");
tradeState = readXmlString(d, "trade_state");
contractId = readXmlString(d, "contract_id");
composeCoupons();
}
/**
* 通过xml组装couponList属性内容.
*/
protected void composeCoupons() {
if (this.couponCount == null || this.couponCount == 0) {
return;
}
this.couponList = new ArrayList(couponCount);
for (int i = 0; i < this.couponCount; i++) {
WxPayOrderNotifyCoupon coupon = new WxPayOrderNotifyCoupon();
coupon.setCouponId(this.getXmlValue("xml/coupon_id_" + i));
coupon.setCouponType(this.getXmlValue("xml/coupon_type_" + i));
coupon.setCouponFee(this.getXmlValueAsInt("xml/coupon_fee_" + i));
couponList.add(coupon);
}
}
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
}

View File

@ -0,0 +1,182 @@
package com.github.binarywang.wxpay.bean.result;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyCoupon;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.w3c.dom.Document;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* @author chenliang
* @date 2021-08-02 5:42 下午
*
* <pre>
* 代扣订单查询结果
* </pre>
*/
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@XStreamAlias("xml")
public class WxWithholdOrderQueryResult extends BaseWxPayResult implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 设备号
* 非必传
*/
@XStreamAlias("device_info")
private String deviceInfo;
/**
* 用户标识
*/
@XStreamAlias("openid")
private String openId;
/**
* 是否关注公众号
* 非必传
*/
@XStreamAlias("is_subscribe")
private String isSubscribe;
/**
* 交易类型
*/
@XStreamAlias("trade_type")
private String tradeType;
/**
* 交易状态
* SUCCESS 支付成功REFUND转入退款NOTPAY未支付CLOSED已关闭ACCEPT已接收PAY_FAIL:支付失败
*/
@XStreamAlias("trade_state")
private String tradeState;
/**
* 付款银行
*/
@XStreamAlias("bank_type")
private String bankType;
/**
* 总金额
*/
@XStreamAlias("total_fee")
private Integer totalFee;
/**
* 货币类型
* 非必传
*/
@XStreamAlias("fee_type")
private String feeType;
/**
* 现金支付金额
*/
@XStreamAlias("cash_fee")
private Integer cashFee;
/**
* 现金支付货币类型
* 非必传
*/
@XStreamAlias("cash_fee_type")
private String cashFeeType;
/**
* 代金券或立减优惠金额
* 非必传
*/
@XStreamAlias("coupon_fee")
private Integer couponFee;
/**
* 代金券或立减优惠使用数量
*/
@XStreamAlias("coupon_count")
private Integer couponCount;
private List<WxPayOrderNotifyCoupon> couponList;
/**
* 微信支付单号
*/
@XStreamAlias("transaction_id")
private String transactionId;
/**
* 商户订单号
*/
@XStreamAlias("out_trade_no")
private String outTradeNo;
/**
* 商家数据包
*/
@XStreamAlias("attach")
private String attach;
/**
* 支付完成时间
*/
@XStreamAlias("time_end")
private String timeEnd;
/**
* 交易状态描述
* 例如支付失败请重新下单
*/
@XStreamAlias("trade_state_desc")
private String tradeStateDesc;
/**
* 通过xml组装couponList属性内容.
*/
protected void composeCoupons() {
if (this.couponCount == null || this.couponCount == 0) {
return;
}
this.couponList = new ArrayList(couponCount);
for (int i = 0; i < this.couponCount; i++) {
WxPayOrderNotifyCoupon coupon = new WxPayOrderNotifyCoupon();
coupon.setCouponId(this.getXmlValue("xml/coupon_id_" + i));
coupon.setCouponType(this.getXmlValue("xml/coupon_type_" + i));
coupon.setCouponFee(this.getXmlValueAsInt("xml/coupon_fee_" + i));
couponList.add(coupon);
}
}
@Override
protected void loadXml(Document d) {
deviceInfo = readXmlString(d, "device_info");
openId = readXmlString(d, "openid");
isSubscribe = readXmlString(d, "is_subscribe");
bankType = readXmlString(d, "bank_type");
totalFee = readXmlInteger(d, "total_fee");
feeType = readXmlString(d, "fee_type");
cashFee = readXmlInteger(d, "cash_fee");
tradeType = readXmlString(d, "trade_type");
cashFeeType = readXmlString(d, "cash_fee_type");
couponFee = readXmlInteger(d, "coupon_fee");
couponCount = readXmlInteger(d, "coupon_count");
transactionId = readXmlString(d, "transaction_id");
outTradeNo = readXmlString(d, "out_trade_no");
attach = readXmlString(d, "attach");
timeEnd = readXmlString(d, "time_end");
tradeState = readXmlString(d, "trade_state");
tradeStateDesc = readXmlString(d, "trade_state_desc");
composeCoupons();
}
}

View File

@ -0,0 +1,44 @@
package com.github.binarywang.wxpay.bean.result;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import org.w3c.dom.Document;
import java.io.Serializable;
/**
* @author chenliang
* @date 2021-08-02 5:39 下午
*
* <pre>
* 委托扣款返回值
* </pre>
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WxWithholdResult extends BaseWxPayResult implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 临时字段
*/
@XStreamAlias("temp")
private String temp;
@Override
protected void loadXml(Document d) {
temp = readXmlString(d, "temp");
}
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
}

View File

@ -0,0 +1,157 @@
package com.github.binarywang.wxpay.service;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.exception.WxPayException;
/**
* <pre>
* 微信签约代扣相关接口.
* https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter2_8.shtml
* </pre>
*
* @author chenliang
* @date 2021-08-02 4:50 下午
*/
public interface WxEntrustPapService {
/**
*
* <pre>
* 获取公众号纯签约链接,
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_1.shtml
* 该接口返回一个签约链接该链接只能在微信内打开
* </pre>
*
* @param wxMpEntrustRequest
* @return
* @throws WxPayException
*/
String mpSign(WxMpEntrustRequest wxMpEntrustRequest) throws WxPayException;
/**
*
* <pre>
* 获取小程序纯签约参数json
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_3.shtml
* 返回一个json 前端用来拉起一个新的签约小程序进行签约
* </pre>
*
*
* @param wxMaEntrustRequest
* @return
* @throws WxPayException
*/
String maSign(WxMaEntrustRequest wxMaEntrustRequest) throws WxPayException;
/**
*
* <pre>
* 获取h5纯签约支付跳转链接
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_4.shtml
* 返回一个签约链接 在浏览器请求链接拉起微信
* </pre>
*
* @param wxH5EntrustRequest
* @return
* @throws WxPayException
*/
WxH5EntrustResult h5Sign(WxH5EntrustRequest wxH5EntrustRequest) throws WxPayException;
/**
*
* <pre>
* 支付中签约
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_5.shtml
* 请求微信 若微信内请求 需要构造json返回
* 若h5请求 直接使用mweb_url 链接即可拉起微信
* </pre>
*
* @param wxPayEntrustRequest
* @return
* @throws WxPayException
*/
WxPayEntrustResult paySign(WxPayEntrustRequest wxPayEntrustRequest) throws WxPayException;
/**
* 申请扣款
* <pre>
* 申请扣款
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_8.shtml
* 请求微信发起委托扣款扣款额度和次数由使用的签约模板限制
* 该扣款接口是立即扣款 无延时 扣款前无消息通知
*
* 特殊情况周期扣费为通知后24小时扣费方式情况下如果用户为首次签约包含解约后重新签约
* 从用户签约成功时间开始算商户在12小时内发起的扣款会被立即执行无延迟商户超过12小时以后发起的扣款都按24小时扣费规则执行
* </pre>
*
* @param wxWithholdRequest
* @return
* @throws WxPayException
*/
WxWithholdResult withhold(WxWithholdRequest wxWithholdRequest) throws WxPayException;
/**
* 预扣费通知
* <pre>
* 预扣费接口
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_10.shtml
* 商户进行委托代扣扣费前需要在可通知时间段内调用预扣费通知的接口为用户发送扣费提醒
* 并设定扣费持续天数和预计扣费金额经过扣费等待期后在可扣费期内可发起扣费扣款金额不能高于预计扣费金额
* 扣费失败可主动发起重试扣费重试次数由其他规则限制直到扣费成功或者可扣费期结束
* 商户只能在北京时间每天 6:0022:00调用预扣费通知
* </pre>
*
* @param wxPreWithholdRequest
* @return
* @throws WxPayException
*/
String preWithhold(WxPreWithholdRequest wxPreWithholdRequest) throws WxPayException;
/**
* 签约状态查询
* <pre>
* 签约状态查询
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_7.shtml
* 查询签约关系接口提供单笔签约关系查询
* </pre>
*
* @param wxSignQueryRequest
* @return
* @throws WxPayException
*/
WxSignQueryResult querySign(WxSignQueryRequest wxSignQueryRequest) throws WxPayException;
/**
* 申请解约
* <pre>
* 申请解约
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_9.shtml
* 商户与用户的签约关系有误或者商户主动要求与用户解除之前的签约协议时可调用此接口完成解约
* 商户可以在商户后台pay.weixin.qq.com设置解约回调地址当发生解约关系的时候微信服务器会向此地址通知解约信息内容与签约返回一致
* </pre>
*
* @param wxTerminatedContractRequest
* @return
* @throws WxPayException
*/
WxTerminationContractResult terminationContract(WxTerminatedContractRequest wxTerminatedContractRequest) throws WxPayException;
/**
*
* <pre>
* 查询代扣订单
* 详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter4_5.shtml
* 该接口仅提供微信扣款服务申请扣款接口创建的订单进行查询商户可以通过该接口主动查询微信代扣订单状态完成下一步的业务逻辑
* ACCEPT等待扣款为24小时延时扣费场景下独有的当没有达到24小时前一直是这种状态
* NOTPAY未支付系统已经启动扣款流程这个状态只是瞬间状态很快会进入终态SUCCESSPAY_FAIL
*
* </pre>
*
* @param wxWithholdOrderQueryRequest
* @return
* @throws WxPayException
*/
WxWithholdOrderQueryResult papOrderQuery(WxWithholdOrderQueryRequest wxWithholdOrderQueryRequest) throws WxPayException;
}

View File

@ -173,6 +173,12 @@ public interface WxPayService {
*/
InputStream downloadV3(String url) throws WxPayException;
/**
* 获取微信签约代扣服务类
* @return entrust service
*/
WxEntrustPapService getWxEntrustPapService();
/**
* 获取企业付款服务类.
*

View File

@ -74,6 +74,8 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
private final MarketingMediaService marketingMediaService = new MarketingMediaServiceImpl(this);
private final MarketingFavorService marketingFavorService = new MarketingFavorServiceImpl(this);
private final MarketingBusiFavorService marketingBusiFavorService = new MarketingBusiFavorServiceImpl(this);
private final WxEntrustPapService wxEntrustPapService = new WxEntrustPapServiceImpl(this);
protected Map<String, WxPayConfig> configMap;
@ -137,6 +139,11 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
this.entPayService = entPayService;
}
@Override
public WxEntrustPapService getWxEntrustPapService() {
return wxEntrustPapService;
}
@Override
public WxPayConfig getConfig() {
if (this.configMap.size() == 1) {

View File

@ -0,0 +1,139 @@
package com.github.binarywang.wxpay.service.impl;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxEntrustPapService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.util.SignUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import java.net.URLEncoder;
/**
* @author chenliang
* @date 2021-08-02 4:53 下午
*/
@Slf4j
@RequiredArgsConstructor
public class WxEntrustPapServiceImpl implements WxEntrustPapService {
private final WxPayService payService;
@Override
public String mpSign(WxMpEntrustRequest wxMpEntrustRequest) throws WxPayException {
StringBuilder signStrTemp = new StringBuilder(payService.getPayBaseUrl() + "/papay/entrustweb");
signStrTemp.append("?appid=").append(wxMpEntrustRequest.getAppid());
signStrTemp.append("&contract_code=").append(wxMpEntrustRequest.getContractCode());
signStrTemp.append("&contract_display_account=").append(URLEncoder.encode(wxMpEntrustRequest.getContractDisplayAccount()));
signStrTemp.append("&mch_id=").append(wxMpEntrustRequest.getMchId()).append("&notify_url=").append(URLEncoder.encode(wxMpEntrustRequest.getNotifyUrl()));
signStrTemp.append("&plan_id=").append(wxMpEntrustRequest.getPlanId()).append("&outerid=").append(URLEncoder.encode(wxMpEntrustRequest.getOuterId()));
signStrTemp.append("&request_serial=").append(wxMpEntrustRequest.getRequestSerial()).append("&timestamp=").append(wxMpEntrustRequest.getTimestamp());
signStrTemp.append("&version=").append(wxMpEntrustRequest.getVersion()).append("&return_web=").append(wxMpEntrustRequest.getReturnWeb()).append("&sign=").append(wxMpEntrustRequest.getSign());
return signStrTemp.toString();
}
@Override
public String maSign(WxMaEntrustRequest wxMaEntrustRequest) throws WxPayException {
wxMaEntrustRequest.checkAndSign(payService.getConfig());
wxMaEntrustRequest.setNotifyUrl(URLEncoder.encode(wxMaEntrustRequest.getNotifyUrl()));
return wxMaEntrustRequest.toString();
}
@Override
public WxH5EntrustResult h5Sign(WxH5EntrustRequest wxH5EntrustRequest) throws WxPayException {
wxH5EntrustRequest.checkAndSign(payService.getConfig());
String sign = SignUtils.createSign(wxH5EntrustRequest, WxPayConstants.SignType.HMAC_SHA256, payService.getConfig().getMchKey(), null);
/**
* https://api.mch.weixin.qq.com/papay/h5entrustweb?appid=wxxxxx&contract_code=001
* &contract_display_account=name1&mch_id=1223816102&notify_url=www.qq.com%2Ftest%2Fpapay&plan_id=106
* &request_serial=123&return_appid= wxcbda96de0b165542&clientip=12.1.1.12&timestamp=1414488825
* &version=1.0&sign= 130C7B07DD3B8074F7BF8BEF5C9A86487A1C57478F8C55587876B9C782F72036
*/
String url = payService.getPayBaseUrl() + "/papay/h5entrustweb";
StringBuilder strBuilder = new StringBuilder(url);
strBuilder.append("?appid=").append(wxH5EntrustRequest.getAppid());
strBuilder.append("&contract_code=").append(wxH5EntrustRequest.getContractCode());
strBuilder.append("&contract_display_account=").append(URLEncoder.encode(wxH5EntrustRequest.getContractDisplayAccount()));
strBuilder.append("&mch_id=").append(wxH5EntrustRequest.getMchId()).append("&notify_url=").append(URLEncoder.encode(wxH5EntrustRequest.getNotifyUrl()));
strBuilder.append("&plan_id=").append(wxH5EntrustRequest.getPlanId()).append("&outerid=").append(URLEncoder.encode(wxH5EntrustRequest.getOuterId()));
strBuilder.append("&return_appid=").append(wxH5EntrustRequest.getReturnAppid());
strBuilder.append("&clientip=").append(wxH5EntrustRequest.getClientIp());
strBuilder.append("&request_serial=").append(wxH5EntrustRequest.getRequestSerial()).append("&timestamp=").append(wxH5EntrustRequest.getTimestamp());
strBuilder.append("&version=").append(wxH5EntrustRequest.getVersion()).append("&sign=").append(sign);
log.debug("h5纯签约请求URL{}", strBuilder.toString());
String responseContent = payService.getV3(strBuilder.toString());
WxH5EntrustResult result = BaseWxPayResult.fromXML(responseContent, WxH5EntrustResult.class);
result.checkResult(payService, wxH5EntrustRequest.getSignType(), true);
return result;
}
@Override
public WxPayEntrustResult paySign(WxPayEntrustRequest wxPayEntrustRequest) throws WxPayException {
wxPayEntrustRequest.checkAndSign(payService.getConfig());
String url = payService.getPayBaseUrl() + "/pay/contractorder";
String responseContent = payService.post(url, wxPayEntrustRequest.toXML(), false);
WxPayEntrustResult result = BaseWxPayResult.fromXML(responseContent, WxPayEntrustResult.class);
result.checkResult(payService, wxPayEntrustRequest.getSignType(), true);
return result;
}
@Override
public WxWithholdResult withhold(WxWithholdRequest wxWithholdRequest) throws WxPayException {
wxWithholdRequest.checkAndSign(payService.getConfig());
String url = payService.getPayBaseUrl() + "/pay/pappayapply";
String responseContent = payService.post(url, wxWithholdRequest.toXML(), false);
WxWithholdResult result = BaseWxPayResult.fromXML(responseContent, WxWithholdResult.class);
result.checkResult(payService, wxWithholdRequest.getSignType(), true);
return result;
}
@Override
public String preWithhold(WxPreWithholdRequest wxPreWithholdRequest) throws WxPayException {
String requestParam = WxGsonBuilder.create().toJson(wxPreWithholdRequest);
String url = payService.getPayBaseUrl() + "/v3/papay/contracts/%s/notify"; // %s为{contract_id}
String httpResponse = payService.postV3(String.format(url, wxPreWithholdRequest.getContractId()), requestParam);
return httpResponse;
}
@Override
public WxSignQueryResult querySign(WxSignQueryRequest wxSignQueryRequest) throws WxPayException {
wxSignQueryRequest.checkAndSign(payService.getConfig());
String url = payService.getPayBaseUrl() + "/papay/querycontract";
String responseContent = payService.post(url, wxSignQueryRequest.toXML(), false);
WxSignQueryResult result = BaseWxPayResult.fromXML(responseContent, WxSignQueryResult.class);
result.checkResult(payService, wxSignQueryRequest.getSignType(), true);
return result;
}
@Override
public WxTerminationContractResult terminationContract(WxTerminatedContractRequest wxTerminatedContractRequest) throws WxPayException {
wxTerminatedContractRequest.checkAndSign(payService.getConfig());
String url = payService.getPayBaseUrl() + "/papay/deletecontract";
String responseContent = payService.post(url, wxTerminatedContractRequest.toXML(), false);
WxTerminationContractResult terminationContractResult = BaseWxPayResult.fromXML(responseContent, WxTerminationContractResult.class);
terminationContractResult.checkResult(payService, wxTerminatedContractRequest.getSignType(), true);
return terminationContractResult;
}
@Override
public WxWithholdOrderQueryResult papOrderQuery(WxWithholdOrderQueryRequest wxWithholdOrderQueryRequest) throws WxPayException {
wxWithholdOrderQueryRequest.checkAndSign(payService.getConfig());
String url = payService.getPayBaseUrl() + "/pay/paporderquery";
String responseContent = payService.post(url, wxWithholdOrderQueryRequest.toXML(), false);
WxWithholdOrderQueryResult wxWithholdOrderQueryResult = BaseWxPayResult.fromXML(responseContent, WxWithholdOrderQueryResult.class);
wxWithholdOrderQueryResult.checkResult(payService, wxWithholdOrderQueryRequest.getSignType(), true);
return wxWithholdOrderQueryResult;
}
}

View File

@ -0,0 +1,236 @@
package com.github.binarywang.wxpay.service.impl;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.testbase.ApiTestModule;
import com.google.common.base.Joiner;
import com.google.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
/**
* @author chenliang
* @date 2021-08-02 6:45 下午
*/
@Test
@Guice(modules = ApiTestModule.class)
public class WxEntrustPapServiceTest {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Inject
private WxPayService payService;
/**
* 公众号纯签约
*/
@Test
public void testMpSign() {
String contractCode = "222200002222";
String displayAccount = Joiner.on("").join("陈*", "(", "10000014", ")");
WxMpEntrustRequest wxMpEntrust = WxMpEntrustRequest.newBuilder()
.planId("142323") //模板ID跟微信申请
.contractCode(contractCode)
.contractDisplayAccount(displayAccount)
.notifyUrl("http://domain.com/api/wxpay/sign/callback.do")
.requestSerial(6L)
//.returnWeb(1)
.version("1.0")
.timestamp(String.valueOf(System.currentTimeMillis() / 1000))
.outerId(displayAccount)
.build();
String url = null;
try {
url = this.payService.getWxEntrustPapService().mpSign(wxMpEntrust);
} catch (WxPayException e) {
e.printStackTrace();
}
logger.info(url);
}
/**
* 小程序纯签约
*/
@Test
public void testMaSign() {
String contractCode = "222220000022222";
String displayAccount = Joiner.on("").join("陈*", "(", "10000001", ")");
WxMaEntrustRequest wxMaEntrustRequest = WxMaEntrustRequest.newBuilder()
.contractCode(contractCode)
.contractDisplayAccount(contractCode)
.notifyUrl("http://domain.com/api/wxpay/sign/callback.do")
.outerId(displayAccount)
.planId("141535")
.requestSerial(2L)
.timestamp(String.valueOf(System.currentTimeMillis() / 1000))
.build();
try {
String url = this.payService.getWxEntrustPapService().maSign(wxMaEntrustRequest);
logger.info(url);
} catch (WxPayException e) {
e.printStackTrace();
}
}
/**
* h5纯签约
*/
@Test
public void testH5Sign() {
String contractCode = "222111122222";
String displayAccount = Joiner.on("").join("陈*", "(", "100000000", ")");
WxH5EntrustRequest wxH5EntrustRequest = WxH5EntrustRequest.newBuilder()
.requestSerial(2L)
.clientIp("127.0.0.1")
.contractCode(contractCode)
.contractDisplayAccount(displayAccount)
.notifyUrl("http://domain.com/api/wxpay/sign/callback.do")
.planId("141535")
.returnAppid("1")
.timestamp(String.valueOf(System.currentTimeMillis() / 1000))
.version("1.0")
.outerId(displayAccount)
.build();
try {
WxH5EntrustResult wxH5EntrustResult = this.payService.getWxEntrustPapService().h5Sign(wxH5EntrustRequest);
logger.info(wxH5EntrustResult.toString());
} catch (WxPayException e) {
e.printStackTrace();
}
}
@Test
public void testPaySign() {
String contractCode = "2222211110000222";
String displayAccount = Joiner.on("").join("陈*", "(", "10000005", ")");
String outTradeNo = "11100111101";
WxPayEntrustRequest wxPayEntrustRequest = WxPayEntrustRequest.newBuilder()
.attach("local")
.body("产品名字")
.contractAppId(this.payService.getConfig().getAppId())
.contractCode(contractCode)
.contractDisplayAccount(displayAccount)
.contractMchId(this.payService.getConfig().getMchId())
//签约回调
.contractNotifyUrl("http://domain.com/api/wxpay/sign/callback.do")
.detail("产品是好")
.deviceInfo("oneplus 7 pro")
//.goodsTag()
//.limitPay()
//支付回调
.notifyUrl("http://domain.com/api/wxpay/pay/callback.do")
.openId("oIvLdt8Q-_aKy4Vo6f4YI6gsIhMc") //openId
.outTradeNo(outTradeNo)
.planId("141535")
//.productId()
.requestSerial(3L)
.spbillCreateIp("127.0.0.1")
//.timeExpire()
//.timeStart()
.totalFee(1)
.tradeType("MWEB")
.contractOuterId(displayAccount)
.build();
try {
WxPayEntrustResult wxPayEntrustResult = this.payService.getWxEntrustPapService().paySign(wxPayEntrustRequest);
logger.info(wxPayEntrustResult.toString());
} catch (WxPayException e) {
e.printStackTrace();
}
}
@Test
public void testWithhold() {
String outTradeNo = "101010101";
WxWithholdRequest withholdRequest = WxWithholdRequest.newBuilder()
.attach("local")
.body("产品名字")
.contractId("202011065409471222") // 微信返回的签约协议号
.detail("产品描述")
.feeType("CNY")
//.goodsTag()
.notifyUrl("http://domain.com/api/wxpay/withhold/callback.do")
.outTradeNo(outTradeNo)
.spbillCreateIp("127.0.0.1")
.totalFee(1)
.tradeType("PAP")
.build();
try {
WxWithholdResult wxWithholdResult = this.payService.getWxEntrustPapService().withhold(withholdRequest);
logger.info(wxWithholdResult.toString());
} catch (WxPayException e) {
e.printStackTrace();
}
}
@Test
public void testPreWithhold() {
WxPreWithholdRequest.EstimateAmount estimateAmount = new WxPreWithholdRequest.EstimateAmount();
estimateAmount.setAmount(1);
estimateAmount.setCurrency("CNY");
WxPreWithholdRequest wxPreWithholdRequest = WxPreWithholdRequest.newBuilder()
.appId("wx73dssxxxxxx")
.contractId("202010275173070001")
.estimateAmount(estimateAmount)
.mchId("1600010102")
.build();
try {
String httpResponseModel = this.payService.getWxEntrustPapService().preWithhold(wxPreWithholdRequest);
logger.info(httpResponseModel);
} catch (WxPayException e) {
e.printStackTrace();
}
}
@Test
public void testQuerySign() {
String outTradeNo = "1212121212";
WxSignQueryRequest wxSignQueryRequest = WxSignQueryRequest.newBuilder()
//.contractId("202010275173073211")
.contractCode(outTradeNo)
.planId(1432112)
.version("1.0")
.build();
try {
WxSignQueryResult wxSignQueryResult = this.payService.getWxEntrustPapService().querySign(wxSignQueryRequest);
logger.info(wxSignQueryResult.toString());
} catch (WxPayException e) {
logger.info("异常码:" + e.getErrCode());
logger.info("异常:" + e);
}
}
@Test
public void testTerminationContract() {
WxTerminatedContractRequest wxTerminatedContractRequest = WxTerminatedContractRequest.newBuilder()
.contractId("202010275173070231")
.contractTerminationRemark("测试解约")
.version("1.0")
.build();
try {
WxTerminationContractResult wxTerminationContractResult = this.payService.getWxEntrustPapService().terminationContract(wxTerminatedContractRequest);
logger.info(wxTerminationContractResult.toString());
} catch (WxPayException e) {
logger.error(e.getMessage());
}
}
}