Skip to content

Commit 372fa16

Browse files
egzosnegzosn
authored andcommitted
微信发红包接口实现
1 parent 81d2182 commit 372fa16

6 files changed

Lines changed: 322 additions & 56 deletions

File tree

pay-java-wx/src/main/java/com/egzosn/pay/wx/api/WxPayService.java

Lines changed: 83 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,22 @@
22

33
import com.alibaba.fastjson.JSONObject;
44
import com.egzosn.pay.common.api.BasePayService;
5-
import com.egzosn.pay.common.api.Callback;
65
import com.egzosn.pay.common.bean.*;
76
import com.egzosn.pay.common.bean.result.PayException;
87
import com.egzosn.pay.common.exception.PayErrorException;
98
import com.egzosn.pay.common.http.HttpConfigStorage;
109
import com.egzosn.pay.common.util.DateUtils;
1110
import com.egzosn.pay.common.util.Util;
11+
import com.egzosn.pay.common.util.XML;
1212
import com.egzosn.pay.common.util.sign.SignUtils;
1313
import com.egzosn.pay.common.util.sign.encrypt.RSA2;
1414
import com.egzosn.pay.common.util.str.StringUtils;
15-
import com.egzosn.pay.wx.bean.WxPayError;
16-
import com.egzosn.pay.wx.bean.WxPayMessage;
17-
import com.egzosn.pay.wx.bean.WxTransactionType;
18-
import com.egzosn.pay.common.util.XML;
19-
import com.egzosn.pay.wx.bean.WxTransferType;
15+
import com.egzosn.pay.wx.bean.*;
16+
2017
import java.io.IOException;
2118
import java.io.InputStream;
22-
import java.math.BigDecimal;
2319
import java.net.URLEncoder;
20+
import java.security.GeneralSecurityException;
2421
import java.util.*;
2522

2623
import static com.egzosn.pay.wx.api.WxConst.*;
@@ -31,13 +28,11 @@
3128
*
3229
* @author egan
3330
* <pre>
34-
* email egzosn@gmail.com
35-
* date 2016-5-18 14:09:01
36-
* </pre>
31+
* email egzosn@gmail.com
32+
* date 2016-5-18 14:09:01
33+
* </pre>
3734
*/
38-
public class WxPayService extends BasePayService<WxPayConfigStorage> {
39-
40-
35+
public class WxPayService extends BasePayService<WxPayConfigStorage> implements WxRedPackService {
4136

4237

4338
/**
@@ -96,14 +91,14 @@ public String getReqUrl(TransactionType transactionType) {
9691
public boolean verify(Map<String, Object> params) {
9792

9893
if (!(SUCCESS.equals(params.get(RETURN_CODE)) && SUCCESS.equals(params.get(RESULT_CODE)))) {
99-
if (LOG.isErrorEnabled()){
94+
if (LOG.isErrorEnabled()) {
10095
LOG.error(String.format("微信支付异常:return_code=%s,参数集=%s", params.get(RETURN_CODE), params));
10196
}
10297
return false;
10398
}
10499

105100
if (null == params.get(SIGN)) {
106-
if (LOG.isDebugEnabled()){
101+
if (LOG.isDebugEnabled()) {
107102
LOG.debug(String.format("微信支付异常:签名为空!%s=%s", OUT_TRADE_NO, params.get(OUT_TRADE_NO)));
108103
}
109104
return false;
@@ -482,25 +477,6 @@ public Map<String, Object> cancel(String transactionId, String outTradeNo) {
482477
return secondaryInterface(transactionId, outTradeNo, WxTransactionType.REVERSE);
483478
}
484479

485-
/**
486-
* 退款
487-
*
488-
* @param transactionId 微信订单号
489-
* @param outTradeNo 商户单号
490-
* @param refundAmount 退款金额
491-
* @param totalAmount 总金额
492-
* @return 返回支付方申请退款后的结果
493-
* @see #refund(RefundOrder, Callback)
494-
*/
495-
@Deprecated
496-
@Override
497-
public Map<String, Object> refund(String transactionId, String outTradeNo, BigDecimal refundAmount, BigDecimal totalAmount) {
498-
499-
return refund(new RefundOrder(transactionId, outTradeNo, refundAmount, totalAmount));
500-
}
501-
502-
503-
504480

505481
/**
506482
* 申请退款接口
@@ -529,18 +505,6 @@ public Map<String, Object> refund(RefundOrder refundOrder) {
529505
}
530506

531507

532-
/**
533-
* 查询退款
534-
*
535-
* @param transactionId 支付平台订单号
536-
* @param outTradeNo 商户单号
537-
* @return 返回支付方查询退款后的结果
538-
*/
539-
@Override
540-
public Map<String, Object> refundquery(String transactionId, String outTradeNo) {
541-
return secondaryInterface(transactionId, outTradeNo, WxTransactionType.REFUNDQUERY);
542-
}
543-
544508
/**
545509
* 查询退款
546510
*
@@ -633,13 +597,12 @@ public Map<String, Object> secondaryInterface(Object transactionIdOrBillDate, St
633597
* @param order 转账订单
634598
* <pre>
635599
*
636-
* 注意事项:
637-
* ◆ 当返回错误码为“SYSTEMERROR”时,请不要更换商户订单号,一定要使用原商户订单号重试,否则可能造成重复支付等资金风险。
638-
* ◆ XML具有可扩展性,因此返回参数可能会有新增,而且顺序可能不完全遵循此文档规范,如果在解析回包的时候发生错误,请商户务必不要换单重试,请商户联系客服确认付款情况。如果有新回包字段,会更新到此API文档中。
639-
* ◆ 因为错误代码字段err_code的值后续可能会增加,所以商户如果遇到回包返回新的错误码,请商户务必不要换单重试,请商户联系客服确认付款情况。如果有新的错误码,会更新到此API文档中。
640-
* ◆ 错误代码描述字段err_code_des只供人工定位问题时做参考,系统实现时请不要依赖这个字段来做自动化处理。
641-
*
642-
* </pre>
600+
* 注意事项:
601+
* ◆ 当返回错误码为“SYSTEMERROR”时,请不要更换商户订单号,一定要使用原商户订单号重试,否则可能造成重复支付等资金风险。
602+
* ◆ XML具有可扩展性,因此返回参数可能会有新增,而且顺序可能不完全遵循此文档规范,如果在解析回包的时候发生错误,请商户务必不要换单重试,请商户联系客服确认付款情况。如果有新回包字段,会更新到此API文档中。
603+
* ◆ 因为错误代码字段err_code的值后续可能会增加,所以商户如果遇到回包返回新的错误码,请商户务必不要换单重试,请商户联系客服确认付款情况。如果有新的错误码,会更新到此API文档中。
604+
* ◆ 错误代码描述字段err_code_des只供人工定位问题时做参考,系统实现时请不要依赖这个字段来做自动化处理。
605+
* </pre>
643606
* @return 对应的转账结果
644607
*/
645608
@Override
@@ -742,7 +705,7 @@ public Map<String, Object> transferQuery(String outNo, String wxTransferType) {
742705
public String keyPublic(String content) {
743706
try {
744707
return RSA2.encrypt(content, payConfigStorage.getKeyPublic(), CIPHER_ALGORITHM, payConfigStorage.getInputCharset());
745-
} catch (Exception e) {
708+
} catch (GeneralSecurityException | IOException e) {
746709
throw new PayErrorException(new WxPayError(FAILURE, e.getLocalizedMessage()));
747710
}
748711
}
@@ -757,4 +720,70 @@ public String keyPublic(String content) {
757720
public PayMessage createMessage(Map<String, Object> message) {
758721
return WxPayMessage.create(message);
759722
}
723+
724+
/**
725+
* 微信发红包
726+
*
727+
* @param redpackOrder 红包实体
728+
* @return 返回发红包实体后的结果
729+
* @author: faymanwang 1057438332@qq.com
730+
*/
731+
@Override
732+
public Map<String, Object> sendredpack(RedpackOrder redpackOrder) {
733+
Map<String, Object> parameters = new TreeMap<String, Object>();
734+
redPackParam(redpackOrder, parameters);
735+
if (WxSendredpackType.SENDGROUPREDPACK == redpackOrder.getTransferType()) {
736+
//现金红包,小程序红包默认传1.裂变红包取传入值,且需要大于3
737+
parameters.put("total_num", Math.max(redpackOrder.getTotalNum(), 3));
738+
parameters.put("amt_type", "ALL_RAND");
739+
} else if (WxSendredpackType.SENDMINIPROGRAMHB == redpackOrder.getTransferType()) {
740+
parameters.put("notify_way", "MINI_PROGRAM_JSAPI");
741+
}
742+
743+
parameters.put(SIGN, createSign(SignUtils.parameterText(parameters, "&", SIGN), payConfigStorage.getInputCharset()));
744+
return requestTemplate.postForObject(getReqUrl(redpackOrder.getTransferType()), XML.getMap2Xml(parameters), JSONObject.class);
745+
}
746+
747+
748+
/**
749+
* 查询红包记录
750+
* 用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包
751+
* 查询红包记录API只支持查询30天内的红包订单,30天之前的红包订单请登录商户平台查询。
752+
*
753+
* @param mchBillno 商户发放红包的商户订单号
754+
* @return 返回查询结果
755+
* @author: faymanwang 1057438332@qq.com
756+
*/
757+
@Override
758+
public Map<String, Object> gethbinfo(String mchBillno) {
759+
Map<String, Object> parameters = this.getPublicParameters();
760+
parameters.put("mch_billno", mchBillno);
761+
parameters.put("bill_type", "MCHT");
762+
parameters.put(SIGN, createSign(SignUtils.parameterText(parameters, "&", SIGN), payConfigStorage.getInputCharset()));
763+
return requestTemplate.postForObject(getReqUrl(WxSendredpackType.GETHBINFO), XML.getMap2Xml(parameters), JSONObject.class);
764+
}
765+
766+
/**
767+
* 微信红包构造参数方法
768+
*
769+
* @param redpackOrder 红包实体
770+
* @param parameters 接收参数
771+
*/
772+
private void redPackParam(RedpackOrder redpackOrder, Map<String, Object> parameters) {
773+
parameters.put(NONCE_STR, SignUtils.randomStr());
774+
parameters.put(MCH_ID, payConfigStorage.getPid());
775+
parameters.put("wxappid", payConfigStorage.getAppid());
776+
parameters.put("send_name", redpackOrder.getSendName());
777+
parameters.put("re_openid", redpackOrder.getReOpenid());
778+
parameters.put("mch_billno", redpackOrder.getMchBillno());
779+
parameters.put("total_amount", Util.conversionCentAmount(redpackOrder.getTotalAmount()));
780+
parameters.put("total_num", 1);
781+
parameters.put("wishing", redpackOrder.getWishing());
782+
parameters.put("client_ip", StringUtils.isNotEmpty(redpackOrder.getIp()) ? redpackOrder.getIp() : "192.168.0.1");
783+
parameters.put("act_name", redpackOrder.getActName());
784+
parameters.put("remark", redpackOrder.getRemark());
785+
if (StringUtils.isNotEmpty(redpackOrder.getSceneId())) {
786+
parameters.put("scene_id", redpackOrder.getSceneId());
787+
}
788+
}
760789
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.egzosn.pay.wx.api;
2+
3+
import com.egzosn.pay.wx.bean.RedpackOrder;
4+
5+
import java.util.Map;
6+
7+
/**
8+
* 微信红包服务
9+
* @author egan
10+
* <pre>
11+
* email egzosn@gmail.com
12+
* date 2020/5/17 22:24
13+
* </pre>
14+
*/
15+
public interface WxRedPackService {
16+
/**
17+
* 微信发红包
18+
*
19+
* @param redpackOrder 红包实体
20+
* @return 返回发红包实体后的结果
21+
*/
22+
Map<String, Object> sendredpack(RedpackOrder redpackOrder);
23+
24+
/**
25+
* 查询红包记录
26+
* 用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包
27+
* 查询红包记录API只支持查询30天内的红包订单,30天之前的红包订单请登录商户平台查询。
28+
*
29+
* @param mchBillno 商户发放红包的商户订单号
30+
* @return 返回查询结果
31+
*/
32+
Map<String, Object> gethbinfo(String mchBillno);
33+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package com.egzosn.pay.wx.bean;
2+
3+
import com.egzosn.pay.common.bean.TransferOrder;
4+
5+
import java.math.BigDecimal;
6+
7+
/**
8+
* @description: 发红包订单
9+
* @author: 保网 faymanwang 1057438332@qq.com
10+
* @time: 2020/5/15 12:40
11+
*/
12+
public class RedpackOrder extends TransferOrder {
13+
14+
15+
/**
16+
* 商户订单号(每个订单号必须唯一。取值范围:0~9,a~z,A~Z)
17+
* 接口根据商户订单号支持重入,如出现超时可再调用
18+
* @return 商户订单号
19+
*/
20+
public String getMchBillno() {
21+
return getOutNo();
22+
}
23+
24+
public void setMchBillno(String mchBillno) {
25+
setOutNo(mchBillno);
26+
}
27+
28+
/**
29+
* 商户名称:红包发送者名称
30+
* @return 红包发送者名称
31+
*/
32+
public String getSendName() {
33+
return getPayerName();
34+
}
35+
36+
public void setSendName(String sendName) {
37+
super.setPayerName(sendName);
38+
}
39+
40+
/**
41+
* 用户openid
42+
* @return 用户openid
43+
*/
44+
public String getReOpenid() {
45+
return getPayeeAccount();
46+
}
47+
48+
public void setReOpenid(String reOpenid) {
49+
super.setPayeeAccount(reOpenid);
50+
}
51+
52+
/**
53+
* 付款金额 每个红包金额必须在默认额度内(默认大于1元,小于200元,可在产品设置中自行申请调高额度)
54+
* @return 付款金额
55+
*/
56+
public BigDecimal getTotalAmount() {
57+
return getAmount();
58+
}
59+
60+
public void setTotalAmount(BigDecimal totalAmount) {
61+
super.setAmount(totalAmount);
62+
}
63+
/**
64+
* 红包发放总人数
65+
* 普通红包:1
66+
* 裂变:必须介于(包括)3到20之间
67+
*/
68+
public int getTotalNum() {
69+
Object totalNum = getAttr("total_num");
70+
return null == totalNum ? 1 : (Integer)totalNum;
71+
}
72+
73+
public void setTotalNum(int totalNum) {
74+
addAttr("total_num", totalNum);
75+
}
76+
/**
77+
* 红包祝福语
78+
*/
79+
public String getWishing() {
80+
return (String) getAttr("wishing");
81+
82+
}
83+
84+
public void setWishing(String wishing) {
85+
addAttr("wishing", wishing);
86+
}
87+
88+
89+
/**
90+
* 活动名称
91+
*/
92+
public String getActName() {
93+
return (String) getAttr("act_name");
94+
}
95+
96+
public void setActName(String actName) {
97+
addAttr("act_name", actName);
98+
}
99+
100+
public String getSceneId() {
101+
return (String) getAttr("scene_id");
102+
}
103+
/**
104+
* 发放红包使用场景,红包金额大于200或者小于1元时必传
105+
* PRODUCT_1:商品促销
106+
* PRODUCT_2:抽奖
107+
* PRODUCT_3:虚拟物品兑奖
108+
* PRODUCT_4:企业内部福利
109+
* PRODUCT_5:渠道分润
110+
* PRODUCT_6:保险回馈
111+
* PRODUCT_7:彩票派奖
112+
* PRODUCT_8:税务刮奖
113+
*/
114+
public void setSceneId(String sceneId) {
115+
addAttr("scene_id", sceneId);
116+
}
117+
118+
119+
public void setTransferType(WxSendredpackType transferType) {
120+
super.setTransferType(transferType);
121+
}
122+
}

0 commit comments

Comments
 (0)