@@ -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; | |||
import java.text.Format; | |||
import java.util.List; | |||
import com.google.common.collect.Lists; | |||
import org.apache.commons.lang3.time.FastDateFormat; | |||
import com.google.common.collect.Lists; | |||
import java.text.Format; | |||
import java.util.List; | |||
/** | |||
* <pre> | |||
@@ -273,4 +272,23 @@ public class WxPayConstants { | |||
*/ | |||
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(); | |||
/** | |||
* 获取分账服务类. | |||
* | |||
* @return the ent pay service | |||
*/ | |||
ProfitSharingService getProfitSharingService(); | |||
/** | |||
* 设置企业付款服务类,允许开发者自定义实现类. | |||
* | |||
@@ -304,6 +311,7 @@ public interface WxPayService { | |||
* @throws WxPayException the wx pay exception | |||
*/ | |||
WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxPayException; | |||
/** | |||
* <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.exception.WxPayException; | |||
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.util.SignUtils; | |||
import com.google.common.base.Joiner; | |||
@@ -59,7 +60,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { | |||
static ThreadLocal<WxPayApiData> wxApiData = new ThreadLocal<>(); | |||
private EntPayService entPayService = new EntPayServiceImpl(this); | |||
private ProfitSharingService profitSharingService = new ProfitSharingServiceImpl(this); | |||
/** | |||
* The Config. | |||
*/ | |||
@@ -70,6 +71,11 @@ public abstract class BaseWxPayServiceImpl implements WxPayService { | |||
return entPayService; | |||
} | |||
@Override | |||
public ProfitSharingService getProfitSharingService() { | |||
return profitSharingService; | |||
} | |||
@Override | |||
public void setEntPayService(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()); | |||
} | |||
} |