mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-04 19:49:07 +00:00
feat 分账同步联调
This commit is contained in:
@@ -157,13 +157,13 @@ public class SimplePayOrderTest {
|
||||
|
||||
## 🍎 系统截图
|
||||
### 收银台演示
|
||||

|
||||

|
||||
### 驾驶舱
|
||||

|
||||

|
||||
### H5收银台演示
|
||||

|
||||

|
||||
### 支付通道配置
|
||||

|
||||

|
||||
## 🛣️ 路线图
|
||||
> 当前处于功能开发阶段,部分功能可能会有调整,`V2.1.0`时将作为正式生产可用版本进行发布,之后会保证系统版本非大版本升级时,API接口和数据接口向前兼容
|
||||
|
||||
|
@@ -2,7 +2,11 @@
|
||||
- [ ] 资金流水优化
|
||||
- [x] 支付通道配置是否支持分账
|
||||
- [ ] 分账接收方管理
|
||||
- [ ] 管理
|
||||
- [ ] 同步
|
||||
- [ ] 分账组管理
|
||||
- [ ] 管理
|
||||
- [ ] 绑定
|
||||
- [ ] 分账订单管理
|
||||
- [ ] 统计报表功能
|
||||
- [x] 修复创建支付订单报错时, 订单保存数据不完整
|
||||
|
@@ -34,6 +34,16 @@ public enum AllocationReceiverTypeEnum {
|
||||
/** 名称 */
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* 根据编码查找
|
||||
*/
|
||||
public static AllocationReceiverTypeEnum findByCode(String code) {
|
||||
return Arrays.stream(AllocationReceiverTypeEnum.values())
|
||||
.filter(e -> e.getCode().equals(code))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("未找到对应的分账接收方类型"));
|
||||
}
|
||||
|
||||
/** 微信支持类型 */
|
||||
public static final List<AllocationReceiverTypeEnum> WECHAT_LIST = Collections.unmodifiableList(Arrays.asList(WX_PERSONAL, WX_MERCHANT));
|
||||
/** 支付宝支持类型 */
|
||||
|
@@ -98,4 +98,8 @@ public interface AliPayCode {
|
||||
// 网关返回码 支付进行中 order success pay inprocess
|
||||
String INPROCESS = "10003";
|
||||
|
||||
/* 分账相关 */
|
||||
/** 分账接收方不存在 */
|
||||
String USER_NOT_EXIST = "USER_NOT_EXIST";
|
||||
|
||||
}
|
||||
|
@@ -1,6 +1,11 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.alipay.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.AllocationReceiverTypeEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.service.code.AliPayCode;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.allocation.entity.AllocationReceiver;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alipay.api.AlipayResponse;
|
||||
import com.alipay.api.domain.AlipayTradeRoyaltyRelationBindModel;
|
||||
import com.alipay.api.domain.AlipayTradeRoyaltyRelationUnbindModel;
|
||||
import com.alipay.api.domain.RoyaltyEntity;
|
||||
@@ -15,6 +20,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.bootx.platform.daxpay.code.AllocationReceiverTypeEnum.*;
|
||||
|
||||
@@ -32,7 +38,7 @@ public class AliPayAllocationReceiverService {
|
||||
* 校验
|
||||
*/
|
||||
public boolean validation(AllocationReceiver allocationReceiver){
|
||||
List<String> list = Arrays.asList(ALI_USER_ID.getOutCode(), ALI_OPEN_ID.getOutCode(), ALI_LOGIN_NAME.getOutCode());
|
||||
List<String> list = Arrays.asList(ALI_USER_ID.getCode(), ALI_OPEN_ID.getCode(), ALI_LOGIN_NAME.getCode());
|
||||
String receiverType = allocationReceiver.getReceiverType();
|
||||
return list.contains(receiverType);
|
||||
}
|
||||
@@ -45,16 +51,17 @@ public class AliPayAllocationReceiverService {
|
||||
AlipayTradeRoyaltyRelationBindModel model = new AlipayTradeRoyaltyRelationBindModel();
|
||||
model.setOutRequestNo(String.valueOf(allocationReceiver.getId()));
|
||||
|
||||
// 分账接收方方类型。
|
||||
RoyaltyEntity entity = new RoyaltyEntity();
|
||||
entity.setType(allocationReceiver.getReceiverType());
|
||||
AllocationReceiverTypeEnum receiverTypeEnum = AllocationReceiverTypeEnum.findByCode(allocationReceiver.getReceiverType());
|
||||
entity.setType(receiverTypeEnum.getOutCode());
|
||||
entity.setAccount(allocationReceiver.getReceiverAccount());
|
||||
entity.setName(allocationReceiver.getReceiverName());
|
||||
entity.setMemo(allocationReceiver.getRelationName());
|
||||
|
||||
// 不报错视为同步成功
|
||||
model.setReceiverList(Collections.singletonList(entity));
|
||||
AlipayTradeRoyaltyRelationBindResponse response = AliPayApi.tradeRoyaltyRelationBind(model);
|
||||
|
||||
// 如果返回成功或者已经绑定, 关系
|
||||
this.verifyErrorMsg(response);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,12 +73,31 @@ public class AliPayAllocationReceiverService {
|
||||
model.setOutRequestNo(String.valueOf(allocationReceiver.getId()));
|
||||
|
||||
RoyaltyEntity entity = new RoyaltyEntity();
|
||||
AllocationReceiverTypeEnum receiverTypeEnum = findByCode(allocationReceiver.getReceiverType());
|
||||
entity.setType(receiverTypeEnum.getOutCode());
|
||||
entity.setAccount(allocationReceiver.getReceiverAccount());
|
||||
entity.setMemo(allocationReceiver.getRelationName());
|
||||
|
||||
model.setReceiverList(Collections.singletonList(entity));
|
||||
AlipayTradeRoyaltyRelationUnbindResponse response = AliPayApi.tradeRoyaltyRelationUnBind(model);
|
||||
System.out.println(response);
|
||||
// 如果出现分账方不存在也视为成功
|
||||
if (Objects.equals(response.getSubCode(), AliPayCode.USER_NOT_EXIST)) {
|
||||
return;
|
||||
}
|
||||
this.verifyErrorMsg(response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证错误信息
|
||||
*/
|
||||
private void verifyErrorMsg(AlipayResponse alipayResponse) {
|
||||
if (!Objects.equals(alipayResponse.getCode(), AliPayCode.SUCCESS)) {
|
||||
String errorMsg = alipayResponse.getSubMsg();
|
||||
if (StrUtil.isBlank(errorMsg)) {
|
||||
errorMsg = alipayResponse.getMsg();
|
||||
}
|
||||
log.error("支付失败 {}", errorMsg);
|
||||
throw new PayFailureException(errorMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,16 @@
|
||||
package cn.bootx.platform.daxpay.service.core.channel.wechat.service;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.AllocationReceiverTypeEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.service.code.WeChatPayCode;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.allocation.entity.AllocationReceiver;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
import com.ijpay.wxpay.WxPayApi;
|
||||
import com.ijpay.wxpay.model.ProfitSharingModel;
|
||||
import com.ijpay.wxpay.model.ReceiverModel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -33,7 +36,7 @@ public class WeChatPayAllocationReceiverService {
|
||||
* 校验参数是否合法
|
||||
*/
|
||||
public boolean validation(AllocationReceiver allocationReceiver){
|
||||
List<String> list = Arrays.asList(WX_MERCHANT.getOutCode(), WX_MERCHANT.getOutCode());
|
||||
List<String> list = Arrays.asList(WX_MERCHANT.getCode(), WX_MERCHANT.getCode());
|
||||
String receiverType = allocationReceiver.getReceiverType();
|
||||
return !list.contains(receiverType);
|
||||
}
|
||||
@@ -42,18 +45,25 @@ public class WeChatPayAllocationReceiverService {
|
||||
* 绑定
|
||||
*/
|
||||
public void bind(AllocationReceiver allocationReceiver, WeChatPayConfig weChatPayConfig){
|
||||
|
||||
Map<String, String> param = ReceiverModel.builder()
|
||||
.type(allocationReceiver.getReceiverType())
|
||||
AllocationReceiverTypeEnum receiverTypeEnum = AllocationReceiverTypeEnum.findByCode(allocationReceiver.getReceiverType());
|
||||
// 接收者参数
|
||||
ReceiverModel receiver = ReceiverModel.builder()
|
||||
.type(receiverTypeEnum.getOutCode())
|
||||
.account(allocationReceiver.getReceiverAccount())
|
||||
.name(allocationReceiver.getReceiverName())
|
||||
.relation_type(allocationReceiver.getRelationType())
|
||||
.custom_relation(allocationReceiver.getRelationType())
|
||||
.custom_relation(allocationReceiver.getRelationName())
|
||||
.build();
|
||||
// 请求参数
|
||||
Map<String, String> params = ProfitSharingModel.builder()
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.receiver(JSONUtil.toJsonStr(receiver))
|
||||
.build()
|
||||
.createSign(weChatPayConfig.getApiKeyV2(), SignType.HMACSHA256);
|
||||
|
||||
String xmlResult = WxPayApi.profitSharingAddReceiver(param);
|
||||
String xmlResult = WxPayApi.profitSharingAddReceiver(params);
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
this.verifyErrorMsg(result);
|
||||
}
|
||||
@@ -62,13 +72,26 @@ public class WeChatPayAllocationReceiverService {
|
||||
* 解除绑定
|
||||
*/
|
||||
public void unbind(AllocationReceiver allocationReceiver, WeChatPayConfig weChatPayConfig){
|
||||
Map<String, String> param = ReceiverModel.builder()
|
||||
.type(allocationReceiver.getReceiverType())
|
||||
AllocationReceiverTypeEnum receiverTypeEnum = AllocationReceiverTypeEnum.findByCode(allocationReceiver.getReceiverType());
|
||||
// 原始参数
|
||||
ReceiverModel receiver = ReceiverModel.builder()
|
||||
.type(receiverTypeEnum.getOutCode())
|
||||
.account(allocationReceiver.getReceiverAccount())
|
||||
.name(allocationReceiver.getReceiverName())
|
||||
.relation_type(allocationReceiver.getRelationType())
|
||||
.custom_relation(allocationReceiver.getRelationName())
|
||||
.build();
|
||||
|
||||
// 原始参数
|
||||
Map<String, String> params = ProfitSharingModel.builder()
|
||||
.mch_id(weChatPayConfig.getWxMchId())
|
||||
.appid(weChatPayConfig.getWxAppId())
|
||||
.nonce_str(WxPayKit.generateStr())
|
||||
.receiver(JSONUtil.toJsonStr(receiver))
|
||||
.build()
|
||||
.createSign(weChatPayConfig.getApiKeyV2(), SignType.HMACSHA256);
|
||||
|
||||
String xmlResult = WxPayApi.profitSharingRemoveReceiver(param);
|
||||
String xmlResult = WxPayApi.profitSharingRemoveReceiver(params);
|
||||
Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
|
||||
this.verifyErrorMsg(result);
|
||||
}
|
||||
@@ -84,7 +107,7 @@ public class WeChatPayAllocationReceiverService {
|
||||
if (StrUtil.isBlank(errorMsg)) {
|
||||
errorMsg = result.get(WeChatPayCode.RETURN_MSG);
|
||||
}
|
||||
log.error("支付失败 {}", errorMsg);
|
||||
log.error("分账绑定或解绑失败 {}", errorMsg);
|
||||
throw new PayFailureException(errorMsg);
|
||||
}
|
||||
}
|
||||
|
@@ -43,17 +43,15 @@ public class AllocationReceiver extends MpBaseEntity implements EntityBaseFuncti
|
||||
* @see AllocationReceiverTypeEnum
|
||||
*/
|
||||
@DbColumn(comment = "分账接收方类型")
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
private String receiverType;
|
||||
|
||||
|
||||
@DbColumn(comment = "接收方账号")
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
private String receiverAccount;
|
||||
|
||||
/** 接收方姓名 */
|
||||
@DbColumn(comment = "接收方姓名")
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS)
|
||||
private String receiverName;
|
||||
|
||||
/**
|
||||
@@ -61,15 +59,13 @@ public class AllocationReceiver extends MpBaseEntity implements EntityBaseFuncti
|
||||
* @see AllocationRelationTypeEnum
|
||||
*/
|
||||
@DbColumn(comment = "分账关系类型")
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
private String relationType;
|
||||
|
||||
@DbColumn(comment = "关系名称")
|
||||
@TableField(updateStrategy = FieldStrategy.NEVER)
|
||||
private String relationName;
|
||||
|
||||
@DbColumn(comment = "是否已经同步到网关")
|
||||
private boolean sync;
|
||||
private Boolean sync;
|
||||
|
||||
@DbColumn(comment = "备注")
|
||||
private String remark;
|
||||
|
@@ -28,6 +28,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -136,7 +137,7 @@ public class AllocationGroupService {
|
||||
}
|
||||
// 接收方需要已经同步到三方值系统中
|
||||
receivers.stream()
|
||||
.filter(receiver -> !receiver.isSync())
|
||||
.filter(receiver -> Objects.equals(receiver.getSync(), Boolean.FALSE))
|
||||
.findAny()
|
||||
.ifPresent(receiver -> {
|
||||
throw new DataNotExistException("接收方未同步到三方值系统中");
|
||||
|
@@ -18,12 +18,14 @@ import cn.bootx.platform.daxpay.service.dto.allocation.AllocationReceiverDto;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsAllocationReceiverStrategy;
|
||||
import cn.bootx.platform.daxpay.service.param.allocation.AllocationReceiverParam;
|
||||
import cn.bootx.platform.daxpay.service.param.allocation.AllocationReceiverQuery;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -94,7 +96,9 @@ public class AllocationReceiverService {
|
||||
AbsAllocationReceiverStrategy receiverStrategy = AllocationReceiverFactory.create(channelEnum);
|
||||
// 校验
|
||||
receiverStrategy.setAllocationReceiver(receiver);
|
||||
receiverStrategy.validation();
|
||||
if (!receiverStrategy.validation()){
|
||||
throw new BizException("接收方信息校验失败");
|
||||
}
|
||||
|
||||
receiver.setSync(false);
|
||||
manager.save(receiver);
|
||||
@@ -105,8 +109,11 @@ public class AllocationReceiverService {
|
||||
*/
|
||||
public void update(AllocationReceiverParam param){
|
||||
AllocationReceiver receiver = manager.findById(param.getId()).orElseThrow(() -> new PayFailureException("未找到分账接收方"));
|
||||
receiver.setName(param.getName())
|
||||
.setRemark(param.getRemark());
|
||||
if (Objects.equals(receiver.getSync(),true)){
|
||||
throw new BizException("该接收方已同步到三方支付系统中,无法修改");
|
||||
}
|
||||
receiver.setSync(null);
|
||||
BeanUtil.copyProperties(param,receiver);
|
||||
manager.updateById(receiver);
|
||||
}
|
||||
|
||||
@@ -116,7 +123,7 @@ public class AllocationReceiverService {
|
||||
public void remove(Long id){
|
||||
// 未同步可以删除
|
||||
AllocationReceiver receiver = manager.findById(id).orElseThrow(() -> new PayFailureException("未找到分账接收方"));
|
||||
if (receiver.isSync()){
|
||||
if (Objects.equals(receiver.getSync(),true)){
|
||||
throw new BizException("该接收方已同步到三方支付系统中,无法删除");
|
||||
}
|
||||
// 判断是否绑定了分账组
|
||||
|
@@ -58,6 +58,7 @@ public class AliPayAllocationReceiverStrategy extends AbsAllocationReceiverStrat
|
||||
if (Objects.equals(aliPayConfig.getAllocation(),false)){
|
||||
throw new PayFailureException("微信支付配置不支持分账");
|
||||
}
|
||||
payConfigService.initConfig(this.aliPayConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -58,7 +58,7 @@ public class AllocationReceiverDto extends BaseDto {
|
||||
private String relationName;
|
||||
|
||||
@Schema(description = "是否已经同步到网关")
|
||||
private boolean sync;
|
||||
private Boolean sync;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
@@ -56,7 +56,7 @@ public class AllocationReceiverParam {
|
||||
private String relationName;
|
||||
|
||||
@Schema(description = "是否已经同步到网关")
|
||||
private boolean sync;
|
||||
private Boolean sync;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
@@ -49,5 +49,5 @@ public class AllocationReceiverQuery {
|
||||
private String relationType;
|
||||
|
||||
@Schema(description = "是否已经同步到网关")
|
||||
private boolean sync;
|
||||
private Boolean sync;
|
||||
}
|
||||
|
Reference in New Issue
Block a user