#178 实现发送代金券接口

This commit is contained in:
Binary Wang 2017-07-15 17:13:00 +08:00 committed by Binary Wang
parent 2726325fad
commit 33d5f87229
6 changed files with 589 additions and 44 deletions

View File

@ -0,0 +1,311 @@
package com.github.binarywang.wxpay.bean.coupon;
import com.github.binarywang.wxpay.bean.request.WxPayBaseRequest;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import me.chanjar.weixin.common.annotation.Required;
/**
* <pre>
* 发送代金券请求对象类
* Created by Binary Wang on 2017-7-15.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@XStreamAlias("xml")
public class WxPayCouponSendRequest extends WxPayBaseRequest {
/**
* <pre>
* 字段名代金券批次id
* 变量名coupon_stock_id
* 是否必填
* 示例值1757
* 类型String
* 说明代金券批次id
* </pre>
*/
@Required
@XStreamAlias("coupon_stock_id")
private String couponStockId;
/**
* <pre>
* 字段名openid记录数
* 变量名openid_count
* 是否必填
* 示例值1
* 类型int
* 说明openid记录数目前支持num=1
* </pre>
*/
@Required
@XStreamAlias("openid_count")
private Integer openidCount;
/**
* <pre>
* 字段名商户单据号
* 变量名partner_trade_no
* 是否必填
* 示例值1000009820141203515766
* 类型String
* 说明商户此次发放凭据号格式商户id+日期+流水号商户侧需保持唯一性
* </pre>
*/
@Required
@XStreamAlias("partner_trade_no")
private String partnerTradeNo;
/**
* <pre>
* 字段名用户openid
* 变量名openid
* 是否必填
* 示例值onqOjjrXT-776SpHnfexGm1_P7iE
* 类型String
* 说明Openid信息用户在appid下的openid
* </pre>
*/
@Required
@XStreamAlias("openid")
private String openid;
/**
* <pre>
* 字段名操作员
* 变量名op_user_id
* 是否必填
* 示例值10000098
* 类型String(32)
* 说明操作员帐号, 默认为商户号,可在商户平台配置操作员对应的api权限
* </pre>
*/
@XStreamAlias("op_user_id")
private String opUserId;
/**
* <pre>
* 字段名设备号
* 变量名device_info
* 是否必填
* 示例值
* 类型String(32)
* 说明微信支付分配的终端设备号
* </pre>
*/
@XStreamAlias("device_info")
private String deviceInfo;
/**
* <pre>
* 字段名协议版本
* 变量名version
* 是否必填
* 示例值1.0
* 类型String(32)
* 说明默认1.0
* </pre>
*/
@XStreamAlias("version")
private String version;
/**
* <pre>
* 字段名协议类型
* 变量名type
* 是否必填
* 示例值XML
* 类型String(32)
* 说明XML目前仅支持默认XML
* </pre>
*/
@XStreamAlias("type")
private String type;
public WxPayCouponSendRequest() {
}
private WxPayCouponSendRequest(Builder builder) {
setAppid(builder.appid);
setMchId(builder.mchId);
setSubAppId(builder.subAppId);
setSubMchId(builder.subMchId);
setNonceStr(builder.nonceStr);
setSign(builder.sign);
setCouponStockId(builder.couponStockId);
setOpenidCount(builder.openidCount);
setPartnerTradeNo(builder.partnerTradeNo);
setOpenid(builder.openid);
setOpUserId(builder.opUserId);
setDeviceInfo(builder.deviceInfo);
setVersion(builder.version);
setType(builder.type);
}
public static Builder newBuilder() {
return new Builder();
}
public String getCouponStockId() {
return this.couponStockId;
}
public void setCouponStockId(String couponStockId) {
this.couponStockId = couponStockId;
}
public Integer getOpenidCount() {
return this.openidCount;
}
public void setOpenidCount(Integer openidCount) {
this.openidCount = openidCount;
}
public String getPartnerTradeNo() {
return this.partnerTradeNo;
}
public void setPartnerTradeNo(String partnerTradeNo) {
this.partnerTradeNo = partnerTradeNo;
}
public String getOpenid() {
return this.openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getOpUserId() {
return this.opUserId;
}
public void setOpUserId(String opUserId) {
this.opUserId = opUserId;
}
public String getDeviceInfo() {
return this.deviceInfo;
}
public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}
public String getVersion() {
return this.version;
}
public void setVersion(String version) {
this.version = version;
}
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
@Override
protected void checkConstraints() {
//do nothing
}
public static final class Builder {
private String appid;
private String mchId;
private String subAppId;
private String subMchId;
private String nonceStr;
private String sign;
private String couponStockId;
private Integer openidCount;
private String partnerTradeNo;
private String openid;
private String opUserId;
private String deviceInfo;
private String version;
private String type;
private Builder() {
}
public Builder appid(String appid) {
this.appid = appid;
return this;
}
public Builder mchId(String mchId) {
this.mchId = mchId;
return this;
}
public Builder subAppId(String subAppId) {
this.subAppId = subAppId;
return this;
}
public Builder subMchId(String subMchId) {
this.subMchId = subMchId;
return this;
}
public Builder nonceStr(String nonceStr) {
this.nonceStr = nonceStr;
return this;
}
public Builder sign(String sign) {
this.sign = sign;
return this;
}
public Builder couponStockId(String couponStockId) {
this.couponStockId = couponStockId;
return this;
}
public Builder openidCount(Integer openidCount) {
this.openidCount = openidCount;
return this;
}
public Builder partnerTradeNo(String partnerTradeNo) {
this.partnerTradeNo = partnerTradeNo;
return this;
}
public Builder openid(String openid) {
this.openid = openid;
return this;
}
public Builder opUserId(String opUserId) {
this.opUserId = opUserId;
return this;
}
public Builder deviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
return this;
}
public Builder version(String version) {
this.version = version;
return this;
}
public Builder type(String type) {
this.type = type;
return this;
}
public WxPayCouponSendRequest build() {
return new WxPayCouponSendRequest(this);
}
}
}

View File

@ -0,0 +1,204 @@
package com.github.binarywang.wxpay.bean.coupon;
import com.github.binarywang.wxpay.bean.result.WxPayBaseResult;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* <pre>
* 发送代金券响应结果类
* Created by Binary Wang on 2017-7-15.
* </pre>
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
@XStreamAlias("xml")
public class WxPayCouponSendResult extends WxPayBaseResult {
/**
* <pre>
* 字段名设备号
* 变量名device_info
* 是否必填
* 示例值123456sb
* 类型String(32)
* 描述微信支付分配的终端设备号
* </pre>
*/
@XStreamAlias("device_info")
private String deviceInfo;
/**
* <pre>
* 字段名代金券批次id
* 变量名coupon_stock_id
* 是否必填
* 示例值1757
* 类型String
* 描述用户在商户appid下的唯一标识
* </pre>
*/
@XStreamAlias("coupon_stock_id")
private String couponStockId;
/**
* <pre>
* 字段名返回记录数
* 变量名resp_count
* 是否必填
* 示例值1
* 类型Int
* 描述返回记录数
* </pre>
*/
@XStreamAlias("resp_count")
private Integer respCount;
/**
* <pre>
* 字段名成功记录数
* 变量名success_count
* 是否必填
* 示例值1或者0
* 类型Int
* 描述成功记录数
* </pre>
*/
@XStreamAlias("success_count")
private Integer successCount;
/**
* <pre>
* 字段名失败记录数
* 变量名failed_count
* 是否必填
* 示例值1或者0
* 类型Int
* 描述失败记录数
* </pre>
*/
@XStreamAlias("failed_count")
private Integer failedCount;
/**
* <pre>
* 字段名用户标识
* 变量名openid
* 是否必填
* 示例值onqOjjrXT-776SpHnfexGm1_P7iE
* 类型String
* 描述用户在商户appid下的唯一标识
* </pre>
*/
@XStreamAlias("openid")
private String openid;
/**
* <pre>
* 字段名返回码
* 变量名ret_code
* 是否必填
* 示例值SUCCESS或者FAILED
* 类型String
* 描述返回码SUCCESS/FAILED
* </pre>
*/
@XStreamAlias("ret_code")
private String retCode;
/**
* <pre>
* 字段名代金券id
* 变量名coupon_id
* 是否必填
* 示例值1870
* 类型String
* 描述对一个用户成功发放代金券则返回代金券id即ret_code为SUCCESS的时候如果ret_code为FAILED则填写空串""
* </pre>
*/
@XStreamAlias("coupon_id")
private String couponId;
/**
* <pre>
* 字段名返回信息
* 变量名ret_msg
* 是否必填
* 示例值失败描述信息例如用户已达领用上限
* 类型String
* 描述返回信息当返回码是FAILED的时候填写否则填空串
* </pre>
*/
@XStreamAlias("ret_msg")
private String retMsg;
public String getDeviceInfo() {
return this.deviceInfo;
}
public void setDeviceInfo(String deviceInfo) {
this.deviceInfo = deviceInfo;
}
public String getCouponStockId() {
return this.couponStockId;
}
public void setCouponStockId(String couponStockId) {
this.couponStockId = couponStockId;
}
public Integer getRespCount() {
return this.respCount;
}
public void setRespCount(Integer respCount) {
this.respCount = respCount;
}
public Integer getSuccessCount() {
return this.successCount;
}
public void setSuccessCount(Integer successCount) {
this.successCount = successCount;
}
public Integer getFailedCount() {
return this.failedCount;
}
public void setFailedCount(Integer failedCount) {
this.failedCount = failedCount;
}
public String getOpenid() {
return this.openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getRetCode() {
return this.retCode;
}
public void setRetCode(String retCode) {
this.retCode = retCode;
}
public String getCouponId() {
return this.couponId;
}
public void setCouponId(String couponId) {
this.couponId = couponId;
}
public String getRetMsg() {
return this.retMsg;
}
public void setRetMsg(String retMsg) {
this.retMsg = retMsg;
}
}

View File

@ -17,13 +17,6 @@ import java.math.BigDecimal;
* <pre>
* Created by Binary Wang on 2016-10-24.
* 微信支付请求对象共用的参数存放类
* 注释中各行每个字段描述对应如下
* <li>字段名
* <li>变量名
* <li>是否必填
* <li>类型
* <li>示例值
* <li>描述
* </pre>
*
* @author <a href="https://github.com/binarywang">binarywang(Binary Wang)</a>
@ -31,72 +24,72 @@ import java.math.BigDecimal;
public abstract class WxPayBaseRequest {
/**
* <pre>
* 公众账号ID
* appid
*
* String(32)
* wxd678efh567hg6787
* 微信分配的公众账号ID企业号corpid即为此appId
* 字段名公众账号ID
* 变量名appid
* 否必填
* 类型String(32)
* 示例值wxd678efh567hg6787
* 描述微信分配的公众账号ID企业号corpid即为此appId
* </pre>
*/
@XStreamAlias("appid")
protected String appid;
/**
* <pre>
* 商户号
* mch_id
*
* String(32)
* 1230000109
* 微信支付分配的商户号
* 字段名商户号
* 变量名mch_id
* 否必填
* 类型String(32)
* 示例值1230000109
* 描述微信支付分配的商户号
* </pre>
*/
@XStreamAlias("mch_id")
protected String mchId;
/**
* <pre>
* 服务商模式下的子商户公众账号ID
* sub_appid
*
* String(32)
* wxd678efh567hg6787
* 微信分配的子商户公众账号ID
* 字段名服务商模式下的子商户公众账号ID
* 变量名sub_appid
* 否必填
* 类型String(32)
* 示例值wxd678efh567hg6787
* 描述微信分配的子商户公众账号ID
* </pre>
*/
@XStreamAlias("sub_appid")
protected String subAppId;
/**
* <pre>
* 服务商模式下的子商户号
* sub_mch_id
*
* String(32)
* 1230000109
* 微信支付分配的子商户号开发者模式下必填
* 字段名服务商模式下的子商户号
* 变量名sub_mch_id
* 否必填
* 类型String(32)
* 示例值1230000109
* 描述微信支付分配的子商户号开发者模式下必填
* </pre>
*/
@XStreamAlias("sub_mch_id")
protected String subMchId;
/**
* <pre>
* 随机字符串
* nonce_str
*
* String(32)
* 5K8264ILTKCH16CQ2502SI8ZNMTM67VS
* 随机字符串不长于32位推荐随机数生成算法
* 字段名随机字符串
* 变量名nonce_str
* 否必填
* 类型String(32)
* 示例值5K8264ILTKCH16CQ2502SI8ZNMTM67VS
* 描述随机字符串不长于32位推荐随机数生成算法
* </pre>
*/
@XStreamAlias("nonce_str")
protected String nonceStr;
/**
* <pre>
* 签名
* sign
*
* String(32)
* C380BEC2BFD727A4B6845133519F3AD6
* 签名详见签名生成算法
* 字段名签名
* 变量名sign
* 否必填
* 类型String(32)
* 示例值C380BEC2BFD727A4B6845133519F3AD6
* 描述签名详见签名生成算法
* </pre>
*/
@XStreamAlias("sign")

View File

@ -1,5 +1,7 @@
package com.github.binarywang.wxpay.service;
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest;
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.config.WxPayConfig;
@ -339,4 +341,14 @@ public interface WxPayService {
* </pre>
*/
String getSandboxSignKey() throws WxPayException;
/**
* <pre>
* 发放代金券
* 接口请求链接https://api.mch.weixin.qq.com/mmpaymkttransfers/send_coupon
* 是否需要证书请求需要双向证书
* 文档地址https://pay.weixin.qq.com/wiki/doc/api/tools/sp_coupon.php?chapter=12_3
* </pre>
*/
WxPayCouponSendResult sendCoupon(WxPayCouponSendRequest request) throws WxPayException;
}

View File

@ -1,6 +1,8 @@
package com.github.binarywang.wxpay.service.impl;
import com.github.binarywang.utils.qrcode.QrcodeUtils;
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest;
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.config.WxPayConfig;
@ -463,4 +465,15 @@ public abstract class WxPayServiceAbstractImpl implements WxPayService {
result.checkResult(this);
return result.getSandboxSignKey();
}
@Override
public WxPayCouponSendResult sendCoupon(WxPayCouponSendRequest request) throws WxPayException {
request.checkAndSign(this.getConfig());
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/send_coupon";
String responseContent = this.post(url, request.toXML(), true);
WxPayCouponSendResult result = WxPayBaseResult.fromXML(responseContent, WxPayCouponSendResult.class);
result.checkResult(this);
return result;
}
}

View File

@ -1,6 +1,8 @@
package com.github.binarywang.wxpay.service.impl;
import com.github.binarywang.utils.qrcode.QrcodeUtils;
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendRequest;
import com.github.binarywang.wxpay.bean.coupon.WxPayCouponSendResult;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.exception.WxPayException;
@ -26,7 +28,7 @@ import static org.testng.Assert.*;
*/
@Test
@Guice(modules = ApiTestModule.class)
public class WxPayServiceImplTest {
public class WxPayServiceAbstractImplTest {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Inject
@ -271,4 +273,14 @@ public class WxPayServiceImplTest {
this.logger.info(signKey);
}
@Test
public void testSendCoupon() throws Exception {
WxPayCouponSendResult result = this.payService.sendCoupon(WxPayCouponSendRequest.newBuilder()
.couponStockId("123")
.openid("122")
.partnerTradeNo("1212")
.openidCount(1)
.build());
this.logger.info(result.toString());
}
}