mirror of
https://gitee.com/hhyykk/ipms-sjy.git
synced 2025-08-16 03:01:53 +08:00
trade:价格计算时,接入优惠劵逻辑
This commit is contained in:
@@ -14,7 +14,7 @@ import java.util.List;
|
||||
public class AppTradeOrderSettlementRespVO {
|
||||
|
||||
@Schema(description = "交易类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") // 对应 TradeOrderTypeEnum 枚举
|
||||
private Integer type = 1; // TODO 芋艿:改成计算
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "购物项数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private List<Item> items;
|
||||
@@ -75,6 +75,9 @@ public class AppTradeOrderSettlementRespVO {
|
||||
@Schema(description = "商品原价(总),单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "500")
|
||||
private Integer totalPrice;
|
||||
|
||||
@Schema(description = "订单优惠(总),单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "66")
|
||||
private Integer discountPrice;
|
||||
|
||||
@Schema(description = "运费金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "50")
|
||||
private Integer deliveryPrice;
|
||||
|
||||
|
@@ -211,7 +211,8 @@ public interface TradeOrderConvert {
|
||||
.setCouponId(settlementReqVO.getCouponId()).setPointStatus(settlementReqVO.getPointStatus())
|
||||
.setDeliveryType(settlementReqVO.getDeliveryType()).setAddressId(settlementReqVO.getAddressId())
|
||||
.setPickUpStoreId(settlementReqVO.getPickUpStoreId())
|
||||
.setItems(new ArrayList<>(settlementReqVO.getItems().size()));
|
||||
.setItems(new ArrayList<>(settlementReqVO.getItems().size()))
|
||||
.setSeckillActivityId(settlementReqVO.getSeckillActivityId());
|
||||
// 商品项的构建
|
||||
Map<Long, CartDO> cartMap = convertMap(cartList, CartDO::getId);
|
||||
for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) {
|
||||
|
@@ -288,4 +288,11 @@ public class TradeOrderDO extends BaseDO {
|
||||
*/
|
||||
private Integer vipPrice;
|
||||
|
||||
/**
|
||||
* 秒杀活动编号
|
||||
*
|
||||
* 关联 SeckillActivityDO 的 id 字段
|
||||
*/
|
||||
private Long seckillActivityId;
|
||||
|
||||
}
|
||||
|
@@ -1,13 +1,19 @@
|
||||
package cn.iocoder.yudao.module.trade.dal.mysql.order;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@Mapper
|
||||
public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
|
||||
@@ -38,4 +44,13 @@ public interface TradeOrderItemMapper extends BaseMapperX<TradeOrderItemDO> {
|
||||
.eq(TradeOrderItemDO::getCommentStatus, commentStatus));
|
||||
}
|
||||
|
||||
default int selectProductSumByOrderId(@Param("orderIds") Set<Long> orderIds) {
|
||||
// SQL sum 查询
|
||||
List<Map<String, Object>> result = selectMaps(new QueryWrapper<TradeOrderItemDO>()
|
||||
.select("SUM(count) AS sumCount")
|
||||
.in("order_id", orderIds)); // 只计算选中的
|
||||
// 获得数量
|
||||
return CollUtil.getFirst(result) != null ? MapUtil.getInt(result.get(0), "sumCount") : 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -82,4 +82,10 @@ public interface TradeOrderMapper extends BaseMapperX<TradeOrderDO> {
|
||||
.eq(TradeOrderDO::getCommentStatus, commentStatus));
|
||||
}
|
||||
|
||||
default List<TradeOrderDO> selectListByUserIdAndSeckillActivityId(Long userId, Long seckillActivityId) {
|
||||
return selectList(new LambdaUpdateWrapper<>(TradeOrderDO.class)
|
||||
.eq(TradeOrderDO::getUserId, userId)
|
||||
.eq(TradeOrderDO::getSeckillActivityId, seckillActivityId));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -82,6 +82,15 @@ public interface TradeOrderQueryService {
|
||||
*/
|
||||
List<ExpressTrackRespDTO> getExpressTrackList(Long id);
|
||||
|
||||
/**
|
||||
* 【会员】在指定秒杀活动下,用户购买的商品数量
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param activityId 活动编号
|
||||
* @return 秒杀商品数量
|
||||
*/
|
||||
int getSeckillProductCount(Long userId, Long activityId);
|
||||
|
||||
// =================== Order Item ===================
|
||||
|
||||
/**
|
||||
|
@@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
|
||||
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
|
||||
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
|
||||
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
|
||||
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
|
||||
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.ExpressClientFactory;
|
||||
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackQueryReqDTO;
|
||||
import cn.iocoder.yudao.module.trade.framework.delivery.core.client.dto.ExpressTrackRespDTO;
|
||||
@@ -120,6 +121,18 @@ public class TradeOrderQueryServiceImpl implements TradeOrderQueryService {
|
||||
return getExpressTrackList(order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSeckillProductCount(Long userId, Long activityId) {
|
||||
// 获得订单列表
|
||||
List<TradeOrderDO> orders = tradeOrderMapper.selectListByUserIdAndSeckillActivityId(userId, activityId);
|
||||
orders.removeIf(order -> TradeOrderStatusEnum.isCanceled(order.getStatus())); // 过滤掉【已取消】的订单
|
||||
if (CollUtil.isEmpty(orders)) {
|
||||
return 0;
|
||||
}
|
||||
// 获得订单项列表
|
||||
return tradeOrderItemMapper.selectProductSumByOrderId(convertSet(orders, TradeOrderDO::getId));
|
||||
}
|
||||
|
||||
// TODO @puhui999:可以加个 spring 缓存,30 分钟;主要考虑及时性要求不高,但是每次调用需要钱;
|
||||
/**
|
||||
* 获得订单的物流轨迹
|
||||
|
@@ -1,19 +1,22 @@
|
||||
package cn.iocoder.yudao.module.trade.service.price.calculator;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityProductRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO;
|
||||
import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum;
|
||||
import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
|
||||
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT;
|
||||
|
||||
// TODO huihui:单测需要补充
|
||||
/**
|
||||
* 秒杀活动的 {@link TradePriceCalculator} 实现类
|
||||
*
|
||||
@@ -24,22 +27,45 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
|
||||
public class TradeSeckillActivityPriceCalculator implements TradePriceCalculator {
|
||||
|
||||
@Resource
|
||||
private SeckillActivityApi activityApi;
|
||||
private SeckillActivityApi seckillActivityApi;
|
||||
|
||||
@Resource
|
||||
private TradeOrderQueryService tradeOrderQueryService;
|
||||
|
||||
@Override
|
||||
public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) {
|
||||
// 1、判断订单类型和是否具有秒杀活动编号
|
||||
// 1. 判断订单类型和是否具有秒杀活动编号
|
||||
if (param.getSeckillActivityId() == null) {
|
||||
return;
|
||||
}
|
||||
// 2、获取秒杀活动商品信息
|
||||
List<SeckillActivityProductRespDTO> productList = activityApi.getSeckillActivityProductList(param.getSeckillActivityId(), convertSet(param.getItems(),
|
||||
TradePriceCalculateReqBO.Item::getSkuId));
|
||||
Map<Long, SeckillActivityProductRespDTO> productMap = convertMap(productList, SeckillActivityProductRespDTO::getSkuId);
|
||||
result.getItems().forEach(item -> {
|
||||
SeckillActivityProductRespDTO product = productMap.get(item.getSkuId());
|
||||
item.setActivityPrice(product.getSeckillPrice()); // 设置活动金额
|
||||
});
|
||||
Assert.isTrue(param.getItems().size() == 1, "秒杀时,只允许选择一个商品");
|
||||
// 2. 校验是否可以参与秒杀
|
||||
TradePriceCalculateRespBO.OrderItem orderItem = result.getItems().get(0);
|
||||
SeckillValidateJoinRespDTO seckillActivity = validateJoinSeckill(
|
||||
param.getUserId(), param.getSeckillActivityId(),
|
||||
orderItem.getSkuId(), orderItem.getCount());
|
||||
|
||||
// 3.1 记录优惠明细
|
||||
Integer discountPrice = orderItem.getPayPrice() - seckillActivity.getSeckillPrice();
|
||||
TradePriceCalculatorHelper.addPromotion(result, orderItem,
|
||||
param.getSeckillActivityId(), seckillActivity.getName(), PromotionTypeEnum.SECKILL_ACTIVITY.getType(),
|
||||
StrUtil.format("秒杀活动:省 {} 元", TradePriceCalculatorHelper.formatPrice(discountPrice)),
|
||||
discountPrice);
|
||||
// 3.2 更新 SKU 优惠金额
|
||||
orderItem.setDiscountPrice(orderItem.getDiscountPrice() + discountPrice);
|
||||
TradePriceCalculatorHelper.recountPayPrice(orderItem);
|
||||
TradePriceCalculatorHelper.recountAllPrice(result);
|
||||
}
|
||||
|
||||
private SeckillValidateJoinRespDTO validateJoinSeckill(Long userId, Long activityId, Long skuId, Integer count) {
|
||||
// 1. 校验是否可以参与秒杀
|
||||
SeckillValidateJoinRespDTO seckillActivity = seckillActivityApi.validateJoinSeckill(activityId, skuId, count);
|
||||
// 2. 校验总限购数量,目前只有 trade 有具体下单的数据,需要交给 trade 价格计算使用
|
||||
int seckillProductCount = tradeOrderQueryService.getSeckillProductCount(userId, activityId);
|
||||
if (seckillProductCount + count > seckillActivity.getTotalLimitCount()) {
|
||||
throw exception(PRICE_CALCULATE_SECKILL_TOTAL_LIMIT_COUNT);
|
||||
}
|
||||
return seckillActivity;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user