feat:拼团订单集成

This commit is contained in:
puhui999
2023-07-21 16:47:04 +08:00
parent d80bf5a368
commit 259807600a
21 changed files with 498 additions and 42 deletions

View File

@@ -1,9 +1,10 @@
package cn.iocoder.yudao.module.trade.controller.admin.order.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Schema(description = "管理后台 - 订单发货 Request VO")
@@ -14,12 +15,18 @@ public class TradeOrderDeliveryReqVO {
@NotNull(message = "订单编号不能为空")
private Long id;
@Schema(description = "发货物流公司编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "发货物流公司编号不能为空")
@Schema(description = "发货类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@InEnum(DeliveryTypeEnum.class)
@NotNull(message = "发货类型不能为空")
private Integer type;
@Schema(description = "发货物流公司编号", example = "1")
private Long logisticsId;
@Schema(description = "发货物流单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "SF123456789")
@NotEmpty(message = "发货物流单号不能为空")
@Schema(description = "发货物流单号", example = "SF123456789")
private String logisticsNo;
// =============== 同城配送 ================
// TODO
}

View File

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.trade.controller.app.order.vo;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -19,11 +18,6 @@ import java.util.List;
@Data
public class AppTradeOrderSettlementReqVO {
@NotNull(message = "交易类型不能为空")
@InEnum(value = TradeOrderTypeEnum.class, message = "交易类型必须是 {value}")
@Deprecated // TODO 芋艿:后续干掉这个字段,对于前端不需要关注这个
private Integer type = 1;
@Schema(description = "商品项数组", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "商品不能为空")
private List<Item> items;

View File

@@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.dto.CombinationRecordReqDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
@@ -52,7 +53,6 @@ public interface TradeOrderConvert {
@Mapping(source = "createReqVO.couponId", target = "couponId"),
@Mapping(target = "remark", ignore = true),
@Mapping(source = "createReqVO.remark", target = "userRemark"),
@Mapping(source = "createReqVO.type", target = "type"),
@Mapping(source = "calculateRespBO.price.totalPrice", target = "totalPrice"),
@Mapping(source = "calculateRespBO.price.discountPrice", target = "discountPrice"),
@Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"),
@@ -123,7 +123,7 @@ public interface TradeOrderConvert {
// TODO 芋艿:可简化
default PageResult<TradeOrderPageItemRespVO> convertPage(PageResult<TradeOrderDO> pageResult, List<TradeOrderItemDO> orderItems,
List<ProductPropertyValueDetailRespDTO> propertyValueDetails,
Map<Long,MemberUserRespDTO> memberUserRespDTOMap) {
Map<Long, MemberUserRespDTO> memberUserRespDTOMap) {
Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId);
Map<Long, ProductPropertyValueDetailRespDTO> propertyValueDetailMap = convertMap(propertyValueDetails, ProductPropertyValueDetailRespDTO::getValueId);
// 转化 List
@@ -267,22 +267,23 @@ public interface TradeOrderConvert {
AppTradeOrderItemRespVO convert03(TradeOrderItemDO bean);
@Mapping(target = "skuId", source = "tradeOrderItemDO.skuId")
@Mapping(target = "orderId", source = "tradeOrderItemDO.orderId")
@Mapping(target = "orderItemId", source = "tradeOrderItemDO.id")
@Mapping(target = "descriptionScores", source = "createReqVO.descriptionScores")
@Mapping(target = "benefitScores", source = "createReqVO.benefitScores")
@Mapping(target = "content", source = "createReqVO.content")
@Mapping(target = "picUrls", source = "createReqVO.picUrls")
@Mapping(target = "anonymous", source = "createReqVO.anonymous")
@Mapping(target = "userId", source = "tradeOrderItemDO.userId")
@Mappings({
@Mapping(target = "skuId", source = "tradeOrderItemDO.skuId"),
@Mapping(target = "orderId", source = "tradeOrderItemDO.orderId"),
@Mapping(target = "orderItemId", source = "tradeOrderItemDO.id"),
@Mapping(target = "descriptionScores", source = "createReqVO.descriptionScores"),
@Mapping(target = "benefitScores", source = "createReqVO.benefitScores"),
@Mapping(target = "content", source = "createReqVO.content"),
@Mapping(target = "picUrls", source = "createReqVO.picUrls"),
@Mapping(target = "anonymous", source = "createReqVO.anonymous"),
@Mapping(target = "userId", source = "tradeOrderItemDO.userId")
})
ProductCommentCreateReqDTO convert04(AppTradeOrderItemCommentCreateReqVO createReqVO, TradeOrderItemDO tradeOrderItemDO);
default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO,
List<TradeCartDO> cartList) {
TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO();
reqBO.setUserId(userId).setType(settlementReqVO.getType())
.setCouponId(settlementReqVO.getCouponId()).setAddressId(settlementReqVO.getAddressId())
reqBO.setUserId(userId).setCouponId(settlementReqVO.getCouponId()).setAddressId(settlementReqVO.getAddressId())
.setItems(new ArrayList<>(settlementReqVO.getItems().size()));
// 商品项的构建
Map<Long, TradeCartDO> cartMap = convertMap(cartList, TradeCartDO::getId);
@@ -317,4 +318,20 @@ public interface TradeOrderConvert {
AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address);
@Mappings({
@Mapping(target = "activityId", source = "createReqVO.combinationActivityId"),
@Mapping(target = "spuId", source = "orderItem.spuId"),
@Mapping(target = "skuId", source = "orderItem.skuId"),
@Mapping(target = "userId", source = "order.userId"),
@Mapping(target = "orderId", source = "order.id"),
@Mapping(target = "headId", source = "createReqVO.combinationHeadId"),
@Mapping(target = "spuName", source = "orderItem.spuName"),
@Mapping(target = "picUrl", source = "orderItem.picUrl"),
@Mapping(target = "combinationPrice", source = "orderItem.payPrice"),
@Mapping(target = "nickname", source = "user.nickname"),
@Mapping(target = "avatar", source = "user.avatar"),
@Mapping(target = "status", ignore = true)
})
CombinationRecordReqDTO convert(TradeOrderDO order, TradeOrderItemDO orderItem, AppTradeOrderCreateReqVO createReqVO, MemberUserRespDTO user);
}

View File

@@ -21,8 +21,10 @@ 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.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
import cn.iocoder.yudao.module.promotion.api.combination.CombinationApi;
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.enums.combination.CombinationRecordStatusEnum;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO;
@@ -103,6 +105,8 @@ public class TradeOrderServiceImpl implements TradeOrderService {
@Resource
private TradeOrderProperties tradeOrderProperties;
@Resource
private CombinationApi combinationApi;
// =================== Order ===================
@Override
@@ -158,7 +162,6 @@ public class TradeOrderServiceImpl implements TradeOrderService {
public TradeOrderDO createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) {
// 1. 用户收件地址的校验
AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId());
// 2. 价格计算
TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO);
@@ -166,9 +169,17 @@ public class TradeOrderServiceImpl implements TradeOrderService {
TradeOrderDO order = createTradeOrder(userId, userIp, createReqVO, calculateRespBO, address);
// 3.2 插入 TradeOrderItemDO 订单项
List<TradeOrderItemDO> orderItems = createTradeOrderItems(order, calculateRespBO);
// 订单创建完后的逻辑
afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO);
// 3.3 校验订单类型
// 拼团
if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
MemberUserRespDTO user = memberUserApi.getUser(userId);
// TODO 拼团一次应该只能选择一种规格的商品
combinationApi.createRecord(TradeOrderConvert.INSTANCE.convert(order, orderItems.get(0), createReqVO, user)
.setStatus(CombinationRecordStatusEnum.NOT_PAY.getStatus()));
}
// TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来!
return order;
}
@@ -188,12 +199,29 @@ public class TradeOrderServiceImpl implements TradeOrderService {
return address;
}
/**
* 校验活动返回订单类型
*
* @param createReqVO 请求参数
* @return 订单类型
*/
private Integer validateActivity(AppTradeOrderCreateReqVO createReqVO) {
if (createReqVO.getSeckillActivityId() != null) {
return TradeOrderTypeEnum.SECKILL.getType();
}
if (createReqVO.getCombinationActivityId() != null) {
return TradeOrderTypeEnum.COMBINATION.getType();
}
// TODO 砍价敬请期待
return TradeOrderTypeEnum.NORMAL.getType();
}
private TradeOrderDO createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO,
TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address) {
TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address);
order.setType(validateActivity(createReqVO));
order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的;
order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus());
order.setType(TradeOrderTypeEnum.NORMAL.getType());
order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum));
order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源?
@@ -270,7 +298,12 @@ public class TradeOrderServiceImpl implements TradeOrderService {
if (updateCount == 0) {
throw exception(ORDER_UPDATE_PAID_STATUS_NOT_UNPAID);
}
// 校验活动
// 1、拼团活动
if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
// 更新拼团状态 TODO puhui999订单支付失败或订单过期删除这条拼团记录
combinationApi.updateRecordStatusAndStartTime(order.getUserId(), order.getId(), CombinationRecordStatusEnum.ONGOING.getStatus());
}
// TODO 芋艿:发送订单变化的消息
// TODO 芋艿:发送站内信
@@ -334,12 +367,12 @@ public class TradeOrderServiceImpl implements TradeOrderService {
return new KeyValue<>(order, payOrder);
}
// TODO 芋艿:如果无需发货,需要怎么存储?
// TODO 芋艿:如果无需发货,需要怎么存储? fix更改订单发货类型为无需发货更改发货类型为等待自提等待用户自提后更改订单状态为已完成
@Override
public void deliveryOrder(Long userId, TradeOrderDeliveryReqVO deliveryReqVO) {
// 校验并获得交易订单(可发货)
TradeOrderDO order = validateOrderDeliverable(deliveryReqVO.getId());
// TODO 芋艿logisticsId 校验存在 发货物流公司 fix
// TODO 判断发货类型,根据发货类型发货
DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(deliveryReqVO.getLogisticsId());
if (deliveryExpress == null) {
throw exception(EXPRESS_NOT_EXISTS);
@@ -369,7 +402,7 @@ public class TradeOrderServiceImpl implements TradeOrderService {
.setTemplateParams(msgMap));
// TODO 芋艿OrderLog
// TODO 设计like是否要单独一个 delivery 发货单表???
// TODO 设计like是否要单独一个 delivery 发货单表??? fix: 确实单独一张发货表就能解决整单发货和单独发货的问题
// TODO 设计niu要不要支持一个订单下多个 order item 单独发货,类似有赞
// TODO 设计lili是不是发货后才支持售后
}
@@ -393,6 +426,15 @@ public class TradeOrderServiceImpl implements TradeOrderService {
|| ObjectUtil.notEqual(order.getDeliveryStatus(), TradeOrderDeliveryStatusEnum.UNDELIVERED.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);
}
// 校验订单拼团是否成功
if (ObjectUtil.equal(TradeOrderTypeEnum.COMBINATION.getType(), order.getType())) {
}
// TODO puhui999: 校验订单砍价是否成功
return order;
}