feat 各种分账各种问题解决和优化

This commit is contained in:
DaxPay
2024-05-31 17:45:39 +08:00
parent fa54a853a5
commit 73e43115ad
23 changed files with 188 additions and 43 deletions

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>cn.daxpay.single</groupId>
<artifactId>daxpay-single</artifactId>
<version>2.0.6</version>
<version>2.0.7</version>
</parent>
<artifactId>daxpay-single-admin</artifactId>

View File

@@ -95,7 +95,7 @@ public class AllocationOrderController {
return Res.ok();
}
@InitPaymentContext(PaymentApiCode.SYNC_REFUND)
@InitPaymentContext(PaymentApiCode.ALLOCATION_FINISH)
@Operation(summary = "分账完结")
@PostMapping("/finish")
public ResResult<Void> finish(String allocationNo){

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>cn.daxpay.single</groupId>
<artifactId>daxpay-single</artifactId>
<version>2.0.6</version>
<version>2.0.7</version>
</parent>
<artifactId>daxpay-single-core</artifactId>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>cn.daxpay.single</groupId>
<artifactId>daxpay-single</artifactId>
<version>2.0.6</version>
<version>2.0.7</version>
</parent>
<artifactId>daxpay-single-gateway</artifactId>

View File

@@ -1,6 +1,7 @@
package cn.daxpay.single.gateway.controller;
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
import cn.daxpay.single.service.core.channel.alipay.service.AliPayNoticeReceiverService;
import com.ijpay.alipay.AliPayApi;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -15,33 +16,29 @@ import java.util.Map;
import java.util.Objects;
/**
* 网关消息通知
* 支付通道消息通知
* @author xxm
* @since 2024/4/16
*/
@IgnoreAuth
@Tag(name = "三方支付网关消息通知")
@Tag(name = "执法通道网关消息通知")
@RestController
@RequestMapping("/gateway/notice")
@RequestMapping("/callback/notice")
@RequiredArgsConstructor
public class PayNoticeReceiverController {
private final AliPayNoticeReceiverService aliPayNoticeReceiverService;
@Operation(summary = "支付宝消息通知")
@PostMapping("/alipay")
public String aliPayNotice(HttpServletRequest request) {
Map<String, String> map = AliPayApi.toMap(request);
// 通过 msg_method 获取消息类型
String msgMethod = map.get("msg_method");
// 通过 biz_content 获取值
String bizContent = map.get("biz_content");
return "success";
return aliPayNoticeReceiverService.noticeReceiver(map);
}
@Operation(summary = "微信消息通知")
@PostMapping("/wechat")
public Map<String, Objects> wechatPayNotice() {
public Map<String, Objects> wechatPayNotice(HttpServletRequest request) {
return new HashMap<>();
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>cn.daxpay.single</groupId>
<artifactId>daxpay-single</artifactId>
<version>2.0.6</version>
<version>2.0.7</version>
</parent>
<artifactId>daxpay-single-service</artifactId>

View File

@@ -113,7 +113,7 @@ public interface AliPayCode {
String ALLOC_FAIL = "FAIL";
/** 异步分账 */
String ALLOC_ASYNC = "ASYNC";
String ALLOC_ASYNC = "async";
/** 同步分账 */
String ALLOC_SYNC = "SYNC";
String ALLOC_SYNC = "sync";
}

View File

@@ -49,7 +49,7 @@ public class AliPayAllocationService {
public void allocation(AllocationOrder allocationOrder, List<AllocationOrderDetail> orderDetails){
// 分账主体参数
AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel();
model.setOutRequestNo(allocationOrder.getOrderNo());
model.setOutRequestNo(allocationOrder.getAllocationNo());
model.setTradeNo(allocationOrder.getOutOrderNo());
model.setRoyaltyMode(AliPayCode.ALLOC_ASYNC);
@@ -79,12 +79,12 @@ public class AliPayAllocationService {
public void finish(AllocationOrder allocationOrder, List<AllocationOrderDetail> orderDetails ){
// 分账主体参数
AlipayTradeOrderSettleModel model = new AlipayTradeOrderSettleModel();
model.setOutRequestNo(String.valueOf(allocationOrder.getOrderNo()));
model.setOutRequestNo(String.valueOf(allocationOrder.getAllocationNo()));
model.setTradeNo(allocationOrder.getOutOrderNo());
model.setRoyaltyMode(AliPayCode.ALLOC_ASYNC);
// 分账完结参数
SettleExtendParams extendParams = new SettleExtendParams();
extendParams.setRoyaltyFinish("true");
extendParams.setRoyaltyFinish(Boolean.TRUE.toString());
model.setExtendParams(extendParams);
// 分账子参数 根据Id排序
@@ -109,7 +109,7 @@ public class AliPayAllocationService {
public AllocRemoteSyncResult sync(AllocationOrder allocationOrder, List<AllocationOrderDetail> allocationOrderDetails){
AlipayTradeOrderSettleQueryModel model = new AlipayTradeOrderSettleQueryModel();
model.setTradeNo(allocationOrder.getOutOrderNo());
model.setOutRequestNo(allocationOrder.getOrderNo());
model.setOutRequestNo(allocationOrder.getAllocationNo());
AlipayTradeOrderSettleQueryRequest request = new AlipayTradeOrderSettleQueryRequest();
request.setBizModel(model);
AlipayTradeOrderSettleQueryResponse response = AliPayApi.execute(request);

View File

@@ -0,0 +1,95 @@
package cn.daxpay.single.service.core.channel.alipay.service;
import cn.bootx.platform.common.core.util.CertUtil;
import cn.daxpay.single.service.core.channel.alipay.entity.AliPayConfig;
import cn.daxpay.single.service.core.payment.allocation.service.AllocationCallbackService;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConstants;
import com.alipay.api.internal.util.AlipaySignature;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.Objects;
import static cn.daxpay.single.service.code.AliPayCode.APP_ID;
import static cn.daxpay.single.service.code.AliPayCode.AUTH_TYPE_KEY;
/**
* 支付宝通知消息接收
* @author xxm
* @since 2024/5/31
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AliPayNoticeReceiverService {
private final AllocationCallbackService allocationCallbackService;
private final AliPayConfigService aliPayConfigService;
/**
* 消息通知处理
*/
public String noticeReceiver(Map<String, String> map) {
// 首先进行验签
if (!this.verifyNotify(map)){
log.error("支付宝消息通知验签失败");
return "fail";
}
// 通过 msg_method 获取消息类型
String msgMethod = map.get("msg_method");
// 通过 biz_content 获取值
String bizContent = map.get("biz_content");
// 分账结果通知
if ("alipay.trade.order.settle.notify".equals(msgMethod)) {
// 转换成对象
// 获取分账号
// 调用统一分账回调处理
// 分账完成
}
// 返回处理成功
return "success";
}
/**
* 校验消息通知
*/
private boolean verifyNotify(Map<String, String> params) {
String callReq = JSONUtil.toJsonStr(params);
log.info("支付宝消息通知报文: {}", callReq);
String appId = params.get(APP_ID);
if (StrUtil.isBlank(appId)) {
log.error("支付宝消息通知报文appId为空");
return false;
}
AliPayConfig alipayConfig = aliPayConfigService.getConfig();
if (Objects.isNull(alipayConfig)) {
log.error("支付宝支付配置不存在");
return false;
}
try {
if (Objects.equals(alipayConfig.getAuthType(), AUTH_TYPE_KEY)) {
return AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), CharsetUtil.UTF_8, AlipayConstants.SIGN_TYPE_RSA2);
}
else {
return AlipaySignature.verifyV1(params, CertUtil.getCertByContent(alipayConfig.getAlipayCert()), CharsetUtil.UTF_8, AlipayConstants.SIGN_TYPE_RSA2);
}
} catch (AlipayApiException e) {
log.error("支付宝验签失败", e);
return false;
}
}
}

View File

@@ -21,6 +21,7 @@ import java.util.List;
import java.util.Map;
import static cn.daxpay.single.code.AllocReceiverTypeEnum.WX_MERCHANT;
import static cn.daxpay.single.code.AllocReceiverTypeEnum.WX_PERSONAL;
/**
*
@@ -36,7 +37,7 @@ public class WeChatPayAllocationReceiverService {
* 校验参数是否合法
*/
public boolean validation(AllocationReceiver allocationReceiver){
List<String> list = Arrays.asList(WX_MERCHANT.getCode(), WX_MERCHANT.getCode());
List<String> list = Arrays.asList(WX_PERSONAL.getCode(), WX_MERCHANT.getCode());
String receiverType = allocationReceiver.getReceiverType();
return list.contains(receiverType);
}

View File

@@ -75,7 +75,7 @@ public class WeChatPayAllocationService {
.appid(config.getWxAppId())
.nonce_str(WxPayKit.generateStr())
.transaction_id(allocationOrder.getOutOrderNo())
.out_order_no(allocationOrder.getOrderNo())
.out_order_no(allocationOrder.getAllocationNo())
.receivers(JSON.toJSONString(list))
.build()
.createSign(config.getApiKeyV2(), SignType.HMACSHA256);
@@ -96,8 +96,9 @@ public class WeChatPayAllocationService {
.appid(config.getWxAppId())
.nonce_str(WxPayKit.generateStr())
.transaction_id(allocationOrder.getOutOrderNo())
.out_order_no(allocationOrder.getOrderNo())
.description("分账完成")
// 分账要使用单独的的流水号, 不能与分账号相同
.out_order_no(allocationOrder.getAllocationNo()+'F')
.description("分账已完成")
.build()
.createSign(config.getApiKeyV2(), SignType.HMACSHA256);
@@ -117,7 +118,7 @@ public class WeChatPayAllocationService {
.mch_id(config.getWxMchId())
.nonce_str(WxPayKit.generateStr())
.transaction_id(allocationOrder.getOutOrderNo())
.out_order_no(allocationOrder.getOrderNo())
.out_order_no(allocationOrder.getAllocationNo())
.build()
.createSign(config.getApiKeyV2(), SignType.HMACSHA256);
String xmlResult = WxPayApi.profitSharingQuery(params);

View File

@@ -0,0 +1,24 @@
package cn.daxpay.single.service.core.payment.allocation.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 分账回调处理
* @author xxm
* @since 2024/5/31
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AllocationCallbackService {
/**
*
*/
public void callback(String allocationNo){
}
}

View File

@@ -3,6 +3,7 @@ package cn.daxpay.single.service.core.payment.allocation.service;
import cn.bootx.platform.common.core.exception.DataNotExistException;
import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.bootx.platform.common.core.util.CollUtil;
import cn.daxpay.single.code.AllocDetailResultEnum;
import cn.daxpay.single.code.AllocOrderStatusEnum;
import cn.daxpay.single.code.PayOrderAllocStatusEnum;
import cn.daxpay.single.exception.pay.PayFailureException;
@@ -35,11 +36,15 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import static cn.daxpay.single.code.AllocOrderStatusEnum.ALLOCATION_END;
import static cn.daxpay.single.code.AllocOrderStatusEnum.FINISH_FAILED;
/**
* 分账服务
* @author xxm
@@ -151,13 +156,13 @@ public class AllocationService {
}
try {
// 需要是分账中分账中或者完成状态才能重新分账
List<String> list = Arrays.asList(AllocOrderStatusEnum.ALLOCATION_END.getCode(),
List<String> list = Arrays.asList(ALLOCATION_END.getCode(),
AllocOrderStatusEnum.ALLOCATION_FAILED.getCode(),
AllocOrderStatusEnum.ALLOCATION_PROCESSING.getCode());
if (!list.contains(order.getStatus())){
throw new PayFailureException("分账单状态错误,无法重试");
}
List<AllocationOrderDetail> details = allocationOrderDetailManager.findAllByOrderId(order.getId());
List<AllocationOrderDetail> details = this.getDetails(order.getId());
// 创建分账策略并初始化
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(order.getChannel());
allocationStrategy.initParam(order, details);
@@ -209,10 +214,11 @@ public class AllocationService {
*/
public AllocationResult finish(AllocationOrder allocationOrder) {
// 只有分账结束后才可以完结
if (!AllocOrderStatusEnum.ALLOCATION_END.getCode().equals(allocationOrder.getStatus())){
if (!Arrays.asList(ALLOCATION_END.getCode(),FINISH_FAILED.getCode()).contains(allocationOrder.getStatus())) {
throw new PayFailureException("分账单状态错误");
}
List<AllocationOrderDetail> details = allocationOrderDetailManager.findAllByOrderId(allocationOrder.getId());
List<AllocationOrderDetail> details = this.getDetails(allocationOrder.getId());
// 创建分账策略并初始化
AbsAllocationStrategy allocationStrategy = AllocationFactory.create(allocationOrder.getChannel());
allocationStrategy.initParam(allocationOrder, details);
@@ -224,11 +230,12 @@ public class AllocationService {
allocationStrategy.finish();
// 完结状态
allocationOrder.setStatus(AllocOrderStatusEnum.FINISH.getCode())
.setFinishTime(LocalDateTime.now())
.setErrorMsg(null);
} catch (Exception e) {
log.error("分账完结错误:", e);
// 失败
allocationOrder.setStatus(AllocOrderStatusEnum.FINISH_FAILED.getCode())
allocationOrder.setStatus(FINISH_FAILED.getCode())
.setErrorMsg(e.getMessage());
}
allocationOrderManager.updateById(allocationOrder);
@@ -293,4 +300,15 @@ public class AllocationService {
}
return orderAndDetail;
}
/**
* 获取发起分账或完结的明细
*/
private List<AllocationOrderDetail> getDetails(Long allocOrderId){
List<AllocationOrderDetail> details = allocationOrderDetailManager.findAllByOrderId(allocOrderId);
// 过滤掉忽略的条目
return details.stream()
.filter(detail -> !Objects.equals(detail.getResult(), AllocDetailResultEnum.IGNORE.getCode()))
.collect(Collectors.toList());
}
}

View File

@@ -13,7 +13,7 @@
<groupId>cn.daxpay.single</groupId>
<artifactId>daxpay-single</artifactId>
<packaging>pom</packaging>
<version>2.0.6</version>
<version>2.0.7</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -22,7 +22,7 @@
<!-- 二方库版本 -->
<bootx-platform.version>1.3.6.2</bootx-platform.version>
<daxpay.version>2.0.6</daxpay.version>
<daxpay.version>2.0.7</daxpay.version>
<!-- 三方库 -->
<slf4j.version>1.7.30</slf4j.version>
<redisson.version>3.16.8</redisson.version>