营销活动+订单:完善大部分 TODO 提到的问题

This commit is contained in:
puhui999
2023-09-08 00:35:54 +08:00
parent 2591ab5d36
commit 0e8755972c
19 changed files with 381 additions and 45 deletions

View File

@@ -25,6 +25,7 @@ import java.util.Map;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
@Tag(name = "管理后台 - 交易订单")
@RestController
@@ -67,6 +68,9 @@ public class TradeOrderController {
public CommonResult<TradeOrderDetailRespVO> getOrderDetail(@RequestParam("id") Long id) {
// 查询订单
TradeOrderDO order = tradeOrderQueryService.getOrder(id);
if (order == null) {
return success(null, ORDER_NOT_FOUND.getMsg());
}
// 查询订单项
List<TradeOrderItemDO> orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);
// orderLog

View File

@@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO;
import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.*;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemCommentCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO;
@@ -34,6 +33,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
@Tag(name = "用户 App - 交易订单")
@RestController
@@ -83,7 +83,7 @@ public class AppTradeOrderController {
// 查询订单
TradeOrderDO order = tradeOrderQueryService.getOrder(getLoginUserId(), id);
if (order == null) {
return success(null);
return success(null, ORDER_NOT_FOUND.getMsg());
}
// 查询订单项

View File

@@ -56,6 +56,10 @@ public class AppTradeOrderSettlementReqVO {
@Schema(description = "拼团团长编号", example = "2048")
private Long combinationHeadId;
// ========== 砍价活动相关字段 ==========
@Schema(description = "砍价活动编号", example = "123")
private Long bargainActivityId;
@Data
@Schema(description = "用户 App - 商品项")
@Valid

View File

@@ -0,0 +1,35 @@
package cn.iocoder.yudao.module.trade.dal.redis.no;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.time.LocalDateTime;
/**
* 订单序号的 Redis DAO
*
* @author HUIHUI
*/
@Repository
public class TradeOrderNoRedisDAO {
public static final String TRADE_ORDER_NO_PREFIX = "O";
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 生成序号
*
* @param prefix 前缀
* @return 序号
*/
public String generate(String prefix) {
String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
Long no = stringRedisTemplate.opsForValue().increment(noPrefix);
return noPrefix + no;
}
}

View File

@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.trade.service.order;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
@@ -25,11 +24,14 @@ import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.product.api.comment.ProductCommentApi;
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.promotion.api.bargain.BargainActivityApi;
import cn.iocoder.yudao.module.promotion.api.bargain.BargainRecordApi;
import cn.iocoder.yudao.module.promotion.api.combination.CombinationRecordApi;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordRespDTO;
import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi;
import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO;
import cn.iocoder.yudao.module.promotion.api.seckill.SeckillActivityApi;
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillActivityUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderRemarkReqVO;
@@ -45,6 +47,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.dal.redis.no.TradeOrderNoRedisDAO;
import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.*;
@@ -70,7 +73,7 @@ import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_NOT_FOUND;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_EQUAL;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.ORDER_UPDATE_PRICE_FAIL_PAID;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
@@ -88,6 +91,8 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
private TradeOrderMapper tradeOrderMapper;
@Resource
private TradeOrderItemMapper tradeOrderItemMapper;
@Resource
private TradeOrderNoRedisDAO orderNoRedisDAO;
@Resource
private CartService cartService;
@@ -111,6 +116,10 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
@Resource
private BargainRecordApi bargainRecordApi;
@Resource
private SeckillActivityApi seckillActivityApi;
@Resource
private BargainActivityApi bargainActivityApi;
@Resource
private MemberUserApi memberUserApi;
@Resource
private MemberLevelApi memberLevelApi;
@@ -189,22 +198,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
// TODO @puhui999这个逻辑先抽个小方法未来要通过设计模式把这些拼团之类的逻辑抽象出去
// 拼团
if (Objects.equals(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
MemberUserRespDTO user = memberUserApi.getUser(userId);
List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
// TODO 拼团一次应该只能选择一种规格的商品
TradeOrderItemDO orderItemDO = orderItems.get(0);
if (CollUtil.isNotEmpty(recordRespDTOS)) {
List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
}
combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
createCombinationRecord(userId, createReqVO, orderItems, order);
}
// 3.2 秒杀的特殊逻辑
// TODO 秒杀扣减库存是下单就扣除还是等待订单支付成功再扣除
if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), order.getType())) {
}
@@ -214,6 +210,22 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
return order;
}
private void createCombinationRecord(Long userId, AppTradeOrderCreateReqVO createReqVO, List<TradeOrderItemDO> orderItems, TradeOrderDO order) {
MemberUserRespDTO user = memberUserApi.getUser(userId);
List<CombinationRecordRespDTO> recordRespDTOS = combinationRecordApi.getRecordListByUserIdAndActivityId(userId, createReqVO.getCombinationActivityId());
// TODO 拼团一次应该只能选择一种规格的商品
TradeOrderItemDO orderItemDO = orderItems.get(0);
if (CollUtil.isNotEmpty(recordRespDTOS)) {
List<Long> skuIds = convertList(recordRespDTOS, CombinationRecordRespDTO::getSkuId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus()));
List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper.selectListByOrderIdAnSkuId(convertList(recordRespDTOS,
CombinationRecordRespDTO::getOrderId, item -> ObjectUtil.equals(item.getStatus(), CombinationRecordStatusEnum.SUCCESS.getStatus())), skuIds);
combinationRecordApi.validateCombinationLimitCount(createReqVO.getCombinationActivityId(),
CollectionUtils.getSumValue(tradeOrderItemDOS, TradeOrderItemDO::getCount, Integer::sum), orderItemDO.getCount());
}
combinationRecordApi.createCombinationRecord(TradeOrderConvert.INSTANCE.convert(order, orderItemDO, createReqVO, user));
}
// TODO @puhui999订单超时自动取消
/**
@@ -240,8 +252,9 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
address = validateAddress(userId, createReqVO.getAddressId());
}
TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address);
String no = orderNoRedisDAO.generate(TradeOrderNoRedisDAO.TRADE_ORDER_NO_PREFIX);
order.setType(validateActivity(createReqVO));
order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @puhui999: 参考支付订单,的 no 生成哈;
order.setNo(no);
order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
@@ -293,19 +306,23 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO,
TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems,
TradePriceCalculateRespBO calculateRespBO) {
// 下单时扣减商品库存
// TODO @puhui999扣库存需要前置
Integer count = getSumValue(orderItems, TradeOrderItemDO::getCount, Integer::sum);
// 1如果是秒杀商品额外扣减秒杀的库存
// 2如果是拼团活动额外扣减拼团的库存
// 3如果是砍价活动额外扣减砍价的库存
productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));
// 删除购物车商品
Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
if (CollUtil.isNotEmpty(cartIds)) {
cartService.deleteCart(userId, cartIds);
if (Objects.equals(TradeOrderTypeEnum.SECKILL.getType(), tradeOrderDO.getType())) {
SeckillActivityUpdateStockReqDTO updateStockReqDTO = new SeckillActivityUpdateStockReqDTO();
updateStockReqDTO.setActivityId(createReqVO.getSeckillActivityId());
updateStockReqDTO.setCount(count);
updateStockReqDTO.setItems(CollectionUtils.convertList(orderItems, item -> {
SeckillActivityUpdateStockReqDTO.Item item1 = new SeckillActivityUpdateStockReqDTO.Item();
item1.setSpuId(item.getSpuId());
item1.setSkuId(item.getSkuId());
item1.setCount(item.getCount());
return item1;
}));
seckillActivityApi.updateSeckillStock(updateStockReqDTO);
}
// 2如果是砍价活动额外扣减砍价的库存
bargainActivityApi.updateBargainActivityStock(createReqVO.getBargainActivityId(), count);
// 扣减积分 TODO 芋艿:待实现,需要前置;
// 这个是不是应该放到支付成功之后?如果支付后的话,可能积分可以重复使用哈。资源类,都要预扣
@@ -315,6 +332,15 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
.setOrderId(tradeOrderDO.getId()));
}
// 下单时扣减商品库存
productSkuApi.updateSkuStock(TradeOrderConvert.INSTANCE.convertNegative(orderItems));
// 删除购物车商品
Set<Long> cartIds = convertSet(createReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId);
if (CollUtil.isNotEmpty(cartIds)) {
cartService.deleteCart(userId, cartIds);
}
// 生成预支付
createPayOrder(tradeOrderDO, orderItems, calculateRespBO);
@@ -464,11 +490,6 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
*/
private TradeOrderDO validateOrderDeliverable(Long id) {
TradeOrderDO order = validateOrderExists(id);
// 校验订单是否是待发货状态
// TODO @puhui999已经发货可以重新发货修改信息
if (!TradeOrderStatusEnum.isUndelivered(order.getStatus())) {
throw exception(ORDER_DELIVERY_FAIL_STATUS_NOT_UNDELIVERED);
}
// 校验订单是否退款
if (ObjectUtil.notEqual(TradeOrderRefundStatusEnum.NONE.getStatus(), order.getRefundStatus())) {
throw exception(ORDER_DELIVERY_FAIL_REFUND_STATUS_NOT_NONE);
@@ -540,14 +561,25 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
if (order.getPayStatus()) {
throw exception(ORDER_UPDATE_PRICE_FAIL_PAID);
}
// TODO @puhui999如果改价需要校验下是否真的变化
if (ObjectUtil.equal(order.getAdjustPrice(), reqVO.getAdjustPrice())) {
throw exception(ORDER_UPDATE_PRICE_FAIL_EQUAL);
}
// 更新
// TODO @puhui999TradeOrderItemDO 需要做 adjustPrice 的分摊;另外,支付订单那的价格,需要 update 下;
List<TradeOrderItemDO> itemDOs = tradeOrderItemMapper.selectListByOrderId(order.getId());
// TradeOrderItemDO 需要做 adjustPrice 的分摊
int price = reqVO.getAdjustPrice() / itemDOs.size();
itemDOs.forEach(item -> {
item.setAdjustPrice(price);
});
// 更新 TradeOrderItem
tradeOrderItemMapper.updateBatch(itemDOs);
// 更新订单
TradeOrderDO update = TradeOrderConvert.INSTANCE.convert(reqVO);
update.setPayPrice(update.getPayPrice() + update.getAdjustPrice());
// TODO @芋艿:改价时,赠送的积分,要不要做改动???
tradeOrderMapper.updateById(update);
// 更新支付订单
payOrderApi.updatePayOrderPriceById(order.getPayOrderId(), update.getPayPrice());
}
@Override