|
@@ -43,6 +43,45 @@ import java.util.stream.Collectors;
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOrder> implements StoreOrderService {
|
|
public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOrder> implements StoreOrderService {
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 金额验证误差阈值(0.01元)
|
|
|
|
|
+ */
|
|
|
|
|
+ private static final BigDecimal AMOUNT_TOLERANCE = new BigDecimal("0.01");
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 订单金额信息封装类
|
|
|
|
|
+ */
|
|
|
|
|
+ private static class OrderAmountInfo {
|
|
|
|
|
+ private final BigDecimal totalAmount; // 订单总金额(菜品总价)
|
|
|
|
|
+ private final BigDecimal tablewareFee; // 餐具费
|
|
|
|
|
+ private final BigDecimal discountAmount; // 优惠金额
|
|
|
|
|
+ private final BigDecimal payAmount; // 实付金额
|
|
|
|
|
+
|
|
|
|
|
+ public OrderAmountInfo(BigDecimal totalAmount, BigDecimal tablewareFee,
|
|
|
|
|
+ BigDecimal discountAmount, BigDecimal payAmount) {
|
|
|
|
|
+ this.totalAmount = totalAmount;
|
|
|
|
|
+ this.tablewareFee = tablewareFee;
|
|
|
|
|
+ this.discountAmount = discountAmount;
|
|
|
|
|
+ this.payAmount = payAmount;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public BigDecimal getTotalAmount() {
|
|
|
|
|
+ return totalAmount;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public BigDecimal getTablewareFee() {
|
|
|
|
|
+ return tablewareFee;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public BigDecimal getDiscountAmount() {
|
|
|
|
|
+ return discountAmount;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public BigDecimal getPayAmount() {
|
|
|
|
|
+ return payAmount;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private final StoreOrderDetailMapper orderDetailMapper;
|
|
private final StoreOrderDetailMapper orderDetailMapper;
|
|
|
private final StoreTableMapper storeTableMapper;
|
|
private final StoreTableMapper storeTableMapper;
|
|
|
private final StoreTableLogMapper storeTableLogMapper;
|
|
private final StoreTableLogMapper storeTableLogMapper;
|
|
@@ -63,11 +102,9 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
log.info("创建订单, dto={}", dto);
|
|
log.info("创建订单, dto={}", dto);
|
|
|
|
|
|
|
|
// 获取当前用户信息
|
|
// 获取当前用户信息
|
|
|
- Integer userId = TokenUtil.getCurrentUserId();
|
|
|
|
|
- if (userId == null) {
|
|
|
|
|
- throw new RuntimeException("用户未登录");
|
|
|
|
|
- }
|
|
|
|
|
- String userPhone = TokenUtil.getCurrentUserPhone();
|
|
|
|
|
|
|
+ Object[] userInfo = getCurrentUserInfo();
|
|
|
|
|
+ Integer userId = (Integer) userInfo[0];
|
|
|
|
|
+ String userPhone = (String) userInfo[1];
|
|
|
|
|
|
|
|
// 检查订单锁定状态
|
|
// 检查订单锁定状态
|
|
|
Integer lockUserId = orderLockService.checkOrderLock(dto.getTableId());
|
|
Integer lockUserId = orderLockService.checkOrderLock(dto.getTableId());
|
|
@@ -118,16 +155,59 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
throw new RuntimeException("购物车中没有新增商品或商品数量未增加,无法创建订单");
|
|
throw new RuntimeException("购物车中没有新增商品或商品数量未增加,无法创建订单");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 验证优惠券(可选,couponId 可以为 null,不选择优惠券时 discountAmount 为 0)
|
|
|
|
|
- BigDecimal discountAmount = BigDecimal.ZERO;
|
|
|
|
|
|
|
+ // 验证并纠正前端传入的金额(订单总金额、餐具费、优惠金额、实付金额)
|
|
|
|
|
+ OrderAmountInfo amountInfo = validateAndCorrectOrderAmounts(dto, cart, storeInfo, table);
|
|
|
|
|
+
|
|
|
|
|
+ // 使用验证后的金额
|
|
|
|
|
+ BigDecimal totalAmount = amountInfo.getTotalAmount();
|
|
|
|
|
+ BigDecimal tablewareFee = amountInfo.getTablewareFee();
|
|
|
|
|
+ BigDecimal discountAmount = amountInfo.getDiscountAmount();
|
|
|
|
|
+ BigDecimal payAmount = amountInfo.getPayAmount();
|
|
|
|
|
+
|
|
|
|
|
+ // 验证优惠券(可选,couponId 可以为 null)
|
|
|
|
|
+ // 注意:订单总金额、优惠金额、实付金额都由前端计算并传入,后端验证其正确性
|
|
|
|
|
+ LifeDiscountCoupon coupon = null; // 缓存优惠券对象,避免重复查询
|
|
|
|
|
+
|
|
|
if (dto.getCouponId() != null) {
|
|
if (dto.getCouponId() != null) {
|
|
|
- // 检查桌号是否已使用优惠券(考虑换桌情况)
|
|
|
|
|
|
|
+ // 如果使用了优惠券,必须传入优惠金额
|
|
|
|
|
+ if (discountAmount == null || discountAmount.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
|
|
+ throw new RuntimeException("使用优惠券时必须传入优惠金额");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查桌号是否已使用优惠券,如果已使用则替换为新优惠券
|
|
|
if (cartService.hasUsedCoupon(dto.getTableId())) {
|
|
if (cartService.hasUsedCoupon(dto.getTableId())) {
|
|
|
- throw new RuntimeException("该桌已使用优惠券,不能重复使用");
|
|
|
|
|
|
|
+ // 获取旧的优惠券使用记录
|
|
|
|
|
+ LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ oldUsageWrapper.eq(StoreCouponUsage::getTableId, dto.getTableId());
|
|
|
|
|
+ oldUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
|
|
|
|
|
+ oldUsageWrapper.in(StoreCouponUsage::getUsageStatus, 0, 1); // 已标记使用、已下单
|
|
|
|
|
+ oldUsageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
|
|
|
|
|
+ oldUsageWrapper.last("LIMIT 1");
|
|
|
|
|
+ StoreCouponUsage oldUsage = storeCouponUsageMapper.selectOne(oldUsageWrapper);
|
|
|
|
|
+
|
|
|
|
|
+ if (oldUsage != null) {
|
|
|
|
|
+ // 如果旧优惠券已经关联到订单(已下单状态),需要将旧优惠券使用记录状态改为"已取消"
|
|
|
|
|
+ if (oldUsage.getUsageStatus() == 1 && oldUsage.getOrderId() != null) {
|
|
|
|
|
+ oldUsage.setUsageStatus(3); // 已取消
|
|
|
|
|
+ oldUsage.setUpdatedTime(new Date());
|
|
|
|
|
+ storeCouponUsageMapper.updateById(oldUsage);
|
|
|
|
|
+ log.info("替换优惠券:取消旧优惠券使用记录, tableId={}, oldCouponId={}, newCouponId={}",
|
|
|
|
|
+ dto.getTableId(), oldUsage.getCouponId(), dto.getCouponId());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果只是已标记使用但未下单,直接逻辑删除
|
|
|
|
|
+ storeCouponUsageMapper.deleteById(oldUsage.getId());
|
|
|
|
|
+ log.info("替换优惠券:删除未下单的旧优惠券使用记录, tableId={}, oldCouponId={}, newCouponId={}",
|
|
|
|
|
+ dto.getTableId(), oldUsage.getCouponId(), dto.getCouponId());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 清除旧的优惠券使用标记
|
|
|
|
|
+ cartService.clearCouponUsed(dto.getTableId());
|
|
|
|
|
+ log.info("替换优惠券:清除旧优惠券标记, tableId={}, newCouponId={}", dto.getTableId(), dto.getCouponId());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 验证优惠券
|
|
|
|
|
- LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(dto.getCouponId());
|
|
|
|
|
|
|
+ // 验证优惠券(只查询一次)
|
|
|
|
|
+ coupon = lifeDiscountCouponMapper.selectById(dto.getCouponId());
|
|
|
if (coupon == null) {
|
|
if (coupon == null) {
|
|
|
throw new RuntimeException("优惠券不存在");
|
|
throw new RuntimeException("优惠券不存在");
|
|
|
}
|
|
}
|
|
@@ -137,29 +217,47 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
throw new RuntimeException("优惠券不属于该门店");
|
|
throw new RuntimeException("优惠券不属于该门店");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 计算餐具费(从门店信息获取)
|
|
|
|
|
- BigDecimal tablewareFee = calculateTablewareFee(storeInfo, dto.getDinerCount());
|
|
|
|
|
-
|
|
|
|
|
- // 验证最低消费(菜品总价 + 餐具费)
|
|
|
|
|
- BigDecimal totalWithTableware = cart.getTotalAmount().add(tablewareFee);
|
|
|
|
|
- if (coupon.getMinimumSpendingAmount() != null
|
|
|
|
|
- && totalWithTableware.compareTo(coupon.getMinimumSpendingAmount()) < 0) {
|
|
|
|
|
- throw new RuntimeException("订单金额未达到优惠券最低消费要求");
|
|
|
|
|
|
|
+ // 验证前端计算的优惠金额是否合理(防止前端计算错误)
|
|
|
|
|
+ BigDecimal totalWithTableware = totalAmount.add(tablewareFee);
|
|
|
|
|
+ BigDecimal expectedDiscountAmount = calculateDiscountAmount(coupon, totalWithTableware);
|
|
|
|
|
+
|
|
|
|
|
+ // 保存前端传入的实付金额(优先使用前端传入的值)
|
|
|
|
|
+ BigDecimal frontendPayAmount = payAmount;
|
|
|
|
|
+
|
|
|
|
|
+ // 验证并纠正优惠金额
|
|
|
|
|
+ discountAmount = validateAndCorrectAmount(
|
|
|
|
|
+ discountAmount,
|
|
|
|
|
+ expectedDiscountAmount,
|
|
|
|
|
+ "优惠金额"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 如果优惠金额被纠正了,重新计算实付金额用于验证
|
|
|
|
|
+ // 但始终优先使用前端传入的实付金额
|
|
|
|
|
+ BigDecimal recalculatedPayAmount = totalAmount.add(tablewareFee).subtract(discountAmount);
|
|
|
|
|
+ if (frontendPayAmount != null) {
|
|
|
|
|
+ // 如果前端传入了实付金额,验证其是否正确(仅用于记录日志)
|
|
|
|
|
+ BigDecimal payAmountDifference = frontendPayAmount.subtract(recalculatedPayAmount).abs();
|
|
|
|
|
+ if (payAmountDifference.compareTo(AMOUNT_TOLERANCE) > 0) {
|
|
|
|
|
+ log.warn("优惠金额纠正后,前端传入的实付金额与重新计算的不一致, frontend={}, recalculated={}, difference={},将使用前端传入的值",
|
|
|
|
|
+ frontendPayAmount, recalculatedPayAmount, payAmountDifference);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 始终使用前端传入的值
|
|
|
|
|
+ payAmount = frontendPayAmount;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果前端没有传入实付金额,使用重新计算的值
|
|
|
|
|
+ payAmount = recalculatedPayAmount;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
|
|
|
|
|
- discountAmount = calculateDiscountAmount(coupon, totalWithTableware);
|
|
|
|
|
-
|
|
|
|
|
- // 标记桌号已使用优惠券
|
|
|
|
|
|
|
+ // 标记桌号已使用新优惠券
|
|
|
cartService.markCouponUsed(dto.getTableId(), dto.getCouponId());
|
|
cartService.markCouponUsed(dto.getTableId(), dto.getCouponId());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果没有使用优惠券,优惠金额应该为0
|
|
|
|
|
+ if (discountAmount != null && discountAmount.compareTo(BigDecimal.ZERO) != 0) {
|
|
|
|
|
+ throw new RuntimeException("未使用优惠券时,优惠金额必须为0");
|
|
|
|
|
+ }
|
|
|
|
|
+ discountAmount = BigDecimal.ZERO;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 计算餐具费(从门店信息获取)
|
|
|
|
|
- BigDecimal tablewareFee = calculateTablewareFee(storeInfo, dto.getDinerCount());
|
|
|
|
|
-
|
|
|
|
|
- // 计算实付金额(菜品总价 + 餐具费 - 优惠金额)
|
|
|
|
|
- BigDecimal payAmount = cart.getTotalAmount().add(tablewareFee).subtract(discountAmount);
|
|
|
|
|
-
|
|
|
|
|
Date now = new Date();
|
|
Date now = new Date();
|
|
|
StoreOrder order = null;
|
|
StoreOrder order = null;
|
|
|
String orderNo = null;
|
|
String orderNo = null;
|
|
@@ -186,15 +284,15 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
Integer addDishCountBefore = orderDetailMapper.selectCount(checkBeforeAddDishWrapper);
|
|
Integer addDishCountBefore = orderDetailMapper.selectCount(checkBeforeAddDishWrapper);
|
|
|
isFirstAddDish = (addDishCountBefore == null || addDishCountBefore == 0);
|
|
isFirstAddDish = (addDishCountBefore == null || addDishCountBefore == 0);
|
|
|
|
|
|
|
|
- // 更新订单信息
|
|
|
|
|
|
|
+ // 更新订单信息(使用前端计算的金额,但经过后端验证)
|
|
|
order.setDinerCount(dto.getDinerCount());
|
|
order.setDinerCount(dto.getDinerCount());
|
|
|
order.setContactPhone(dto.getContactPhone());
|
|
order.setContactPhone(dto.getContactPhone());
|
|
|
order.setTablewareFee(tablewareFee);
|
|
order.setTablewareFee(tablewareFee);
|
|
|
- order.setTotalAmount(cart.getTotalAmount());
|
|
|
|
|
|
|
+ order.setTotalAmount(totalAmount); // 使用验证后的订单总金额
|
|
|
order.setCouponId(dto.getCouponId());
|
|
order.setCouponId(dto.getCouponId());
|
|
|
order.setCurrentCouponId(dto.getCouponId());
|
|
order.setCurrentCouponId(dto.getCouponId());
|
|
|
- order.setDiscountAmount(discountAmount);
|
|
|
|
|
- order.setPayAmount(payAmount);
|
|
|
|
|
|
|
+ order.setDiscountAmount(discountAmount); // 使用验证后的优惠金额
|
|
|
|
|
+ order.setPayAmount(payAmount); // 使用验证后的实付金额
|
|
|
order.setRemark(dto.getRemark());
|
|
order.setRemark(dto.getRemark());
|
|
|
order.setUpdatedUserId(userId);
|
|
order.setUpdatedUserId(userId);
|
|
|
order.setUpdatedTime(now);
|
|
order.setUpdatedTime(now);
|
|
@@ -234,11 +332,11 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
order.setPayUserId(userId);
|
|
order.setPayUserId(userId);
|
|
|
order.setPayUserPhone(userPhone);
|
|
order.setPayUserPhone(userPhone);
|
|
|
order.setOrderStatus(0); // 待支付
|
|
order.setOrderStatus(0); // 待支付
|
|
|
- order.setTotalAmount(cart.getTotalAmount());
|
|
|
|
|
|
|
+ order.setTotalAmount(totalAmount); // 使用验证后的订单总金额
|
|
|
order.setCouponId(dto.getCouponId());
|
|
order.setCouponId(dto.getCouponId());
|
|
|
order.setCurrentCouponId(dto.getCouponId()); // 记录当前使用的优惠券
|
|
order.setCurrentCouponId(dto.getCouponId()); // 记录当前使用的优惠券
|
|
|
- order.setDiscountAmount(discountAmount);
|
|
|
|
|
- order.setPayAmount(payAmount);
|
|
|
|
|
|
|
+ order.setDiscountAmount(discountAmount); // 使用验证后的优惠金额
|
|
|
|
|
+ order.setPayAmount(payAmount); // 使用验证后的实付金额
|
|
|
|
|
|
|
|
// 如果immediatePay为0,只创建订单不支付;为1则创建订单并支付
|
|
// 如果immediatePay为0,只创建订单不支付;为1则创建订单并支付
|
|
|
// 暂时不实现立即支付,由前端调用支付接口
|
|
// 暂时不实现立即支付,由前端调用支付接口
|
|
@@ -278,13 +376,33 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
usage.setUpdatedTime(new Date());
|
|
usage.setUpdatedTime(new Date());
|
|
|
storeCouponUsageMapper.updateById(usage);
|
|
storeCouponUsageMapper.updateById(usage);
|
|
|
}
|
|
}
|
|
|
- } else if (isUpdate) {
|
|
|
|
|
- // 如果是更新订单且没有使用优惠券,需要清除之前的优惠券使用记录
|
|
|
|
|
- // 这里暂时不处理,因为可能用户只是想更新订单信息,不想改变优惠券
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果是更新订单,且优惠券发生变化,需要处理旧优惠券的使用记录
|
|
|
|
|
+ if (isUpdate && finalOrder.getCouponId() != null &&
|
|
|
|
|
+ (dto.getCouponId() == null || !finalOrder.getCouponId().equals(dto.getCouponId()))) {
|
|
|
|
|
+ // 订单的优惠券被替换或取消,需要将旧优惠券使用记录状态改为"已取消"
|
|
|
|
|
+ LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ oldUsageWrapper.eq(StoreCouponUsage::getOrderId, finalOrder.getId());
|
|
|
|
|
+ oldUsageWrapper.eq(StoreCouponUsage::getCouponId, finalOrder.getCouponId());
|
|
|
|
|
+ oldUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
|
|
|
|
|
+ oldUsageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
|
|
|
|
|
+ oldUsageWrapper.last("LIMIT 1");
|
|
|
|
|
+ StoreCouponUsage oldUsage = storeCouponUsageMapper.selectOne(oldUsageWrapper);
|
|
|
|
|
+ if (oldUsage != null) {
|
|
|
|
|
+ oldUsage.setUsageStatus(3); // 已取消
|
|
|
|
|
+ oldUsage.setUpdatedTime(new Date());
|
|
|
|
|
+ storeCouponUsageMapper.updateById(oldUsage);
|
|
|
|
|
+ log.info("更新订单时替换优惠券:取消旧优惠券使用记录, orderId={}, oldCouponId={}, newCouponId={}",
|
|
|
|
|
+ finalOrder.getId(), finalOrder.getCouponId(), dto.getCouponId());
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 创建订单明细
|
|
// 创建订单明细
|
|
|
// 如果是更新订单,需要判断哪些商品是新增的或数量增加的,标记为加餐
|
|
// 如果是更新订单,需要判断哪些商品是新增的或数量增加的,标记为加餐
|
|
|
|
|
+ // 餐具的特殊ID(用于标识餐具项)
|
|
|
|
|
+ final Integer TABLEWARE_CUISINE_ID = -1;
|
|
|
|
|
+
|
|
|
List<StoreOrderDetail> orderDetails = cart.getItems().stream()
|
|
List<StoreOrderDetail> orderDetails = cart.getItems().stream()
|
|
|
.map(item -> {
|
|
.map(item -> {
|
|
|
StoreOrderDetail detail = new StoreOrderDetail();
|
|
StoreOrderDetail detail = new StoreOrderDetail();
|
|
@@ -292,7 +410,30 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
detail.setOrderNo(finalOrderNo);
|
|
detail.setOrderNo(finalOrderNo);
|
|
|
detail.setCuisineId(item.getCuisineId());
|
|
detail.setCuisineId(item.getCuisineId());
|
|
|
detail.setCuisineName(item.getCuisineName());
|
|
detail.setCuisineName(item.getCuisineName());
|
|
|
- detail.setCuisineType(item.getCuisineType());
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 设置菜品类型:如果为null,根据是否为餐具设置默认值
|
|
|
|
|
+ Integer cuisineType = item.getCuisineType();
|
|
|
|
|
+ if (cuisineType == null) {
|
|
|
|
|
+ // 如果是餐具,设置为0;否则设置为1(默认单品)
|
|
|
|
|
+ if (TABLEWARE_CUISINE_ID.equals(item.getCuisineId())) {
|
|
|
|
|
+ cuisineType = 0; // 0表示餐具
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 尝试从菜品信息中获取,如果获取不到则默认为1(单品)
|
|
|
|
|
+ try {
|
|
|
|
|
+ StoreCuisine cuisine = storeCuisineMapper.selectById(item.getCuisineId());
|
|
|
|
|
+ if (cuisine != null && cuisine.getCuisineType() != null) {
|
|
|
|
|
+ cuisineType = cuisine.getCuisineType();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ cuisineType = 1; // 默认为单品
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("获取菜品类型失败, cuisineId={}, 使用默认值1", item.getCuisineId(), e);
|
|
|
|
|
+ cuisineType = 1; // 默认为单品
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ detail.setCuisineType(cuisineType);
|
|
|
|
|
+
|
|
|
detail.setCuisineImage(item.getCuisineImage());
|
|
detail.setCuisineImage(item.getCuisineImage());
|
|
|
detail.setUnitPrice(item.getUnitPrice());
|
|
detail.setUnitPrice(item.getUnitPrice());
|
|
|
detail.setQuantity(item.getQuantity());
|
|
detail.setQuantity(item.getQuantity());
|
|
@@ -371,10 +512,8 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
log.info("支付订单, orderId={}, payType={}", orderId, payType);
|
|
log.info("支付订单, orderId={}, payType={}", orderId, payType);
|
|
|
|
|
|
|
|
// 获取当前用户信息
|
|
// 获取当前用户信息
|
|
|
- Integer userId = TokenUtil.getCurrentUserId();
|
|
|
|
|
- if (userId == null) {
|
|
|
|
|
- throw new RuntimeException("用户未登录");
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Object[] userInfo = getCurrentUserInfo();
|
|
|
|
|
+ Integer userId = (Integer) userInfo[0];
|
|
|
|
|
|
|
|
// 检查结算锁定状态
|
|
// 检查结算锁定状态
|
|
|
Integer lockUserId = orderLockService.checkSettlementLock(orderId);
|
|
Integer lockUserId = orderLockService.checkSettlementLock(orderId);
|
|
@@ -382,16 +521,38 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
throw new RuntimeException("订单结算已被其他用户锁定,无法支付");
|
|
throw new RuntimeException("订单结算已被其他用户锁定,无法支付");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- StoreOrder order = this.getById(orderId);
|
|
|
|
|
- if (order == null) {
|
|
|
|
|
- throw new RuntimeException("订单不存在");
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 验证订单状态
|
|
|
|
|
+ StoreOrder order = validateOrderForOperation(orderId, 0, "支付");
|
|
|
|
|
|
|
|
- if (order.getOrderStatus() != 0) {
|
|
|
|
|
- throw new RuntimeException("订单状态不正确,无法支付");
|
|
|
|
|
|
|
+ // 支付时重新计算优惠券金额和实付金额(此时订单金额已确定,不会再变化)
|
|
|
|
|
+ BigDecimal discountAmount = BigDecimal.ZERO;
|
|
|
|
|
+ BigDecimal tablewareFee = order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO;
|
|
|
|
|
+ BigDecimal totalAmount = order.getTotalAmount() != null ? order.getTotalAmount() : BigDecimal.ZERO;
|
|
|
|
|
+ BigDecimal totalWithTableware = totalAmount.add(tablewareFee);
|
|
|
|
|
+
|
|
|
|
|
+ if (order.getCouponId() != null) {
|
|
|
|
|
+ // 查询优惠券信息
|
|
|
|
|
+ LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(order.getCouponId());
|
|
|
|
|
+ if (coupon == null) {
|
|
|
|
|
+ throw new RuntimeException("优惠券不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 验证最低消费(菜品总价 + 餐具费)
|
|
|
|
|
+ if (coupon.getMinimumSpendingAmount() != null
|
|
|
|
|
+ && totalWithTableware.compareTo(coupon.getMinimumSpendingAmount()) < 0) {
|
|
|
|
|
+ throw new RuntimeException("订单金额未达到优惠券最低消费要求(" + coupon.getMinimumSpendingAmount() + "元)");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
|
|
|
|
|
+ discountAmount = calculateDiscountAmount(coupon, totalWithTableware);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 这里可以调用支付接口,暂时直接更新为已支付
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 计算实付金额(菜品总价 + 餐具费 - 优惠金额)
|
|
|
|
|
+ BigDecimal payAmount = totalWithTableware.subtract(discountAmount);
|
|
|
|
|
+
|
|
|
|
|
+ // 更新订单信息(包括优惠金额和实付金额)
|
|
|
|
|
+ order.setDiscountAmount(discountAmount);
|
|
|
|
|
+ order.setPayAmount(payAmount);
|
|
|
order.setOrderStatus(1); // 已支付
|
|
order.setOrderStatus(1); // 已支付
|
|
|
order.setPayStatus(1); // 已支付
|
|
order.setPayStatus(1); // 已支付
|
|
|
order.setPayType(payType);
|
|
order.setPayType(payType);
|
|
@@ -418,8 +579,8 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 支付完成后,自动重置餐桌(保留订单数据,只重置餐桌绑定关系和购物车)
|
|
|
|
|
- // resetTableAfterPayment 方法会完全清空购物车,所以不需要单独调用 clearCart
|
|
|
|
|
|
|
+ // 支付完成后,清空购物车和重置餐桌状态(保留订单数据,不删除订单)
|
|
|
|
|
+ // resetTableAfterPayment 方法会清空购物车和重置餐桌状态,但不会删除订单数据
|
|
|
resetTableAfterPayment(order.getTableId());
|
|
resetTableAfterPayment(order.getTableId());
|
|
|
|
|
|
|
|
// 支付订单成功后,自动解锁结算锁定
|
|
// 支付订单成功后,自动解锁结算锁定
|
|
@@ -439,14 +600,8 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
public boolean cancelOrder(Integer orderId) {
|
|
public boolean cancelOrder(Integer orderId) {
|
|
|
log.info("取消订单, orderId={}", orderId);
|
|
log.info("取消订单, orderId={}", orderId);
|
|
|
|
|
|
|
|
- StoreOrder order = this.getById(orderId);
|
|
|
|
|
- if (order == null) {
|
|
|
|
|
- throw new RuntimeException("订单不存在");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (order.getOrderStatus() != 0) {
|
|
|
|
|
- throw new RuntimeException("订单状态不正确,无法取消");
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 验证订单状态
|
|
|
|
|
+ StoreOrder order = validateOrderForOperation(orderId, 0, "取消");
|
|
|
|
|
|
|
|
order.setOrderStatus(2); // 已取消
|
|
order.setOrderStatus(2); // 已取消
|
|
|
order.setUpdatedTime(new Date());
|
|
order.setUpdatedTime(new Date());
|
|
@@ -459,17 +614,27 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
|
|
|
|
|
this.updateById(order);
|
|
this.updateById(order);
|
|
|
|
|
|
|
|
- // 更新桌号状态
|
|
|
|
|
|
|
+ // 恢复购物车的已下单数量(允许重新下单)
|
|
|
|
|
+ cartService.unlockCartItems(order.getTableId());
|
|
|
|
|
+
|
|
|
|
|
+ // 清除优惠券使用标记
|
|
|
|
|
+ cartService.clearCouponUsed(order.getTableId());
|
|
|
|
|
+
|
|
|
|
|
+ // 更新桌号状态(检查购物车是否为空,如果为空则设为空闲)
|
|
|
StoreTable table = storeTableMapper.selectById(order.getTableId());
|
|
StoreTable table = storeTableMapper.selectById(order.getTableId());
|
|
|
if (table != null) {
|
|
if (table != null) {
|
|
|
table.setCurrentOrderId(null);
|
|
table.setCurrentOrderId(null);
|
|
|
- table.setStatus(0); // 空闲
|
|
|
|
|
|
|
+ // 检查购物车是否为空,如果为空则设为空闲
|
|
|
|
|
+ CartDTO cart = cartService.getCart(order.getTableId());
|
|
|
|
|
+ if (cart.getItems() == null || cart.getItems().isEmpty()) {
|
|
|
|
|
+ table.setStatus(0); // 空闲
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 购物车还有商品,保持当前状态或设为就餐中
|
|
|
|
|
+ table.setStatus(1); // 就餐中
|
|
|
|
|
+ }
|
|
|
storeTableMapper.updateById(table);
|
|
storeTableMapper.updateById(table);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 清除优惠券使用标记
|
|
|
|
|
- cartService.clearCouponUsed(order.getTableId());
|
|
|
|
|
-
|
|
|
|
|
log.info("订单取消成功, orderId={}", orderId);
|
|
log.info("订单取消成功, orderId={}", orderId);
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
@@ -676,15 +841,8 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
public StoreOrder addDishToOrder(Integer orderId, Integer cuisineId, Integer quantity, String remark) {
|
|
public StoreOrder addDishToOrder(Integer orderId, Integer cuisineId, Integer quantity, String remark) {
|
|
|
log.info("加餐, orderId={}, cuisineId={}, quantity={}", orderId, cuisineId, quantity);
|
|
log.info("加餐, orderId={}, cuisineId={}, quantity={}", orderId, cuisineId, quantity);
|
|
|
|
|
|
|
|
- // 验证订单
|
|
|
|
|
- StoreOrder order = this.getById(orderId);
|
|
|
|
|
- if (order == null) {
|
|
|
|
|
- throw new RuntimeException("订单不存在");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (order.getOrderStatus() != 0) {
|
|
|
|
|
- throw new RuntimeException("订单状态不正确,无法加餐");
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 验证订单状态
|
|
|
|
|
+ StoreOrder order = validateOrderForOperation(orderId, 0, "加餐");
|
|
|
|
|
|
|
|
// 验证菜品
|
|
// 验证菜品
|
|
|
StoreCuisine cuisine = storeCuisineMapper.selectById(cuisineId);
|
|
StoreCuisine cuisine = storeCuisineMapper.selectById(cuisineId);
|
|
@@ -696,8 +854,9 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 获取当前用户信息
|
|
// 获取当前用户信息
|
|
|
- Integer userId = TokenUtil.getCurrentUserId();
|
|
|
|
|
- String userPhone = TokenUtil.getCurrentUserPhone();
|
|
|
|
|
|
|
+ Object[] userInfo = getCurrentUserInfo();
|
|
|
|
|
+ Integer userId = (Integer) userInfo[0];
|
|
|
|
|
+ String userPhone = (String) userInfo[1];
|
|
|
|
|
|
|
|
// 在加餐之前,检查订单明细中是否已经有 is_add_dish=1 的记录
|
|
// 在加餐之前,检查订单明细中是否已经有 is_add_dish=1 的记录
|
|
|
// 如果没有,说明这是首次加餐(首次订单发生变化)
|
|
// 如果没有,说明这是首次加餐(首次订单发生变化)
|
|
@@ -717,10 +876,13 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
|
|
|
|
|
Date now = new Date();
|
|
Date now = new Date();
|
|
|
Integer quantityBefore = 0; // 加餐前的数量(用于记录变更日志)
|
|
Integer quantityBefore = 0; // 加餐前的数量(用于记录变更日志)
|
|
|
|
|
+ BigDecimal addAmount; // 新增的金额
|
|
|
|
|
|
|
|
if (existingDetail != null) {
|
|
if (existingDetail != null) {
|
|
|
// 记录加餐前的数量
|
|
// 记录加餐前的数量
|
|
|
quantityBefore = existingDetail.getQuantity();
|
|
quantityBefore = existingDetail.getQuantity();
|
|
|
|
|
+ // 计算新增金额(单价 * 新增数量)
|
|
|
|
|
+ addAmount = existingDetail.getUnitPrice().multiply(BigDecimal.valueOf(quantity));
|
|
|
// 更新数量
|
|
// 更新数量
|
|
|
existingDetail.setQuantity(existingDetail.getQuantity() + quantity);
|
|
existingDetail.setQuantity(existingDetail.getQuantity() + quantity);
|
|
|
existingDetail.setSubtotalAmount(existingDetail.getUnitPrice()
|
|
existingDetail.setSubtotalAmount(existingDetail.getUnitPrice()
|
|
@@ -739,40 +901,44 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
} else {
|
|
} else {
|
|
|
// 添加新菜品(加餐)
|
|
// 添加新菜品(加餐)
|
|
|
quantityBefore = 0; // 新菜品,加餐前数量为0
|
|
quantityBefore = 0; // 新菜品,加餐前数量为0
|
|
|
|
|
+ // 计算新增金额(单价 * 数量)
|
|
|
|
|
+ addAmount = cuisine.getTotalPrice().multiply(BigDecimal.valueOf(quantity));
|
|
|
StoreOrderDetail detail = new StoreOrderDetail();
|
|
StoreOrderDetail detail = new StoreOrderDetail();
|
|
|
detail.setOrderId(orderId);
|
|
detail.setOrderId(orderId);
|
|
|
detail.setOrderNo(order.getOrderNo());
|
|
detail.setOrderNo(order.getOrderNo());
|
|
|
detail.setCuisineId(cuisine.getId());
|
|
detail.setCuisineId(cuisine.getId());
|
|
|
detail.setCuisineName(cuisine.getName());
|
|
detail.setCuisineName(cuisine.getName());
|
|
|
- detail.setCuisineType(cuisine.getCuisineType());
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 设置菜品类型:如果为null,默认为1(单品)
|
|
|
|
|
+ Integer cuisineType = cuisine.getCuisineType();
|
|
|
|
|
+ if (cuisineType == null) {
|
|
|
|
|
+ cuisineType = 1; // 默认为单品
|
|
|
|
|
+ log.warn("菜品类型为null,使用默认值1, cuisineId={}", cuisine.getId());
|
|
|
|
|
+ }
|
|
|
|
|
+ detail.setCuisineType(cuisineType);
|
|
|
|
|
+
|
|
|
detail.setCuisineImage(cuisine.getImages());
|
|
detail.setCuisineImage(cuisine.getImages());
|
|
|
detail.setUnitPrice(cuisine.getTotalPrice());
|
|
detail.setUnitPrice(cuisine.getTotalPrice());
|
|
|
detail.setQuantity(quantity);
|
|
detail.setQuantity(quantity);
|
|
|
- detail.setSubtotalAmount(cuisine.getTotalPrice().multiply(BigDecimal.valueOf(quantity)));
|
|
|
|
|
|
|
+ detail.setSubtotalAmount(addAmount);
|
|
|
detail.setAddUserId(userId);
|
|
detail.setAddUserId(userId);
|
|
|
detail.setAddUserPhone(userPhone);
|
|
detail.setAddUserPhone(userPhone);
|
|
|
detail.setIsAddDish(1); // 标记为加餐
|
|
detail.setIsAddDish(1); // 标记为加餐
|
|
|
detail.setAddDishTime(now);
|
|
detail.setAddDishTime(now);
|
|
|
detail.setRemark(remark);
|
|
detail.setRemark(remark);
|
|
|
detail.setCreatedUserId(userId);
|
|
detail.setCreatedUserId(userId);
|
|
|
|
|
+ detail.setCreatedTime(now);
|
|
|
|
|
+ detail.setUpdatedTime(now);
|
|
|
orderDetailMapper.insert(detail);
|
|
orderDetailMapper.insert(detail);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 重新计算订单总金额
|
|
|
|
|
- LambdaQueryWrapper<StoreOrderDetail> allDetailWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
- allDetailWrapper.eq(StoreOrderDetail::getOrderId, orderId);
|
|
|
|
|
- allDetailWrapper.eq(StoreOrderDetail::getDeleteFlag, 0);
|
|
|
|
|
- List<StoreOrderDetail> allDetails = orderDetailMapper.selectList(allDetailWrapper);
|
|
|
|
|
- BigDecimal newTotalAmount = allDetails.stream()
|
|
|
|
|
- .map(StoreOrderDetail::getSubtotalAmount)
|
|
|
|
|
- .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
-
|
|
|
|
|
- // 重新计算实付金额(菜品总价 + 餐具费 - 优惠金额)
|
|
|
|
|
- BigDecimal newPayAmount = newTotalAmount.add(order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO)
|
|
|
|
|
- .subtract(order.getDiscountAmount() != null ? order.getDiscountAmount() : BigDecimal.ZERO);
|
|
|
|
|
|
|
+ // 增量计算订单总金额(避免重新查询所有订单明细)
|
|
|
|
|
+ BigDecimal newTotalAmount = order.getTotalAmount().add(addAmount);
|
|
|
|
|
|
|
|
|
|
+ // 加餐时只更新订单总金额,不计算优惠金额和实付金额(因为可能还会继续加菜,支付时再统一计算)
|
|
|
|
|
+ // 如果订单使用了优惠券,不验证最低消费(因为可能还会继续加菜,支付时再验证)
|
|
|
order.setTotalAmount(newTotalAmount);
|
|
order.setTotalAmount(newTotalAmount);
|
|
|
- order.setPayAmount(newPayAmount);
|
|
|
|
|
|
|
+ // order.setDiscountAmount 和 order.setPayAmount 保持不变,支付时再计算
|
|
|
order.setUpdatedTime(new Date());
|
|
order.setUpdatedTime(new Date());
|
|
|
order.setUpdatedUserId(userId);
|
|
order.setUpdatedUserId(userId);
|
|
|
this.updateById(order);
|
|
this.updateById(order);
|
|
@@ -856,18 +1022,45 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
- public StoreOrder updateOrderCoupon(Integer orderId, Integer couponId) {
|
|
|
|
|
- log.info("更新订单优惠券, orderId={}, couponId={}", orderId, couponId);
|
|
|
|
|
|
|
+ public boolean completeOrderByMerchant(Integer orderId) {
|
|
|
|
|
+ log.info("商家手动完成订单, orderId={}", orderId);
|
|
|
|
|
|
|
|
StoreOrder order = this.getById(orderId);
|
|
StoreOrder order = this.getById(orderId);
|
|
|
if (order == null) {
|
|
if (order == null) {
|
|
|
throw new RuntimeException("订单不存在");
|
|
throw new RuntimeException("订单不存在");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (order.getOrderStatus() != 0) {
|
|
|
|
|
- throw new RuntimeException("订单状态不正确,无法修改优惠券");
|
|
|
|
|
|
|
+ // 商家手动完成订单,不校验支付状态,直接设置为已完成
|
|
|
|
|
+ order.setOrderStatus(3); // 已完成
|
|
|
|
|
+ order.setUpdatedTime(new Date());
|
|
|
|
|
+
|
|
|
|
|
+ // 从 token 获取用户信息
|
|
|
|
|
+ Integer userId = TokenUtil.getCurrentUserId();
|
|
|
|
|
+ if (userId != null) {
|
|
|
|
|
+ order.setUpdatedUserId(userId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.updateById(order);
|
|
|
|
|
+
|
|
|
|
|
+ // 更新桌号状态
|
|
|
|
|
+ StoreTable table = storeTableMapper.selectById(order.getTableId());
|
|
|
|
|
+ if (table != null) {
|
|
|
|
|
+ table.setCurrentOrderId(null);
|
|
|
|
|
+ table.setStatus(0); // 空闲
|
|
|
|
|
+ storeTableMapper.updateById(table);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ log.info("商家手动完成订单成功, orderId={}", orderId);
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public StoreOrder updateOrderCoupon(Integer orderId, Integer couponId) {
|
|
|
|
|
+ log.info("更新订单优惠券, orderId={}, couponId={}", orderId, couponId);
|
|
|
|
|
+
|
|
|
|
|
+ // 验证订单状态
|
|
|
|
|
+ StoreOrder order = validateOrderForOperation(orderId, 0, "修改优惠券");
|
|
|
|
|
+
|
|
|
BigDecimal discountAmount = BigDecimal.ZERO;
|
|
BigDecimal discountAmount = BigDecimal.ZERO;
|
|
|
|
|
|
|
|
if (couponId != null) {
|
|
if (couponId != null) {
|
|
@@ -889,16 +1082,15 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
throw new RuntimeException("订单金额未达到优惠券最低消费要求");
|
|
throw new RuntimeException("订单金额未达到优惠券最低消费要求");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 计算优惠金额
|
|
|
|
|
- discountAmount = coupon.getNominalValue();
|
|
|
|
|
- BigDecimal totalAmount = totalWithTableware;
|
|
|
|
|
- if (discountAmount.compareTo(totalAmount) > 0) {
|
|
|
|
|
- discountAmount = totalAmount;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
|
|
|
|
|
+ discountAmount = calculateDiscountAmount(coupon, totalWithTableware);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 如果之前有优惠券,更新使用记录状态为已取消
|
|
|
|
|
|
|
+ // 如果之前有优惠券,且优惠券发生变化(包括取消优惠券),需要处理旧优惠券使用记录
|
|
|
if (order.getCouponId() != null && (couponId == null || !order.getCouponId().equals(couponId))) {
|
|
if (order.getCouponId() != null && (couponId == null || !order.getCouponId().equals(couponId))) {
|
|
|
|
|
+ // 清除旧优惠券的使用标记(如果取消优惠券或更换优惠券)
|
|
|
|
|
+ cartService.clearCouponUsed(order.getTableId());
|
|
|
|
|
+
|
|
|
LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
|
|
LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
|
|
|
oldUsageWrapper.eq(StoreCouponUsage::getOrderId, orderId);
|
|
oldUsageWrapper.eq(StoreCouponUsage::getOrderId, orderId);
|
|
|
oldUsageWrapper.eq(StoreCouponUsage::getCouponId, order.getCouponId());
|
|
oldUsageWrapper.eq(StoreCouponUsage::getCouponId, order.getCouponId());
|
|
@@ -913,8 +1105,12 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 如果新设置了优惠券,更新或创建使用记录
|
|
|
|
|
|
|
+ // 如果新设置了优惠券,需要标记桌号已使用优惠券,并更新或创建使用记录
|
|
|
if (couponId != null) {
|
|
if (couponId != null) {
|
|
|
|
|
+ // 检查桌号是否已使用优惠券(如果更换优惠券,之前的标记已清除)
|
|
|
|
|
+ if (!cartService.hasUsedCoupon(order.getTableId())) {
|
|
|
|
|
+ cartService.markCouponUsed(order.getTableId(), couponId);
|
|
|
|
|
+ }
|
|
|
LambdaQueryWrapper<StoreCouponUsage> usageWrapper = new LambdaQueryWrapper<>();
|
|
LambdaQueryWrapper<StoreCouponUsage> usageWrapper = new LambdaQueryWrapper<>();
|
|
|
usageWrapper.eq(StoreCouponUsage::getTableId, order.getTableId());
|
|
usageWrapper.eq(StoreCouponUsage::getTableId, order.getTableId());
|
|
|
usageWrapper.eq(StoreCouponUsage::getCouponId, couponId);
|
|
usageWrapper.eq(StoreCouponUsage::getCouponId, couponId);
|
|
@@ -932,6 +1128,7 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
// 创建新的使用记录
|
|
// 创建新的使用记录
|
|
|
StoreTable table = storeTableMapper.selectById(order.getTableId());
|
|
StoreTable table = storeTableMapper.selectById(order.getTableId());
|
|
|
if (table != null) {
|
|
if (table != null) {
|
|
|
|
|
+ Date now = new Date();
|
|
|
StoreCouponUsage newUsage = new StoreCouponUsage();
|
|
StoreCouponUsage newUsage = new StoreCouponUsage();
|
|
|
newUsage.setTableId(order.getTableId());
|
|
newUsage.setTableId(order.getTableId());
|
|
|
newUsage.setStoreId(order.getStoreId());
|
|
newUsage.setStoreId(order.getStoreId());
|
|
@@ -939,7 +1136,8 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
newUsage.setCouponId(couponId);
|
|
newUsage.setCouponId(couponId);
|
|
|
newUsage.setDiscountAmount(discountAmount);
|
|
newUsage.setDiscountAmount(discountAmount);
|
|
|
newUsage.setUsageStatus(1); // 已下单
|
|
newUsage.setUsageStatus(1); // 已下单
|
|
|
- newUsage.setCreatedTime(new Date());
|
|
|
|
|
|
|
+ newUsage.setCreatedTime(now);
|
|
|
|
|
+ newUsage.setUpdatedTime(now); // 设置更新时间,避免数据库约束错误
|
|
|
Integer userId = TokenUtil.getCurrentUserId();
|
|
Integer userId = TokenUtil.getCurrentUserId();
|
|
|
if (userId != null) {
|
|
if (userId != null) {
|
|
|
newUsage.setCreatedUserId(userId);
|
|
newUsage.setCreatedUserId(userId);
|
|
@@ -995,13 +1193,17 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
log.info("删除购物车数据, tableId={}, count={}", tableId, cartList.size());
|
|
log.info("删除购物车数据, tableId={}, count={}", tableId, cartList.size());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 2. 删除订单数据(逻辑删除,包括订单明细)
|
|
|
|
|
|
|
+ // 2. 只删除未支付或已取消的订单(保留已支付/已完成的订单,避免数据丢失)
|
|
|
|
|
+ // 订单状态:0-待支付,1-已支付,2-已取消,3-已完成
|
|
|
LambdaQueryWrapper<StoreOrder> orderWrapper = new LambdaQueryWrapper<>();
|
|
LambdaQueryWrapper<StoreOrder> orderWrapper = new LambdaQueryWrapper<>();
|
|
|
orderWrapper.eq(StoreOrder::getTableId, tableId);
|
|
orderWrapper.eq(StoreOrder::getTableId, tableId);
|
|
|
orderWrapper.eq(StoreOrder::getDeleteFlag, 0);
|
|
orderWrapper.eq(StoreOrder::getDeleteFlag, 0);
|
|
|
|
|
+ // 只查询未支付(0)或已取消(2)的订单
|
|
|
|
|
+ orderWrapper.in(StoreOrder::getOrderStatus, 0, 2);
|
|
|
List<StoreOrder> orderList = this.list(orderWrapper);
|
|
List<StoreOrder> orderList = this.list(orderWrapper);
|
|
|
|
|
+ List<Integer> orderIds = new ArrayList<>();
|
|
|
if (orderList != null && !orderList.isEmpty()) {
|
|
if (orderList != null && !orderList.isEmpty()) {
|
|
|
- List<Integer> orderIds = orderList.stream()
|
|
|
|
|
|
|
+ orderIds = orderList.stream()
|
|
|
.map(StoreOrder::getId)
|
|
.map(StoreOrder::getId)
|
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
@@ -1040,19 +1242,80 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
// 删除订单(逻辑删除,使用 MyBatis-Plus 的 removeByIds)
|
|
// 删除订单(逻辑删除,使用 MyBatis-Plus 的 removeByIds)
|
|
|
// 使用 removeByIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
|
|
// 使用 removeByIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
|
|
|
this.removeByIds(orderIds);
|
|
this.removeByIds(orderIds);
|
|
|
- log.info("删除订单数据, tableId={}, count={}", tableId, orderList.size());
|
|
|
|
|
|
|
+ log.info("删除未支付/已取消订单数据, tableId={}, count={}", tableId, orderList.size());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 3. 清空Redis中的购物车缓存
|
|
|
|
|
|
|
+ // 查询该桌号的所有订单(包括已支付/已完成的),用于后续处理锁定记录
|
|
|
|
|
+ LambdaQueryWrapper<StoreOrder> allOrderWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ allOrderWrapper.eq(StoreOrder::getTableId, tableId);
|
|
|
|
|
+ allOrderWrapper.eq(StoreOrder::getDeleteFlag, 0);
|
|
|
|
|
+ List<StoreOrder> allOrderList = this.list(allOrderWrapper);
|
|
|
|
|
+ List<Integer> allOrderIds = new ArrayList<>();
|
|
|
|
|
+ if (allOrderList != null && !allOrderList.isEmpty()) {
|
|
|
|
|
+ allOrderIds = allOrderList.stream()
|
|
|
|
|
+ .map(StoreOrder::getId)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 只删除未下单的优惠券使用记录(保留已下单/已支付的记录,避免数据丢失)
|
|
|
|
|
+ // usageStatus: 0-已标记使用, 1-已下单, 2-已支付, 3-已取消
|
|
|
|
|
+ LambdaQueryWrapper<StoreCouponUsage> couponUsageWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ couponUsageWrapper.eq(StoreCouponUsage::getTableId, tableId);
|
|
|
|
|
+ couponUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
|
|
|
|
|
+ // 只删除已标记使用但未下单的记录(usageStatus=0)
|
|
|
|
|
+ couponUsageWrapper.eq(StoreCouponUsage::getUsageStatus, 0);
|
|
|
|
|
+ List<StoreCouponUsage> couponUsageList = storeCouponUsageMapper.selectList(couponUsageWrapper);
|
|
|
|
|
+ if (couponUsageList != null && !couponUsageList.isEmpty()) {
|
|
|
|
|
+ List<Integer> couponUsageIds = couponUsageList.stream()
|
|
|
|
|
+ .map(StoreCouponUsage::getId)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ // 使用 deleteBatchIds 进行逻辑删除(MyBatis-Plus 会自动处理 @TableLogic)
|
|
|
|
|
+ storeCouponUsageMapper.deleteBatchIds(couponUsageIds);
|
|
|
|
|
+ log.info("删除未下单的优惠券使用记录, tableId={}, count={}", tableId, couponUsageList.size());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 删除该桌号的所有订单锁定记录(逻辑删除)
|
|
|
|
|
+ // 包括下单锁定(lock_type=1,通过 tableId 查找)和结算锁定(lock_type=2,通过订单ID关联)
|
|
|
|
|
+
|
|
|
|
|
+ // 删除下单锁定(通过 tableId 查找)
|
|
|
|
|
+ LambdaQueryWrapper<StoreOrderLock> tableLockWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ tableLockWrapper.eq(StoreOrderLock::getTableId, tableId);
|
|
|
|
|
+ tableLockWrapper.eq(StoreOrderLock::getDeleteFlag, 0);
|
|
|
|
|
+ List<StoreOrderLock> tableLockList = storeOrderLockMapper.selectList(tableLockWrapper);
|
|
|
|
|
+ if (tableLockList != null && !tableLockList.isEmpty()) {
|
|
|
|
|
+ List<Integer> tableLockIds = tableLockList.stream()
|
|
|
|
|
+ .map(StoreOrderLock::getId)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ storeOrderLockMapper.deleteBatchIds(tableLockIds);
|
|
|
|
|
+ log.info("删除下单锁定记录, tableId={}, count={}", tableId, tableLockList.size());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 删除结算锁定(通过 orderId 查找,如果有订单的话)
|
|
|
|
|
+ // 注意:这里使用 allOrderIds,包括所有订单(已删除和未删除的),因为锁定记录可能关联已支付的订单
|
|
|
|
|
+ if (!allOrderIds.isEmpty()) {
|
|
|
|
|
+ LambdaQueryWrapper<StoreOrderLock> orderLockWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ orderLockWrapper.in(StoreOrderLock::getOrderId, allOrderIds);
|
|
|
|
|
+ orderLockWrapper.eq(StoreOrderLock::getDeleteFlag, 0);
|
|
|
|
|
+ List<StoreOrderLock> orderLockList = storeOrderLockMapper.selectList(orderLockWrapper);
|
|
|
|
|
+ if (orderLockList != null && !orderLockList.isEmpty()) {
|
|
|
|
|
+ List<Integer> orderLockIds = orderLockList.stream()
|
|
|
|
|
+ .map(StoreOrderLock::getId)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ storeOrderLockMapper.deleteBatchIds(orderLockIds);
|
|
|
|
|
+ log.info("删除结算锁定记录, orderIds={}, count={}", allOrderIds, orderLockList.size());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 清空Redis中的购物车缓存
|
|
|
String cartKey = "cart:table:" + tableId;
|
|
String cartKey = "cart:table:" + tableId;
|
|
|
baseRedisService.delete(cartKey);
|
|
baseRedisService.delete(cartKey);
|
|
|
log.info("清空Redis购物车缓存, tableId={}", tableId);
|
|
log.info("清空Redis购物车缓存, tableId={}", tableId);
|
|
|
|
|
|
|
|
- // 4. 清除优惠券使用标记
|
|
|
|
|
|
|
+ // 6. 清除优惠券使用标记(Redis中的标记)
|
|
|
cartService.clearCouponUsed(tableId);
|
|
cartService.clearCouponUsed(tableId);
|
|
|
log.info("清除优惠券使用标记, tableId={}", tableId);
|
|
log.info("清除优惠券使用标记, tableId={}", tableId);
|
|
|
|
|
|
|
|
- // 5. 重置餐桌表(使用 LambdaUpdateWrapper 来显式设置 null 值)
|
|
|
|
|
|
|
+ // 7. 重置餐桌表(使用 LambdaUpdateWrapper 来显式设置 null 值)
|
|
|
LambdaUpdateWrapper<StoreTable> updateWrapper = new LambdaUpdateWrapper<>();
|
|
LambdaUpdateWrapper<StoreTable> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
updateWrapper.eq(StoreTable::getId, tableId)
|
|
updateWrapper.eq(StoreTable::getId, tableId)
|
|
|
.set(StoreTable::getCurrentOrderId, null) // 显式设置 null
|
|
.set(StoreTable::getCurrentOrderId, null) // 显式设置 null
|
|
@@ -1278,10 +1541,18 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
|
|
|
|
|
// 4. 查询优惠券信息(如果有)
|
|
// 4. 查询优惠券信息(如果有)
|
|
|
String couponName = null;
|
|
String couponName = null;
|
|
|
|
|
+ Integer couponType = null;
|
|
|
|
|
+ BigDecimal discountRate = null;
|
|
|
|
|
+ BigDecimal nominalValue = null;
|
|
|
|
|
+ BigDecimal minimumSpendingAmount = null;
|
|
|
if (order.getCouponId() != null) {
|
|
if (order.getCouponId() != null) {
|
|
|
LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(order.getCouponId());
|
|
LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(order.getCouponId());
|
|
|
if (coupon != null) {
|
|
if (coupon != null) {
|
|
|
couponName = coupon.getName();
|
|
couponName = coupon.getName();
|
|
|
|
|
+ couponType = coupon.getCouponType();
|
|
|
|
|
+ discountRate = coupon.getDiscountRate();
|
|
|
|
|
+ nominalValue = coupon.getNominalValue();
|
|
|
|
|
+ minimumSpendingAmount = coupon.getMinimumSpendingAmount();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1305,6 +1576,10 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
vo.setTablewareFee(order.getTablewareFee());
|
|
vo.setTablewareFee(order.getTablewareFee());
|
|
|
vo.setCouponId(order.getCouponId());
|
|
vo.setCouponId(order.getCouponId());
|
|
|
vo.setCouponName(couponName);
|
|
vo.setCouponName(couponName);
|
|
|
|
|
+ vo.setCouponType(couponType);
|
|
|
|
|
+ vo.setDiscountRate(discountRate);
|
|
|
|
|
+ vo.setNominalValue(nominalValue);
|
|
|
|
|
+ vo.setMinimumSpendingAmount(minimumSpendingAmount);
|
|
|
vo.setDiscountAmount(order.getDiscountAmount());
|
|
vo.setDiscountAmount(order.getDiscountAmount());
|
|
|
vo.setPayAmount(order.getPayAmount());
|
|
vo.setPayAmount(order.getPayAmount());
|
|
|
vo.setOrderStatus(order.getOrderStatus());
|
|
vo.setOrderStatus(order.getOrderStatus());
|
|
@@ -1561,8 +1836,10 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
changeLogs.add(changeLog);
|
|
changeLogs.add(changeLog);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 批量插入变更记录
|
|
|
|
|
|
|
+ // 批量插入变更记录(使用 MyBatis-Plus 的批量插入)
|
|
|
if (!changeLogs.isEmpty()) {
|
|
if (!changeLogs.isEmpty()) {
|
|
|
|
|
+ // 使用循环插入(MyBatis-Plus 的 BaseMapper 没有批量插入方法,需要手动实现或使用 ServiceImpl 的 saveBatch)
|
|
|
|
|
+ // 注意:如果变更记录数量很大,可以考虑使用 MyBatis 的批量插入
|
|
|
for (StoreOrderChangeLog log : changeLogs) {
|
|
for (StoreOrderChangeLog log : changeLogs) {
|
|
|
orderChangeLogMapper.insert(log);
|
|
orderChangeLogMapper.insert(log);
|
|
|
}
|
|
}
|
|
@@ -1762,6 +2039,39 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
|
|
+ * 验证订单是否存在且状态正确(用于支付、取消、加餐、更新优惠券等操作)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param orderId 订单ID
|
|
|
|
|
+ * @param expectedStatus 期望的订单状态(null表示不校验状态)
|
|
|
|
|
+ * @param operation 操作名称(用于错误提示)
|
|
|
|
|
+ * @return 订单对象
|
|
|
|
|
+ */
|
|
|
|
|
+ private StoreOrder validateOrderForOperation(Integer orderId, Integer expectedStatus, String operation) {
|
|
|
|
|
+ StoreOrder order = this.getById(orderId);
|
|
|
|
|
+ if (order == null) {
|
|
|
|
|
+ throw new RuntimeException("订单不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (expectedStatus != null && order.getOrderStatus() != expectedStatus) {
|
|
|
|
|
+ throw new RuntimeException("订单状态不正确,无法" + operation);
|
|
|
|
|
+ }
|
|
|
|
|
+ return order;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取当前登录用户信息
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return 用户ID和手机号的数组 [userId, userPhone]
|
|
|
|
|
+ */
|
|
|
|
|
+ private Object[] getCurrentUserInfo() {
|
|
|
|
|
+ Integer userId = TokenUtil.getCurrentUserId();
|
|
|
|
|
+ String userPhone = TokenUtil.getCurrentUserPhone();
|
|
|
|
|
+ if (userId == null) {
|
|
|
|
|
+ throw new RuntimeException("用户未登录");
|
|
|
|
|
+ }
|
|
|
|
|
+ return new Object[]{userId, userPhone};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
* 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
|
|
* 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
|
|
|
*
|
|
*
|
|
|
* @param coupon 优惠券对象
|
|
* @param coupon 优惠券对象
|
|
@@ -1800,4 +2110,95 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
|
|
|
|
|
return discountAmount;
|
|
return discountAmount;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 验证并纠正前端传入的订单金额
|
|
|
|
|
+ * 包括:订单总金额、餐具费、优惠金额、实付金额
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param dto 创建订单DTO
|
|
|
|
|
+ * @param cart 购物车信息
|
|
|
|
|
+ * @param storeInfo 门店信息
|
|
|
|
|
+ * @param table 餐桌信息
|
|
|
|
|
+ * @return 验证并纠正后的订单金额信息
|
|
|
|
|
+ */
|
|
|
|
|
+ private OrderAmountInfo validateAndCorrectOrderAmounts(
|
|
|
|
|
+ CreateOrderDTO dto,
|
|
|
|
|
+ CartDTO cart,
|
|
|
|
|
+ StoreInfo storeInfo,
|
|
|
|
|
+ StoreTable table) {
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 获取前端传入的金额(如果为null则使用默认值)
|
|
|
|
|
+ BigDecimal frontendTotalAmount = dto.getTotalAmount() != null
|
|
|
|
|
+ ? dto.getTotalAmount()
|
|
|
|
|
+ : cart.getTotalAmount();
|
|
|
|
|
+ BigDecimal frontendTablewareFee = dto.getTablewareFee() != null
|
|
|
|
|
+ ? dto.getTablewareFee()
|
|
|
|
|
+ : BigDecimal.ZERO;
|
|
|
|
|
+ BigDecimal frontendDiscountAmount = dto.getDiscountAmount() != null
|
|
|
|
|
+ ? dto.getDiscountAmount()
|
|
|
|
|
+ : BigDecimal.ZERO;
|
|
|
|
|
+ BigDecimal frontendPayAmount = dto.getPayAmount();
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 计算后端验证值
|
|
|
|
|
+ BigDecimal backendTotalAmount = cart.getTotalAmount();
|
|
|
|
|
+ BigDecimal backendTablewareFee = calculateTablewareFee(storeInfo, dto.getDinerCount());
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 验证并纠正订单总金额
|
|
|
|
|
+ BigDecimal totalAmount = validateAndCorrectAmount(
|
|
|
|
|
+ frontendTotalAmount,
|
|
|
|
|
+ backendTotalAmount,
|
|
|
|
|
+ "订单总金额"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 验证并纠正餐具费
|
|
|
|
|
+ BigDecimal tablewareFee = validateAndCorrectAmount(
|
|
|
|
|
+ frontendTablewareFee,
|
|
|
|
|
+ backendTablewareFee,
|
|
|
|
|
+ "餐具费"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 计算期望的实付金额(订单总金额 + 餐具费 - 优惠金额)
|
|
|
|
|
+ BigDecimal expectedPayAmount = totalAmount.add(tablewareFee).subtract(frontendDiscountAmount);
|
|
|
|
|
+
|
|
|
|
|
+ // 6. 验证并纠正实付金额
|
|
|
|
|
+ BigDecimal payAmount = frontendPayAmount != null
|
|
|
|
|
+ ? validateAndCorrectAmount(frontendPayAmount, expectedPayAmount, "实付金额")
|
|
|
|
|
+ : expectedPayAmount;
|
|
|
|
|
+
|
|
|
|
|
+ // 7. 返回验证后的金额信息
|
|
|
|
|
+ return new OrderAmountInfo(totalAmount, tablewareFee, frontendDiscountAmount, payAmount);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 验证并纠正金额
|
|
|
|
|
+ * 如果前端金额与后端计算金额的误差超过阈值,则使用后端计算的金额
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param frontendAmount 前端传入的金额
|
|
|
|
|
+ * @param backendAmount 后端计算的金额
|
|
|
|
|
+ * @param amountName 金额名称(用于日志)
|
|
|
|
|
+ * @return 验证并纠正后的金额
|
|
|
|
|
+ */
|
|
|
|
|
+ private BigDecimal validateAndCorrectAmount(
|
|
|
|
|
+ BigDecimal frontendAmount,
|
|
|
|
|
+ BigDecimal backendAmount,
|
|
|
|
|
+ String amountName) {
|
|
|
|
|
+
|
|
|
|
|
+ if (frontendAmount == null || backendAmount == null) {
|
|
|
|
|
+ log.warn("{}验证失败:前端金额或后端金额为null, frontend={}, backend={}",
|
|
|
|
|
+ amountName, frontendAmount, backendAmount);
|
|
|
|
|
+ return backendAmount != null ? backendAmount : BigDecimal.ZERO;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ BigDecimal difference = frontendAmount.subtract(backendAmount).abs();
|
|
|
|
|
+
|
|
|
|
|
+ if (difference.compareTo(AMOUNT_TOLERANCE) > 0) {
|
|
|
|
|
+ log.warn("前端计算的{}与后端计算不一致, frontend={}, backend={}, difference={}",
|
|
|
|
|
+ amountName, frontendAmount, backendAmount, difference);
|
|
|
|
|
+ // 使用后端计算的金额,确保数据准确性
|
|
|
|
|
+ return backendAmount;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 误差在允许范围内,使用前端金额
|
|
|
|
|
+ return frontendAmount;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|