交易分账 重构

This commit is contained in:
2023-08-29 14:54:41 +08:00
parent f836ddddd2
commit 1a40e284b7
6 changed files with 163 additions and 63 deletions

View File

@@ -212,6 +212,46 @@ public class SpringBootTestController {
@Autowired @Autowired
private MemberAdapayRecordService memberAdapayRecordService; private MemberAdapayRecordService memberAdapayRecordService;
/**
* 测试多笔支付情况,解冻部分金额
*/
@Test
public void calculateUnfreezeAmountTest() {
BigDecimal orderAmount = new BigDecimal("28");
List<OrderPayRecord> payRecordList = Lists.newArrayList();
// 第一笔支付记录
JSONObject jsonObject = new JSONObject();
jsonObject.put("paymentId", "1");
jsonObject.put("amount", "10");
OrderPayRecord build = OrderPayRecord.builder()
.payAmount(new BigDecimal("10"))
.deductionRecord(jsonObject.toJSONString())
.build();
payRecordList.add(build);
// 第二笔支付记录
JSONObject jsonObject2 = new JSONObject();
jsonObject2.put("paymentId", "2");
jsonObject2.put("amount", "10");
OrderPayRecord build2 = OrderPayRecord.builder()
.payAmount(new BigDecimal("10"))
.deductionRecord(jsonObject2.toJSONString())
.build();
payRecordList.add(build2);
// 第三笔支付记录
JSONObject jsonObject3 = new JSONObject();
jsonObject3.put("paymentId", "3");
jsonObject3.put("amount", "10");
OrderPayRecord build3 = OrderPayRecord.builder()
.payAmount(new BigDecimal("10"))
.deductionRecord(jsonObject3.toJSONString())
.build();
payRecordList.add(build3);
List<Map<String, Object>> maps = orderBasicInfoService.calculateUnfreezeAmount(orderAmount, payRecordList);
System.out.println(maps);
}
@Test @Test
public void unfreezeAmountAndUpdateSpendAmountTest() { public void unfreezeAmountAndUpdateSpendAmountTest() {
String paymentId = "123"; String paymentId = "123";

View File

@@ -1,12 +1,9 @@
package com.jsowell.pile.domain; package com.jsowell.pile.domain;
import lombok.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/** /**
* 订单支付明细 * 订单支付明细
@@ -29,6 +26,7 @@ public class OrderPayRecord {
/** /**
* 支付方式1-本金余额支付2-赠送余额支付3-白名单支付4-微信支付5-支付宝支付) * 支付方式1-本金余额支付2-赠送余额支付3-白名单支付4-微信支付5-支付宝支付)
* @see com.jsowell.common.enums.ykc.OrderPayRecordEnum
*/ */
private String payMode; private String payMode;
@@ -49,6 +47,10 @@ public class OrderPayRecord {
/** /**
* 扣款记录 * 扣款记录
* {
* "paymentId": "123123",
* "amount": "1.00"
* }
*/ */
private String deductionRecord; private String deductionRecord;

View File

@@ -5,10 +5,7 @@ import com.jsowell.adapay.response.PaymentReverseResponse;
import com.jsowell.adapay.vo.OrderSettleResult; import com.jsowell.adapay.vo.OrderSettleResult;
import com.jsowell.common.core.domain.ykc.RealTimeMonitorData; import com.jsowell.common.core.domain.ykc.RealTimeMonitorData;
import com.jsowell.common.core.domain.ykc.TransactionRecordsData; import com.jsowell.common.core.domain.ykc.TransactionRecordsData;
import com.jsowell.pile.domain.AdapayMemberAccount; import com.jsowell.pile.domain.*;
import com.jsowell.pile.domain.OrderBasicInfo;
import com.jsowell.pile.domain.OrderDetail;
import com.jsowell.pile.domain.SettleOrderReport;
import com.jsowell.pile.dto.*; import com.jsowell.pile.dto.*;
import com.jsowell.pile.vo.base.MerchantOrderInfoVO; import com.jsowell.pile.vo.base.MerchantOrderInfoVO;
import com.jsowell.pile.vo.base.OrderAmountDetailVO; import com.jsowell.pile.vo.base.OrderAmountDetailVO;
@@ -147,6 +144,8 @@ public interface IOrderBasicInfoService {
List<OrderVO> getListByMemberIdAndOrderStatus(String memberId, List<String> orderStatusList, LocalDateTime dateTime, String stationId); List<OrderVO> getListByMemberIdAndOrderStatus(String memberId, List<String> orderStatusList, LocalDateTime dateTime, String stationId);
List<Map<String, Object>> calculateUnfreezeAmount(BigDecimal orderAmount, List<OrderPayRecord> payRecordList);
void orderSplittingOperations(AdapayMemberAccount adapayMemberAccount, List<SettleOrderReport> stationReportList); void orderSplittingOperations(AdapayMemberAccount adapayMemberAccount, List<SettleOrderReport> stationReportList);
void orderSplittingOperations(String merchantId, String tradeDate); void orderSplittingOperations(String merchantId, String tradeDate);

View File

@@ -38,6 +38,8 @@ public interface MemberAdapayRecordService{
void updateSpendAmount(String paymentId, BigDecimal amount); void updateSpendAmount(String paymentId, BigDecimal amount);
void unfreezeAmount(String paymentId, BigDecimal unfreezeAmount);
void unfreezeAmountAndUpdateSpendAmount(String paymentId, BigDecimal unfreezeAmount, BigDecimal spendAmount); void unfreezeAmountAndUpdateSpendAmount(String paymentId, BigDecimal unfreezeAmount, BigDecimal spendAmount);
void updateRefundAmountFromFreezeAmount(String paymentId, BigDecimal refundAmount); void updateRefundAmountFromFreezeAmount(String paymentId, BigDecimal refundAmount);

View File

@@ -89,6 +89,14 @@ public class MemberAdapayRecordServiceImpl implements MemberAdapayRecordService
commonUpdateAmountMethod(paymentId, spendAmount, null, null); commonUpdateAmountMethod(paymentId, spendAmount, null, null);
} }
/**
* 解冻金额
*/
@Override
public void unfreezeAmount(String paymentId, BigDecimal unfreezeAmount) {
commonUpdateAmountMethod(paymentId, null, null, unfreezeAmount.negate());
}
/** /**
* 解冻金额并更新消费金额 * 解冻金额并更新消费金额
* @param unfreezeAmount 解冻金额 * @param unfreezeAmount 解冻金额

View File

@@ -749,42 +749,46 @@ public class OrderBasicInfoServiceImpl implements IOrderBasicInfoService {
return null; return null;
} }
/* // 获取一级运营商的 延时分账设置
获取一级运营商的 延时分账设置
使用延时分账的一级运营商,需要
未使用延时分账的一级运营商
*/
String delayMode = merchantInfo.getDelayMode(); String delayMode = merchantInfo.getDelayMode();
if (StringUtils.equals(delayMode, Constants.ADAPAY_PAY_MODE_DELAY)) { if (StringUtils.equals(delayMode, Constants.ONE)) {
// 记账 冻结金额 /*
// freezeAmount(orderBasicInfo); delay商户, 如果存在退款金额, 支付的钱部分解冻(也就是只解冻需要退款的部分), 剩下的钱继续冻结等待第二天凌晨分账
*/
// 执行退款逻辑
delayMerchantOrderRefundLogic(orderBasicInfo, adapayMemberAccount, merchantInfo.getAppId());
} else {
/*
非delay商户, 支付的钱全部解冻后, 更新消费金额和退款金额(只有在线支付才退款, 余额支付退到余额)
*/
notDelayMerchantOrderRefundLogic(orderBasicInfo, adapayMemberAccount, merchantInfo.getAppId());
} }
OrderSettleResult orderSettleResult = null; // OrderSettleResult orderSettleResult = null;
// 退款逻辑/需要退款的情况 // 退款逻辑/需要退款的情况
BigDecimal residue = orderBasicInfo.getRefundAmount(); // BigDecimal residue = orderBasicInfo.getRefundAmount();
if (residue.compareTo(BigDecimal.ZERO) > 0) { // if (residue.compareTo(BigDecimal.ZERO) > 0) {
// 执行退款逻辑 // // 执行退款逻辑
try { // try {
String payMode = orderBasicInfo.getPayMode(); // String payMode = orderBasicInfo.getPayMode();
if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_BALANCE.getValue())) { // if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_BALANCE.getValue())) {
// 余额支付 // // 余额支付
balancePaymentOrderRefundV2(orderBasicInfo); // balancePaymentOrderRefundV2(orderBasicInfo);
} else if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue())) { // } else if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue())) {
// 微信支付 // // 微信支付
onlinePaymentOrderRefund(orderBasicInfo); // onlinePaymentOrderRefund(orderBasicInfo);
} else { // } else {
// 白名单支付 // // 白名单支付
logger.info("订单:{}使用白名单支付,不进行退款处理", orderBasicInfo.getOrderCode()); // logger.info("订单:{}使用白名单支付,不进行退款处理", orderBasicInfo.getOrderCode());
} // }
} catch (Exception e) { // } catch (Exception e) {
logger.error("订单退款逻辑异常orderCode:{}", orderBasicInfo.getOrderCode(), e); // logger.error("订单退款逻辑异常orderCode:{}", orderBasicInfo.getOrderCode(), e);
} // }
} // }
return orderSettleResult; return null;
} }
@@ -827,21 +831,33 @@ public class OrderBasicInfoServiceImpl implements IOrderBasicInfoService {
} }
/** /**
* 延迟商家订单处理逻辑 * 延迟商家订单退款处理逻辑
* 例如:举视以及下面的二级运营商 * 例如:举视以及下面的二级运营商
* * 因为在结算时还没有到分账的时间,先解冻需要退款的金额,并退款
* @param orderBasicInfo 订单信息 * @param orderBasicInfo 订单信息
* @param adapayMemberAccount 汇付用户信息 * @param adapayMemberAccount 汇付用户信息
* @param wechatAppId 小程序appId * @param wechatAppId 小程序appId
* @return
*/ */
private OrderSettleResult delayMerchantOrderProcessingLogic(OrderBasicInfo orderBasicInfo, AdapayMemberAccount adapayMemberAccount, String wechatAppId) { private void delayMerchantOrderRefundLogic(OrderBasicInfo orderBasicInfo, AdapayMemberAccount adapayMemberAccount, String wechatAppId) {
try {
return null; String payMode = orderBasicInfo.getPayMode();
if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_BALANCE.getValue())) {
// 余额支付
balancePaymentOrderRefundV2(orderBasicInfo);
} else if (StringUtils.equals(payMode, OrderPayModeEnum.PAYMENT_OF_WECHATPAY.getValue())) {
// 微信支付
onlinePaymentOrderRefund(orderBasicInfo);
} else {
// 白名单支付
logger.info("订单:{}使用白名单支付,不进行退款处理", orderBasicInfo.getOrderCode());
}
} catch (Exception e) {
logger.error("订单退款逻辑异常orderCode:{}", orderBasicInfo.getOrderCode(), e);
}
} }
/** /**
* 不延迟商家订单处理逻辑 * 不延迟商家订单退款处理逻辑
* 例如:希晓 * 例如:希晓
* 相当于已经分账完成了 * 相当于已经分账完成了
* *
@@ -850,7 +866,7 @@ public class OrderBasicInfoServiceImpl implements IOrderBasicInfoService {
* @param wechatAppId 小程序appId * @param wechatAppId 小程序appId
* @return * @return
*/ */
private OrderSettleResult notDelayMerchantOrderProcessingLogic(OrderBasicInfo orderBasicInfo, AdapayMemberAccount adapayMemberAccount, String wechatAppId) { private OrderSettleResult notDelayMerchantOrderRefundLogic(OrderBasicInfo orderBasicInfo, AdapayMemberAccount adapayMemberAccount, String wechatAppId) {
return null; return null;
} }
@@ -1156,7 +1172,7 @@ public class OrderBasicInfoServiceImpl implements IOrderBasicInfoService {
// 需要退回本金的金额 // 需要退回本金的金额
BigDecimal returnPrincipal = returnAmountMap.get("returnPrincipal"); BigDecimal returnPrincipal = returnAmountMap.get("returnPrincipal");
// 更新会员钱包 // 更新会员钱包/余额退回到钱包
UpdateMemberBalanceDTO updateMemberBalanceDTO = UpdateMemberBalanceDTO.builder() UpdateMemberBalanceDTO updateMemberBalanceDTO = UpdateMemberBalanceDTO.builder()
.memberId(orderBasicInfo.getMemberId()) .memberId(orderBasicInfo.getMemberId())
.type(MemberWalletEnum.TYPE_IN.getValue()) // 进账 .type(MemberWalletEnum.TYPE_IN.getValue()) // 进账
@@ -1166,24 +1182,57 @@ public class OrderBasicInfoServiceImpl implements IOrderBasicInfoService {
.build(); .build();
memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO); memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO);
// TODO 更新member_adapay_record // 更新order_pay_record, 解冻部分
List<Map<String, Object>> list = calculateUnfreezeAmount(orderAmount, payRecordList);
for (Map<String, Object> map : list) {
String paymentId = (String) map.get("paymentId");
String unfreezeAmount = (String) map.get("unfreezeAmount");
memberAdapayRecordService.unfreezeAmount(paymentId, new BigDecimal(unfreezeAmount));
}
}
/**
* 计算解冻金额
* @param orderAmount 订单消费金额
* @param payRecordList 订单支付记录
*/
@Override
public List<Map<String, Object>> calculateUnfreezeAmount(BigDecimal orderAmount, List<OrderPayRecord> payRecordList) {
List<Map<String, Object>> resultList = Lists.newArrayList();
BigDecimal tempAmount = new BigDecimal(orderAmount.toString()); // 临时金额
for (OrderPayRecord record : payRecordList) { for (OrderPayRecord record : payRecordList) {
JSONObject jsonObject = JSON.parseObject(record.getDeductionRecord());
String paymentId = jsonObject.getString("paymentId");
// BigDecimal amount = jsonObject.getBigDecimal("amount");
BigDecimal payAmount = record.getPayAmount(); // 此交易单支付的金额
// 该笔支付扣除金额
BigDecimal deductionAmount;
// 该笔支付解冻金额
BigDecimal unfreezeAmount = null;
// 临时消费金额 = 临时消费金额 - 该笔交易的剩余金额
tempAmount = tempAmount.subtract(payAmount);
if (tempAmount.compareTo(BigDecimal.ZERO) >= 0) {
// 计算以后大于等于0说明这笔支付剩余金额需要扣完还要继续扣下一笔
deductionAmount = payAmount;
unfreezeAmount = payAmount.subtract(deductionAmount); // 支付金额 - 扣除金额 = 需要退回的金额
Map<String, Object> map = Maps.newHashMap();
map.put("paymentId", paymentId);
map.put("unfreezeAmount", unfreezeAmount);
resultList.add(map);
} else {
// 如果小于0则说明该笔交易的剩余金额用不完扣除金额等于临时消费金额并结束循环
deductionAmount = payAmount.add(tempAmount); // 该笔交易的剩余金额加上一个负数临时消费金额,就是该笔交易扣除金额
unfreezeAmount = payAmount.subtract(deductionAmount); // 支付金额 - 扣除金额 = 需要退回的金额
Map<String, Object> map = Maps.newHashMap();
map.put("paymentId", paymentId);
map.put("unfreezeAmount", unfreezeAmount);
resultList.add(map);
break;
} }
// 更新order_pay_record
// 更新订单支付记录
// List<OrderPayRecord> updatePayRecordList = Lists.newArrayList();
// if (returnPrincipal != null && principalPayRecord != null) {
// principalPayRecord.setRefundAmount(returnPrincipal);
// updatePayRecordList.add(principalPayRecord);
// }
// if (CollectionUtils.isNotEmpty(updatePayRecordList)) {
// orderPayRecordService.updateBatch(updatePayRecordList);
// }
} }
return resultList;
}
/** /**
* 订单分账逻辑 * 订单分账逻辑