fix(order): 前置余额扣减并统一金额精度处理,补充余额校验与单测
- 抽取 validateSufficientBalance,统一使用 normalizeMoney 校验与比较,提升健壮性\n- AbstractOrderPlacementStrategy:在创建订单前根据 shouldDeduct 进行余额校验与扣减,使用上下文 orderId 记录流水,避免不一致\n- deductCustomerBalance:使用 amountToDeduct 变量并先归一化后运算,修正可能的精度问题\n- 调整/补充测试用例:扣减失败不插入订单、不保存用户信息;更新 selectById 调用次数校验
This commit is contained in:
@@ -7,6 +7,7 @@ import com.starry.admin.modules.order.module.dto.OrderPlacementCommand;
|
||||
import com.starry.admin.modules.order.module.dto.OrderPlacementResult;
|
||||
import com.starry.admin.modules.order.module.dto.PaymentInfo;
|
||||
import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
abstract class AbstractOrderPlacementStrategy implements OrderPlacementStrategy {
|
||||
|
||||
@@ -26,16 +27,19 @@ abstract class AbstractOrderPlacementStrategy implements OrderPlacementStrategy
|
||||
throw new CustomException("支付信息不能为空");
|
||||
}
|
||||
|
||||
PlayOrderInfoEntity order = service.createOrderRecord(context);
|
||||
|
||||
if (command.isDeductBalance() && service.shouldDeductBalance(context)) {
|
||||
BigDecimal netAmount = service.normalizeMoney(paymentInfo.getFinalAmount());
|
||||
boolean shouldDeduct = command.isDeductBalance() && service.shouldDeductBalance(context);
|
||||
if (shouldDeduct) {
|
||||
service.validateSufficientBalance(context.getPurchaserBy(), netAmount);
|
||||
service.deductCustomerBalance(
|
||||
context.getPurchaserBy(),
|
||||
service.normalizeMoney(paymentInfo.getFinalAmount()),
|
||||
netAmount,
|
||||
command.getBalanceOperationAction(),
|
||||
order.getId());
|
||||
context.getOrderId());
|
||||
}
|
||||
|
||||
PlayOrderInfoEntity order = service.createOrderRecord(context);
|
||||
|
||||
OrderAmountBreakdown amountBreakdown =
|
||||
breakdown != null ? breakdown : service.fallbackBreakdown(paymentInfo);
|
||||
return OrderPlacementResult.of(order, amountBreakdown);
|
||||
|
||||
@@ -162,6 +162,7 @@ public class OrderLifecycleServiceImpl implements IOrderLifecycleService {
|
||||
|
||||
validateCouponUsage(context);
|
||||
|
||||
|
||||
OrderConstant.RewardType rewardType = context.getRewardType() != null
|
||||
? context.getRewardType()
|
||||
: OrderConstant.RewardType.NOT_APPLICABLE;
|
||||
@@ -278,6 +279,18 @@ public class OrderLifecycleServiceImpl implements IOrderLifecycleService {
|
||||
return OrderAmountBreakdown.of(grossAmount, discountAmount, netAmount);
|
||||
}
|
||||
|
||||
void validateSufficientBalance(String customerId, BigDecimal requiredAmount) {
|
||||
PlayCustomUserInfoEntity customer = customUserInfoService.selectById(customerId);
|
||||
if (customer == null) {
|
||||
throw new CustomException("顾客不存在");
|
||||
}
|
||||
BigDecimal before = normalizeMoney(customer.getAccountBalance());
|
||||
BigDecimal required = normalizeMoney(requiredAmount);
|
||||
if (required.compareTo(before) > 0) {
|
||||
throw new ServiceException("余额不足", 998);
|
||||
}
|
||||
}
|
||||
|
||||
void deductCustomerBalance(
|
||||
String customerId,
|
||||
BigDecimal netAmount,
|
||||
@@ -288,10 +301,11 @@ public class OrderLifecycleServiceImpl implements IOrderLifecycleService {
|
||||
throw new CustomException("顾客不存在");
|
||||
}
|
||||
BigDecimal before = normalizeMoney(customer.getAccountBalance());
|
||||
if (netAmount.compareTo(before) > 0) {
|
||||
BigDecimal amountToDeduct = normalizeMoney(netAmount);
|
||||
if (amountToDeduct.compareTo(before) > 0) {
|
||||
throw new ServiceException("余额不足", 998);
|
||||
}
|
||||
BigDecimal after = normalizeMoney(before.subtract(netAmount));
|
||||
BigDecimal after = normalizeMoney(before.subtract(amountToDeduct));
|
||||
String action = StrUtil.isNotBlank(operationAction) ? operationAction : "下单";
|
||||
customUserInfoService.updateAccountBalanceById(
|
||||
customerId,
|
||||
@@ -299,7 +313,7 @@ public class OrderLifecycleServiceImpl implements IOrderLifecycleService {
|
||||
after,
|
||||
BalanceOperationType.CONSUME.getCode(),
|
||||
action,
|
||||
netAmount,
|
||||
amountToDeduct,
|
||||
BigDecimal.ZERO,
|
||||
orderId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user