|
|
@@ -21,6 +21,7 @@ import shop.alien.mapper.UserReservationMapper;
|
|
|
import shop.alien.mapper.UserReservationTableMapper;
|
|
|
import shop.alien.entity.store.dto.CartItemDTO;
|
|
|
import shop.alien.entity.store.dto.CreateOrderDTO;
|
|
|
+import shop.alien.entity.store.dto.UpdateOrderCouponDTO;
|
|
|
import shop.alien.entity.store.vo.OrderChangeLogBatchVO;
|
|
|
import shop.alien.entity.store.vo.OrderChangeLogItemVO;
|
|
|
import shop.alien.entity.store.vo.OrderInfoVO;
|
|
|
@@ -194,11 +195,28 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ BigDecimal serviceFee = dto.getServiceFee() != null ? dto.getServiceFee() : BigDecimal.ZERO;
|
|
|
+
|
|
|
Date now = new Date();
|
|
|
+
|
|
|
+ Set<Integer> cartCuisineIds = cart.getItems().stream()
|
|
|
+ .map(CartItemDTO::getCuisineId)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .filter(id -> id > 0)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+ Map<Integer, BigDecimal> listUnitByCuisine = cartCuisineIds.isEmpty()
|
|
|
+ ? Collections.emptyMap()
|
|
|
+ : DiningMenuPricing.resolveListUnitPriceByCuisineId(cartCuisineIds, storeCuisineMapper);
|
|
|
+ Map<Integer, BigDecimal> saleUnitByCuisine = cartCuisineIds.isEmpty()
|
|
|
+ ? Collections.emptyMap()
|
|
|
+ : DiningMenuPricing.resolveSaleUnitPrice(table.getStoreId(), listUnitByCuisine, storeProductDiscountRuleMapper);
|
|
|
+
|
|
|
StoreOrder order = null;
|
|
|
String orderNo = null;
|
|
|
boolean isUpdate = false; // 是否是更新订单
|
|
|
-
|
|
|
+ /** 更新订单场景下,写库前的优惠券 ID,用于加餐换券/取消券时作废旧 {@link StoreCouponUsage} */
|
|
|
+ Integer previousCouponIdBeforeUpdate = null;
|
|
|
+
|
|
|
// 检查桌号是否已绑定订单
|
|
|
if (table.getCurrentOrderId() != null) {
|
|
|
// 查询已存在的订单
|
|
|
@@ -207,6 +225,7 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
// 订单存在且是待支付状态,更新订单
|
|
|
isUpdate = true;
|
|
|
order = existingOrder;
|
|
|
+ previousCouponIdBeforeUpdate = order.getCouponId();
|
|
|
orderNo = order.getOrderNo(); // 使用原订单号
|
|
|
log.info("桌号已绑定订单,更新订单信息, orderId={}, orderNo={}", order.getId(), orderNo);
|
|
|
|
|
|
@@ -214,6 +233,7 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
order.setDinerCount(dto.getDinerCount());
|
|
|
order.setContactPhone(dto.getContactPhone());
|
|
|
order.setTablewareFee(tablewareFee);
|
|
|
+ order.setServiceFee(serviceFee);
|
|
|
order.setTotalAmount(totalAmount);
|
|
|
order.setCouponId(dto.getCouponId());
|
|
|
order.setCurrentCouponId(dto.getCouponId());
|
|
|
@@ -275,6 +295,7 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
order.setDinerCount(dto.getDinerCount());
|
|
|
order.setContactPhone(dto.getContactPhone());
|
|
|
order.setTablewareFee(tablewareFee);
|
|
|
+ order.setServiceFee(serviceFee);
|
|
|
order.setPayUserId(userId);
|
|
|
order.setPayUserPhone(userPhone);
|
|
|
order.setOrderStatus(0); // 待支付
|
|
|
@@ -324,13 +345,13 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 如果是更新订单,且优惠券发生变化,需要处理旧优惠券的使用记录
|
|
|
- if (isUpdate && finalOrder.getCouponId() != null &&
|
|
|
- (dto.getCouponId() == null || !finalOrder.getCouponId().equals(dto.getCouponId()))) {
|
|
|
+ // 如果是更新订单,且优惠券发生变化,需要处理旧优惠券的使用记录(须在写入新 couponId 前记录 previousCouponIdBeforeUpdate)
|
|
|
+ if (isUpdate && previousCouponIdBeforeUpdate != null
|
|
|
+ && (dto.getCouponId() == null || !dto.getCouponId().equals(previousCouponIdBeforeUpdate))) {
|
|
|
// 订单的优惠券被替换或取消,需要将旧优惠券使用记录状态改为"已取消"
|
|
|
LambdaQueryWrapper<StoreCouponUsage> oldUsageWrapper = new LambdaQueryWrapper<>();
|
|
|
oldUsageWrapper.eq(StoreCouponUsage::getOrderId, finalOrder.getId());
|
|
|
- oldUsageWrapper.eq(StoreCouponUsage::getCouponId, finalOrder.getCouponId());
|
|
|
+ oldUsageWrapper.eq(StoreCouponUsage::getCouponId, previousCouponIdBeforeUpdate);
|
|
|
oldUsageWrapper.eq(StoreCouponUsage::getDeleteFlag, 0);
|
|
|
oldUsageWrapper.orderByDesc(StoreCouponUsage::getCreatedTime);
|
|
|
oldUsageWrapper.last("LIMIT 1");
|
|
|
@@ -340,7 +361,7 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
oldUsage.setUpdatedTime(new Date());
|
|
|
storeCouponUsageMapper.updateById(oldUsage);
|
|
|
log.info("更新订单时替换优惠券:取消旧优惠券使用记录, orderId={}, oldCouponId={}, newCouponId={}",
|
|
|
- finalOrder.getId(), finalOrder.getCouponId(), dto.getCouponId());
|
|
|
+ finalOrder.getId(), previousCouponIdBeforeUpdate, dto.getCouponId());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -349,18 +370,6 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
// 餐具的特殊ID(用于标识餐具项)
|
|
|
final Integer TABLEWARE_CUISINE_ID = -1;
|
|
|
|
|
|
- java.util.Set<Integer> cartCuisineIds = cart.getItems().stream()
|
|
|
- .map(CartItemDTO::getCuisineId)
|
|
|
- .filter(Objects::nonNull)
|
|
|
- .filter(id -> id > 0)
|
|
|
- .collect(Collectors.toSet());
|
|
|
- java.util.Map<Integer, java.math.BigDecimal> listUnitByCuisine = cartCuisineIds.isEmpty()
|
|
|
- ? java.util.Collections.emptyMap()
|
|
|
- : DiningMenuPricing.resolveListUnitPriceByCuisineId(cartCuisineIds, storeCuisineMapper);
|
|
|
- java.util.Map<Integer, java.math.BigDecimal> saleUnitByCuisine = cartCuisineIds.isEmpty()
|
|
|
- ? java.util.Collections.emptyMap()
|
|
|
- : DiningMenuPricing.resolveSaleUnitPrice(table.getStoreId(), listUnitByCuisine, storeProductDiscountRuleMapper);
|
|
|
-
|
|
|
List<StoreOrderDetail> orderDetails = cart.getItems().stream()
|
|
|
.map(item -> {
|
|
|
StoreOrderDetail detail = new StoreOrderDetail();
|
|
|
@@ -508,35 +517,14 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
// 验证订单状态
|
|
|
StoreOrder order = validateOrderForOperation(orderId, 0, "支付");
|
|
|
|
|
|
- // 支付时重新计算优惠券金额和实付金额(此时订单金额已确定,不会再变化)
|
|
|
- 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.setPayStatus(1); // 已支付
|
|
|
order.setPayType(payType);
|
|
|
@@ -972,37 +960,34 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public StoreOrder updateOrderCoupon(Integer orderId, Integer couponId) {
|
|
|
+ public StoreOrder updateOrderCoupon(UpdateOrderCouponDTO dto) {
|
|
|
+ if (dto == null || dto.getOrderId() == null) {
|
|
|
+ throw new RuntimeException("订单ID不能为空");
|
|
|
+ }
|
|
|
+ Integer orderId = dto.getOrderId();
|
|
|
+ Integer couponId = dto.getCouponId();
|
|
|
log.info("更新订单优惠券, orderId={}, couponId={}", orderId, couponId);
|
|
|
|
|
|
// 验证订单状态
|
|
|
StoreOrder order = validateOrderForOperation(orderId, 0, "修改优惠券");
|
|
|
|
|
|
- BigDecimal discountAmount = BigDecimal.ZERO;
|
|
|
-
|
|
|
if (couponId != null) {
|
|
|
- // 验证优惠券
|
|
|
LifeDiscountCoupon coupon = lifeDiscountCouponMapper.selectById(couponId);
|
|
|
if (coupon == null) {
|
|
|
throw new RuntimeException("优惠券不存在");
|
|
|
}
|
|
|
-
|
|
|
- // 验证优惠券是否属于该门店
|
|
|
if (!coupon.getStoreId().equals(String.valueOf(order.getStoreId()))) {
|
|
|
throw new RuntimeException("优惠券不属于该门店");
|
|
|
}
|
|
|
-
|
|
|
- // 验证最低消费(菜品总价 + 餐具费)
|
|
|
- BigDecimal totalWithTableware = order.getTotalAmount().add(order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO);
|
|
|
- if (coupon.getMinimumSpendingAmount() != null
|
|
|
- && totalWithTableware.compareTo(coupon.getMinimumSpendingAmount()) < 0) {
|
|
|
- throw new RuntimeException("订单金额未达到优惠券最低消费要求");
|
|
|
- }
|
|
|
-
|
|
|
- // 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
|
|
|
- discountAmount = calculateDiscountAmount(coupon, totalWithTableware);
|
|
|
}
|
|
|
|
|
|
+ BigDecimal discountAmount = dto.getDiscountAmount() != null
|
|
|
+ ? dto.getDiscountAmount()
|
|
|
+ : (order.getDiscountAmount() != null ? order.getDiscountAmount() : BigDecimal.ZERO);
|
|
|
+ BigDecimal payAmount = dto.getPayAmount() != null
|
|
|
+ ? dto.getPayAmount()
|
|
|
+ : (order.getPayAmount() != null ? order.getPayAmount() : BigDecimal.ZERO);
|
|
|
+
|
|
|
// 如果之前有优惠券,且优惠券发生变化(包括取消优惠券),需要处理旧优惠券使用记录
|
|
|
if (order.getCouponId() != null && (couponId == null || !order.getCouponId().equals(couponId))) {
|
|
|
// 清除旧优惠券的使用标记(如果取消优惠券或更换优惠券)
|
|
|
@@ -1064,10 +1049,6 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 重新计算实付金额(菜品总价 + 餐具费 - 优惠金额)
|
|
|
- BigDecimal tablewareFee = order.getTablewareFee() != null ? order.getTablewareFee() : BigDecimal.ZERO;
|
|
|
- BigDecimal payAmount = order.getTotalAmount().add(tablewareFee).subtract(discountAmount);
|
|
|
-
|
|
|
order.setCouponId(couponId);
|
|
|
order.setCurrentCouponId(couponId);
|
|
|
order.setDiscountAmount(discountAmount);
|
|
|
@@ -1552,6 +1533,7 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
vo.setItems(items);
|
|
|
vo.setTotalAmount(order.getTotalAmount());
|
|
|
vo.setTablewareFee(order.getTablewareFee());
|
|
|
+ vo.setServiceFee(order.getServiceFee() != null ? order.getServiceFee() : BigDecimal.ZERO);
|
|
|
vo.setCouponId(order.getCouponId());
|
|
|
vo.setCouponName(couponName);
|
|
|
vo.setCouponType(couponType);
|
|
|
@@ -1706,6 +1688,7 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
vo.setRemark(order.getRemark());
|
|
|
vo.setTotalAmount(order.getTotalAmount());
|
|
|
vo.setTablewareFee(order.getTablewareFee());
|
|
|
+ vo.setServiceFee(order.getServiceFee() != null ? order.getServiceFee() : BigDecimal.ZERO);
|
|
|
vo.setCouponId(order.getCouponId());
|
|
|
vo.setCouponName(couponName);
|
|
|
vo.setDiscountAmount(order.getDiscountAmount());
|
|
|
@@ -2131,44 +2114,4 @@ public class StoreOrderServiceImpl extends ServiceImpl<StoreOrderMapper, StoreOr
|
|
|
return new Object[]{userId, userPhone};
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 计算优惠金额:根据优惠券类型(满减券或折扣券)计算
|
|
|
- *
|
|
|
- * @param coupon 优惠券对象
|
|
|
- * @param totalWithTableware 订单总金额(含餐具费)
|
|
|
- * @return 优惠金额
|
|
|
- */
|
|
|
- private BigDecimal calculateDiscountAmount(LifeDiscountCoupon coupon, BigDecimal totalWithTableware) {
|
|
|
- if (coupon == null || totalWithTableware == null || totalWithTableware.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
- return BigDecimal.ZERO;
|
|
|
- }
|
|
|
-
|
|
|
- Integer couponType = coupon.getCouponType();
|
|
|
- BigDecimal discountAmount = BigDecimal.ZERO;
|
|
|
-
|
|
|
- if (couponType != null && couponType == 2) {
|
|
|
- // 折扣券:根据折扣率计算优惠金额
|
|
|
- // discountRate: 0-100,例如80表示8折,优惠金额 = 订单金额 * (100 - discountRate) / 100
|
|
|
- BigDecimal discountRate = coupon.getDiscountRate();
|
|
|
- if (discountRate != null && discountRate.compareTo(BigDecimal.ZERO) > 0 && discountRate.compareTo(new BigDecimal(100)) <= 0) {
|
|
|
- // 计算折扣后的金额
|
|
|
- BigDecimal discountedAmount = totalWithTableware.multiply(discountRate).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
|
|
|
- // 优惠金额 = 原价 - 折扣后价格
|
|
|
- discountAmount = totalWithTableware.subtract(discountedAmount);
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 满减券(默认或couponType=1):使用nominalValue
|
|
|
- discountAmount = coupon.getNominalValue();
|
|
|
- if (discountAmount == null) {
|
|
|
- discountAmount = BigDecimal.ZERO;
|
|
|
- }
|
|
|
- // 优惠金额不能超过订单总金额
|
|
|
- if (discountAmount.compareTo(totalWithTableware) > 0) {
|
|
|
- discountAmount = totalWithTableware;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return discountAmount;
|
|
|
- }
|
|
|
-
|
|
|
}
|