| @@ -0,0 +1,33 @@ | |||||
| package com.github.binarywang.wxpay.bean.profitsharing; | |||||
| import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; | |||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||||
| import lombok.Data; | |||||
| import lombok.EqualsAndHashCode; | |||||
| import lombok.NoArgsConstructor; | |||||
| /** | |||||
| * @author Wang GuangXin 2019/10/22 10:06 | |||||
| * @version 1.0 | |||||
| */ | |||||
| @Data | |||||
| @EqualsAndHashCode(callSuper = true) | |||||
| @NoArgsConstructor | |||||
| @XStreamAlias("xml") | |||||
| public class ProfitSharingResult extends BaseWxPayResult { | |||||
| /** | |||||
| * 微信订单号. | |||||
| */ | |||||
| @XStreamAlias("transaction_id") | |||||
| private String transactionId; | |||||
| /** | |||||
| * 商户分账单号. | |||||
| */ | |||||
| @XStreamAlias("out_order_no") | |||||
| private String outOrderNo; | |||||
| /** | |||||
| * 微信分账单号. | |||||
| */ | |||||
| @XStreamAlias("order_id") | |||||
| private String orderId; | |||||
| } | |||||
| @@ -0,0 +1,86 @@ | |||||
| package com.github.binarywang.wxpay.bean.profitsharing; | |||||
| import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest; | |||||
| import com.github.binarywang.wxpay.constant.WxPayConstants; | |||||
| import com.github.binarywang.wxpay.exception.WxPayException; | |||||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||||
| import lombok.*; | |||||
| import me.chanjar.weixin.common.annotation.Required; | |||||
| /** | |||||
| * @author Wang GuangXin 2019/10/21 17:57 | |||||
| * @version 1.0 | |||||
| */ | |||||
| @Data | |||||
| @EqualsAndHashCode(callSuper = true) | |||||
| @Builder(builderMethodName = "newBuilder") | |||||
| @NoArgsConstructor | |||||
| @AllArgsConstructor | |||||
| @XStreamAlias("xml") | |||||
| public class ProfitsharingRequest extends BaseWxPayRequest { | |||||
| private static final long serialVersionUID = 212049937430575842L; | |||||
| /** | |||||
| * <pre> | |||||
| * 字段名:微信订单号. | |||||
| * 变量名:transaction_id | |||||
| * 是否必填:是 | |||||
| * String(32) | |||||
| * 示例值:4208450740201411110007820472 | |||||
| * 描述:微信支付订单号 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("transaction_id") | |||||
| @Required | |||||
| private String transactionId; | |||||
| /** | |||||
| * <pre> | |||||
| * 字段名:商户分账单号. | |||||
| * 变量名:out_order_no | |||||
| * 是否必填:是 | |||||
| * String(64) | |||||
| * 示例值:P20150806125346 | |||||
| * 描述:商户系统内部的分账单号,在商户系统内部唯一(单次分账、多次分账、完结分账应使用不同的商户分账单号),同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@ | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("out_order_no") | |||||
| @Required | |||||
| private String outOrderNo; | |||||
| /** | |||||
| * <pre> | |||||
| * 字段名:分账接收方列表. | |||||
| * 变量名:receivers | |||||
| * 是否必填:是 | |||||
| * String(10240) | |||||
| * 示例值:[ | |||||
| * { | |||||
| * "type": "MERCHANT_ID", | |||||
| * "account":"190001001", | |||||
| * "amount":100, | |||||
| * "description": "分到商户" | |||||
| * }, | |||||
| * { | |||||
| * "type": "PERSONAL_WECHATID", | |||||
| * "account":"86693952", | |||||
| * "amount":888, | |||||
| * "description": "分到个人" | |||||
| * } | |||||
| * ] | |||||
| * 描述:分账接收方列表,不超过50个json对象,不能设置分账方作为分账接受方,使用Json格式 | |||||
| * </pre> | |||||
| */ | |||||
| @XStreamAlias("receivers") | |||||
| @Required | |||||
| private String receivers; | |||||
| @Override | |||||
| protected void checkConstraints() throws WxPayException { | |||||
| /** | |||||
| * 目前仅支持HMAC-SHA256 | |||||
| */ | |||||
| this.setSignType(WxPayConstants.SignType.HMAC_SHA256); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,47 @@ | |||||
| package com.github.binarywang.wxpay.bean.profitsharing; | |||||
| import java.io.Serializable; | |||||
| /** | |||||
| * @author Wang GuangXin 2019/10/22 11:07 | |||||
| * @version 1.0 | |||||
| */ | |||||
| public class Receiver implements Serializable { | |||||
| private String type; | |||||
| private String account; | |||||
| private Integer amount; | |||||
| private String description; | |||||
| /** | |||||
| * @param type MERCHANT_ID:商户ID | |||||
| * PERSONAL_WECHATID:个人微信号PERSONAL_OPENID:个人openid(由父商户APPID转换得到)PERSONAL_SUB_OPENID: 个人sub_openid(由子商户APPID转换得到) | |||||
| * @param account 类型是MERCHANT_ID时,是商户ID | |||||
| * 类型是PERSONAL_WECHATID时,是个人微信号 | |||||
| * 类型是PERSONAL_OPENID时,是个人openid | |||||
| * 类型是PERSONAL_SUB_OPENID时,是个人sub_openid | |||||
| * @param amount 分账金额,单位为分,只能为整数,不能超过原订单支付金额及最大分账比例金额 | |||||
| * @param description 分账的原因描述,分账账单中需要体现 | |||||
| */ | |||||
| public Receiver(String type, String account, Integer amount, String description) { | |||||
| this.type = type; | |||||
| this.account = account; | |||||
| this.amount = amount; | |||||
| this.description = description; | |||||
| } | |||||
| public String getType() { | |||||
| return type; | |||||
| } | |||||
| public String getAccount() { | |||||
| return account; | |||||
| } | |||||
| public Integer getAmount() { | |||||
| return amount; | |||||
| } | |||||
| public String getDescription() { | |||||
| return description; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,51 @@ | |||||
| package com.github.binarywang.wxpay.bean.profitsharing; | |||||
| import com.google.gson.Gson; | |||||
| import java.io.Serializable; | |||||
| import java.util.ArrayList; | |||||
| /** | |||||
| * @author Wang GuangXin 2019/10/22 11:01 | |||||
| * @version 1.0 | |||||
| */ | |||||
| public class ReceiverList implements Serializable { | |||||
| private static final long serialVersionUID = -1316860887694489921L; | |||||
| ArrayList list; | |||||
| private ReceiverList() { | |||||
| } | |||||
| /** | |||||
| * 获取一个实例 | |||||
| * @return | |||||
| */ | |||||
| public static ReceiverList getInstance() { | |||||
| ReceiverList receiverList = new ReceiverList(); | |||||
| receiverList.list = new ArrayList(); | |||||
| return receiverList; | |||||
| } | |||||
| /** | |||||
| * 添加一个分账条目 | |||||
| * 注意微信上限为50个 | |||||
| * @param receiver | |||||
| * @return | |||||
| */ | |||||
| public ReceiverList add(Receiver receiver) { | |||||
| this.list.add(receiver); | |||||
| return this; | |||||
| } | |||||
| /** | |||||
| * 转为JSON格式 | |||||
| * @return | |||||
| */ | |||||
| public String toJSONString() { | |||||
| Gson gson = new Gson(); | |||||
| return gson.toJson(this.list); | |||||
| } | |||||
| } | |||||
| @@ -1,11 +1,10 @@ | |||||
| package com.github.binarywang.wxpay.constant; | package com.github.binarywang.wxpay.constant; | ||||
| import java.text.Format; | |||||
| import java.util.List; | |||||
| import com.google.common.collect.Lists; | |||||
| import org.apache.commons.lang3.time.FastDateFormat; | import org.apache.commons.lang3.time.FastDateFormat; | ||||
| import com.google.common.collect.Lists; | |||||
| import java.text.Format; | |||||
| import java.util.List; | |||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| @@ -273,4 +272,23 @@ public class WxPayConstants { | |||||
| */ | */ | ||||
| public static final String CHANGE = "CHANGE"; | public static final String CHANGE = "CHANGE"; | ||||
| } | } | ||||
| public static class ReceiverType { | |||||
| /** | |||||
| * 商户id | |||||
| */ | |||||
| public static final String MERCHANT_ID = "MERCHANT_ID"; | |||||
| /** | |||||
| * 个人微信号 | |||||
| */ | |||||
| public static final String PERSONAL_WECHATID = "PERSONAL_WECHATID"; | |||||
| /** | |||||
| * 个人openid | |||||
| */ | |||||
| public static final String PERSONAL_OPENID = "PERSONAL_OPENID"; | |||||
| /** | |||||
| * 个人sub_openid | |||||
| */ | |||||
| public static final String PERSONAL_SUB_OPENID = "PERSONAL_SUB_OPENID"; | |||||
| } | |||||
| } | } | ||||
| @@ -0,0 +1,26 @@ | |||||
| package com.github.binarywang.wxpay.service; | |||||
| import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingResult; | |||||
| import com.github.binarywang.wxpay.bean.profitsharing.ProfitsharingRequest; | |||||
| import com.github.binarywang.wxpay.exception.WxPayException; | |||||
| /** | |||||
| * @author Wang GuangXin 2019/10/22 10:05 | |||||
| * @version 1.0 | |||||
| */ | |||||
| public interface ProfitSharingService { | |||||
| /** | |||||
| * 单次分账请求按照传入的分账接收方账号和资金进行分账,同时会将订单剩余的待分账金额解冻给特约商户。故操作成功后,订单不能再进行分账,也不能进行分账完结。 | |||||
| * <p> | |||||
| * 接口频率:30QPS | |||||
| * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/allocation_sl.php?chapter=25_1&index=1 | |||||
| * 接口链接:https://api.mch.weixin.qq.com/secapi/pay/profitsharing | |||||
| * | |||||
| * @param profitsharingRequest | |||||
| * @return | |||||
| * @throws WxPayException the wx pay exception | |||||
| */ | |||||
| ProfitSharingResult profitsharing(ProfitsharingRequest profitsharingRequest) throws WxPayException; | |||||
| ; | |||||
| } | |||||
| @@ -65,6 +65,13 @@ public interface WxPayService { | |||||
| */ | */ | ||||
| EntPayService getEntPayService(); | EntPayService getEntPayService(); | ||||
| /** | |||||
| * 获取分账服务类. | |||||
| * | |||||
| * @return the ent pay service | |||||
| */ | |||||
| ProfitSharingService getProfitSharingService(); | |||||
| /** | /** | ||||
| * 设置企业付款服务类,允许开发者自定义实现类. | * 设置企业付款服务类,允许开发者自定义实现类. | ||||
| * | * | ||||
| @@ -304,6 +311,7 @@ public interface WxPayService { | |||||
| * @throws WxPayException the wx pay exception | * @throws WxPayException the wx pay exception | ||||
| */ | */ | ||||
| WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException; | WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException; | ||||
| /** | /** | ||||
| * <pre> | * <pre> | ||||
| * 查询红包记录. | * 查询红包记录. | ||||
| @@ -18,6 +18,7 @@ import com.github.binarywang.wxpay.constant.WxPayConstants.SignType; | |||||
| import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType; | import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType; | ||||
| import com.github.binarywang.wxpay.exception.WxPayException; | import com.github.binarywang.wxpay.exception.WxPayException; | ||||
| import com.github.binarywang.wxpay.service.EntPayService; | import com.github.binarywang.wxpay.service.EntPayService; | ||||
| import com.github.binarywang.wxpay.service.ProfitSharingService; | |||||
| import com.github.binarywang.wxpay.service.WxPayService; | import com.github.binarywang.wxpay.service.WxPayService; | ||||
| import com.github.binarywang.wxpay.util.SignUtils; | import com.github.binarywang.wxpay.util.SignUtils; | ||||
| import com.google.common.base.Joiner; | import com.google.common.base.Joiner; | ||||
| @@ -59,7 +60,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { | |||||
| static ThreadLocal<WxPayApiData> wxApiData = new ThreadLocal<>(); | static ThreadLocal<WxPayApiData> wxApiData = new ThreadLocal<>(); | ||||
| private EntPayService entPayService = new EntPayServiceImpl(this); | private EntPayService entPayService = new EntPayServiceImpl(this); | ||||
| private ProfitSharingService profitSharingService = new ProfitSharingServiceImpl(this); | |||||
| /** | /** | ||||
| * The Config. | * The Config. | ||||
| */ | */ | ||||
| @@ -70,6 +71,11 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { | |||||
| return entPayService; | return entPayService; | ||||
| } | } | ||||
| @Override | |||||
| public ProfitSharingService getProfitSharingService() { | |||||
| return profitSharingService; | |||||
| } | |||||
| @Override | @Override | ||||
| public void setEntPayService(EntPayService entPayService) { | public void setEntPayService(EntPayService entPayService) { | ||||
| this.entPayService = entPayService; | this.entPayService = entPayService; | ||||
| @@ -0,0 +1,31 @@ | |||||
| package com.github.binarywang.wxpay.service.impl; | |||||
| import com.github.binarywang.wxpay.bean.entpay.EntPayResult; | |||||
| import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingResult; | |||||
| import com.github.binarywang.wxpay.bean.profitsharing.ProfitsharingRequest; | |||||
| import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; | |||||
| import com.github.binarywang.wxpay.exception.WxPayException; | |||||
| import com.github.binarywang.wxpay.service.ProfitSharingService; | |||||
| import com.github.binarywang.wxpay.service.WxPayService; | |||||
| /** | |||||
| * @author Wang GuangXin 2019/10/22 10:13 | |||||
| * @version 1.0 | |||||
| */ | |||||
| public class ProfitSharingServiceImpl implements ProfitSharingService { | |||||
| private WxPayService payService; | |||||
| public ProfitSharingServiceImpl(WxPayService payService) { | |||||
| this.payService = payService; | |||||
| } | |||||
| @Override | |||||
| public ProfitSharingResult profitsharing(ProfitsharingRequest request) throws WxPayException { | |||||
| request.checkAndSign(this.payService.getConfig()); | |||||
| String url = this.payService.getPayBaseUrl() + "/secapi/pay/profitsharing"; | |||||
| String responseContent = this.payService.post(url, request.toXML(), true); | |||||
| ProfitSharingResult result = BaseWxPayResult.fromXML(responseContent, ProfitSharingResult.class); | |||||
| result.checkResult(this.payService, request.getSignType(), true); | |||||
| return result; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,40 @@ | |||||
| package com.github.binarywang.wxpay.service.impl; | |||||
| import com.github.binarywang.wxpay.bean.profitsharing.ProfitsharingRequest; | |||||
| import com.github.binarywang.wxpay.bean.profitsharing.Receiver; | |||||
| import com.github.binarywang.wxpay.bean.profitsharing.ReceiverList; | |||||
| 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.testbase.ApiTestModule; | |||||
| import com.google.inject.Inject; | |||||
| import org.slf4j.Logger; | |||||
| import org.slf4j.LoggerFactory; | |||||
| import org.testng.annotations.Guice; | |||||
| import org.testng.annotations.Test; | |||||
| @Test | |||||
| @Guice(modules = ApiTestModule.class) | |||||
| public class ProfitSharingServiceImplTest { | |||||
| private final Logger logger = LoggerFactory.getLogger(this.getClass()); | |||||
| @Inject | |||||
| private WxPayService payService; | |||||
| @Test | |||||
| public void testProfitsharing() throws WxPayException { | |||||
| ReceiverList instance = ReceiverList.getInstance(); | |||||
| instance.add(new Receiver(WxPayConstants.ReceiverType.PERSONAL_OPENID, | |||||
| "oyOUE5ql4TtzrBg5cVOwxq6tbjOs", | |||||
| 100, | |||||
| "分到用户")); | |||||
| ProfitsharingRequest request = ProfitsharingRequest | |||||
| .newBuilder() | |||||
| .outOrderNo("P20150806125346") | |||||
| .transactionId("4208450740201411110007820472") | |||||
| // .receivers("[{\"type\": \"PERSONAL_OPENID\",\"account\":\"oyOUE5ql4TtzrBg5cVOwxq6tbjOs\",\"amount\":100,\"description\": \"分到用户\"}]") | |||||
| .receivers(instance.toJSONString()) | |||||
| .build(); | |||||
| this.logger.info(this.payService.getProfitSharingService().profitsharing(request).toString()); | |||||
| } | |||||
| } | |||||