Commit 01d10b518c79932b0e76f16ca163d87b22a85fec
1 parent
d7a1c8f7
trade:优化创建订单接口的后端实现
Showing
17 changed files
with
310 additions
and
139 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApi.java
| 1 | package cn.iocoder.yudao.module.product.api.spu; | 1 | package cn.iocoder.yudao.module.product.api.spu; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; | 3 | +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 4 | 4 | ||
| 5 | import java.util.Collection; | 5 | import java.util.Collection; |
| 6 | import java.util.List; | 6 | import java.util.List; |
| @@ -19,6 +19,6 @@ public interface ProductSpuApi { | @@ -19,6 +19,6 @@ public interface ProductSpuApi { | ||
| 19 | * @param ids SPU 编号列表 | 19 | * @param ids SPU 编号列表 |
| 20 | * @return SPU 数组 | 20 | * @return SPU 数组 |
| 21 | */ | 21 | */ |
| 22 | - List<SpuInfoRespDTO> getSpuList(Collection<Long> ids); | 22 | + List<ProductSpuRespDTO> getSpuList(Collection<Long> ids); |
| 23 | 23 | ||
| 24 | } | 24 | } |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/SpuInfoRespDTO.java renamed to yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/ProductSpuRespDTO.java
| @@ -9,11 +9,13 @@ import java.util.List; | @@ -9,11 +9,13 @@ import java.util.List; | ||
| 9 | 9 | ||
| 10 | // TODO @LeeYan9: ProductSpuRespDTO | 10 | // TODO @LeeYan9: ProductSpuRespDTO |
| 11 | /** | 11 | /** |
| 12 | + * 商品 SPU 信息 Response DTO | ||
| 13 | + * | ||
| 12 | * @author LeeYan9 | 14 | * @author LeeYan9 |
| 13 | * @since 2022-08-26 | 15 | * @since 2022-08-26 |
| 14 | */ | 16 | */ |
| 15 | @Data | 17 | @Data |
| 16 | -public class SpuInfoRespDTO { | 18 | +public class ProductSpuRespDTO { |
| 17 | 19 | ||
| 18 | /** | 20 | /** |
| 19 | * 商品 SPU 编号,自增 | 21 | * 商品 SPU 编号,自增 |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
| 1 | package cn.iocoder.yudao.module.product.api.spu; | 1 | package cn.iocoder.yudao.module.product.api.spu; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 3 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 4 | -import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; | 4 | +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 5 | import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; | 5 | import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; |
| 6 | import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; | 6 | import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; |
| 7 | import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; | 7 | import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; |
| @@ -27,7 +27,7 @@ public class ProductSpuApiImpl implements ProductSpuApi { | @@ -27,7 +27,7 @@ public class ProductSpuApiImpl implements ProductSpuApi { | ||
| 27 | private ProductSpuMapper productSpuMapper; | 27 | private ProductSpuMapper productSpuMapper; |
| 28 | 28 | ||
| 29 | @Override | 29 | @Override |
| 30 | - public List<SpuInfoRespDTO> getSpuList(Collection<Long> spuIds) { | 30 | + public List<ProductSpuRespDTO> getSpuList(Collection<Long> spuIds) { |
| 31 | // TODO TODO LeeYan9: AllEmpty? | 31 | // TODO TODO LeeYan9: AllEmpty? |
| 32 | if (CollectionUtils.isAnyEmpty(spuIds)) { | 32 | if (CollectionUtils.isAnyEmpty(spuIds)) { |
| 33 | return Collections.emptyList(); | 33 | return Collections.emptyList(); |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/spu/ProductSpuConvert.java
| 1 | package cn.iocoder.yudao.module.product.convert.spu; | 1 | package cn.iocoder.yudao.module.product.convert.spu; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | -import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; | 4 | +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 5 | import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; | 5 | import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; |
| 6 | import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO; | 6 | import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageReqVO; |
| 7 | import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO; | 7 | import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppSpuPageRespVO; |
| @@ -35,7 +35,7 @@ public interface ProductSpuConvert { | @@ -35,7 +35,7 @@ public interface ProductSpuConvert { | ||
| 35 | 35 | ||
| 36 | AppSpuPageRespVO convertAppResp(ProductSpuDO list); | 36 | AppSpuPageRespVO convertAppResp(ProductSpuDO list); |
| 37 | 37 | ||
| 38 | - List<SpuInfoRespDTO> convertList2(List<ProductSpuDO> list); | 38 | + List<ProductSpuRespDTO> convertList2(List<ProductSpuDO> list); |
| 39 | 39 | ||
| 40 | List<ProductSpuSimpleRespVO> convertList02(List<ProductSpuDO> list); | 40 | List<ProductSpuSimpleRespVO> convertList02(List<ProductSpuDO> list); |
| 41 | 41 |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/ErrorCodeConstants.java
| @@ -22,17 +22,17 @@ public interface ErrorCodeConstants { | @@ -22,17 +22,17 @@ public interface ErrorCodeConstants { | ||
| 22 | 22 | ||
| 23 | // ========== Coupon 相关 1003003000 ============ | 23 | // ========== Coupon 相关 1003003000 ============ |
| 24 | ErrorCode COUPON_NO_MATCH_SPU = new ErrorCode(1003003000, "优惠劵没有可使用的商品!"); | 24 | ErrorCode COUPON_NO_MATCH_SPU = new ErrorCode(1003003000, "优惠劵没有可使用的商品!"); |
| 25 | - ErrorCode COUPON_NO_MATCH_MIN_PRICE = new ErrorCode(1003003000, "不满足优惠劵使用的最低金额"); | 25 | + ErrorCode COUPON_NO_MATCH_MIN_PRICE = new ErrorCode(1003003000, "所结算的商品中未满足使用的金额"); |
| 26 | 26 | ||
| 27 | // ========== 优惠劵模板 1003004000 ========== | 27 | // ========== 优惠劵模板 1003004000 ========== |
| 28 | ErrorCode COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1003004000, "优惠劵模板不存在"); | 28 | ErrorCode COUPON_TEMPLATE_NOT_EXISTS = new ErrorCode(1003004000, "优惠劵模板不存在"); |
| 29 | ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1003004001, "发放数量不能小于已领取数量({})"); | 29 | ErrorCode COUPON_TEMPLATE_TOTAL_COUNT_TOO_SMALL = new ErrorCode(1003004001, "发放数量不能小于已领取数量({})"); |
| 30 | 30 | ||
| 31 | // ========== 优惠劵模板 1003005000 ========== | 31 | // ========== 优惠劵模板 1003005000 ========== |
| 32 | - ErrorCode COUPON_NOT_EXISTS = new ErrorCode(1003005000, "优惠劵不存在"); | 32 | + ErrorCode COUPON_NOT_EXISTS = new ErrorCode(1003005000, "优惠券不存在"); |
| 33 | ErrorCode COUPON_DELETE_FAIL_USED = new ErrorCode(1003005001, "回收优惠劵失败,优惠劵已被使用"); | 33 | ErrorCode COUPON_DELETE_FAIL_USED = new ErrorCode(1003005001, "回收优惠劵失败,优惠劵已被使用"); |
| 34 | ErrorCode COUPON_STATUS_NOT_UNUSED = new ErrorCode(1006003003, "优惠劵不处于待使用状态"); | 34 | ErrorCode COUPON_STATUS_NOT_UNUSED = new ErrorCode(1006003003, "优惠劵不处于待使用状态"); |
| 35 | - ErrorCode COUPON_VALID_TIME_NOT_NOW = new ErrorCode(1006003004, "优惠劵不在有效期内"); | 35 | + ErrorCode COUPON_VALID_TIME_NOT_NOW = new ErrorCode(1006003004, "优惠券不在使用时间范围内"); |
| 36 | 36 | ||
| 37 | // ========== 满减送活动 1003006000 ========== | 37 | // ========== 满减送活动 1003006000 ========== |
| 38 | ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1003006000, "满减送活动不存在"); | 38 | ErrorCode REWARD_ACTIVITY_NOT_EXISTS = new ErrorCode(1003006000, "满减送活动不存在"); |
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceImpl.java
| @@ -116,7 +116,8 @@ public class PriceServiceImpl implements PriceService { | @@ -116,7 +116,8 @@ public class PriceServiceImpl implements PriceService { | ||
| 116 | assert originPrice != null; | 116 | assert originPrice != null; |
| 117 | if (originPrice < coupon.getUsePrice()) { | 117 | if (originPrice < coupon.getUsePrice()) { |
| 118 | return couponMeetRespDTO.setMeet(false) | 118 | return couponMeetRespDTO.setMeet(false) |
| 119 | - .setMeetTip(String.format("差 %s 元可用优惠劵", formatPrice(coupon.getUsePrice() - originPrice))); | 119 | +// .setMeetTip(String.format("差 %s 元可用优惠劵", formatPrice(coupon.getUsePrice() - originPrice))); |
| 120 | + .setMeetTip("所结算的商品中未满足使用的金额"); | ||
| 120 | } | 121 | } |
| 121 | } catch (ServiceException serviceException) { | 122 | } catch (ServiceException serviceException) { |
| 122 | couponMeetRespDTO.setMeet(false); | 123 | couponMeetRespDTO.setMeet(false); |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
| @@ -12,10 +12,12 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; | @@ -12,10 +12,12 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; | ||
| 12 | public interface ErrorCodeConstants { | 12 | public interface ErrorCodeConstants { |
| 13 | 13 | ||
| 14 | // ========== Order 模块 1-011-000-000 ========== | 14 | // ========== Order 模块 1-011-000-000 ========== |
| 15 | - ErrorCode ORDER_SKU_NOT_FOUND = new ErrorCode(1011000001, "商品不存在"); | ||
| 16 | - ErrorCode ORDER_SPU_NOT_SALE = new ErrorCode(1011000002, "商品不可售卖"); | ||
| 17 | - ErrorCode ORDER_SKU_NOT_SALE = new ErrorCode(1011000003, "商品Sku不可售卖"); | ||
| 18 | - ErrorCode ORDER_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1011000004, "商品库存不足"); | 15 | + ErrorCode ORDER_CREATE_SKU_NOT_FOUND = new ErrorCode(1011000001, "商品 SKU 不存在"); |
| 16 | + ErrorCode ORDER_CREATE_SPU_NOT_SALE = new ErrorCode(1011000002, "商品 SPU 不可售卖"); | ||
| 17 | + ErrorCode ORDER_CREATE_SKU_NOT_SALE = new ErrorCode(1011000003, "商品 SKU 不可售卖"); | ||
| 18 | + ErrorCode ORDER_CREATE_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1011000004, "商品 SKU 库存不足"); | ||
| 19 | + ErrorCode ORDER_CREATE_SPU_NOT_FOUND = new ErrorCode(1011000005, "商品 SPU 不可售卖"); | ||
| 20 | + ErrorCode ORDER_CREATE_ADDRESS_NOT_FOUND = new ErrorCode(1011000006, "收货地址不存在"); | ||
| 19 | 21 | ||
| 20 | // ========== Cart 模块 1-011-001-000 ========== | 22 | // ========== Cart 模块 1-011-001-000 ========== |
| 21 | ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1001001000, "购物车项不存在"); | 23 | ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1001001000, "购物车项不存在"); |
yudao-module-mall/yudao-module-trade-biz/pom.xml
| @@ -29,18 +29,21 @@ | @@ -29,18 +29,21 @@ | ||
| 29 | <artifactId>yudao-module-product-api</artifactId> | 29 | <artifactId>yudao-module-product-api</artifactId> |
| 30 | <version>${revision}</version> | 30 | <version>${revision}</version> |
| 31 | </dependency> | 31 | </dependency> |
| 32 | - | ||
| 33 | <dependency> | 32 | <dependency> |
| 34 | <groupId>cn.iocoder.boot</groupId> | 33 | <groupId>cn.iocoder.boot</groupId> |
| 35 | <artifactId>yudao-module-pay-api</artifactId> | 34 | <artifactId>yudao-module-pay-api</artifactId> |
| 36 | <version>${revision}</version> | 35 | <version>${revision}</version> |
| 37 | </dependency> | 36 | </dependency> |
| 38 | - | ||
| 39 | <dependency> | 37 | <dependency> |
| 40 | <groupId>cn.iocoder.boot</groupId> | 38 | <groupId>cn.iocoder.boot</groupId> |
| 41 | <artifactId>yudao-module-promotion-api</artifactId> | 39 | <artifactId>yudao-module-promotion-api</artifactId> |
| 42 | <version>${revision}</version> | 40 | <version>${revision}</version> |
| 43 | </dependency> | 41 | </dependency> |
| 42 | + <dependency> | ||
| 43 | + <groupId>cn.iocoder.boot</groupId> | ||
| 44 | + <artifactId>yudao-module-member-api</artifactId> | ||
| 45 | + <version>${revision}</version> | ||
| 46 | + </dependency> | ||
| 44 | 47 | ||
| 45 | <!-- 业务组件 --> | 48 | <!-- 业务组件 --> |
| 46 | <dependency> | 49 | <dependency> |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java
| @@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty; | @@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty; | ||
| 5 | import lombok.Data; | 5 | import lombok.Data; |
| 6 | 6 | ||
| 7 | import javax.validation.constraints.Min; | 7 | import javax.validation.constraints.Min; |
| 8 | +import javax.validation.constraints.NotEmpty; | ||
| 8 | import javax.validation.constraints.NotNull; | 9 | import javax.validation.constraints.NotNull; |
| 9 | import java.util.List; | 10 | import java.util.List; |
| 10 | 11 | ||
| @@ -14,7 +15,7 @@ public class AppTradeOrderCreateReqVO { | @@ -14,7 +15,7 @@ public class AppTradeOrderCreateReqVO { | ||
| 14 | 15 | ||
| 15 | @ApiModelProperty(name = "收件地址编号", required = true, example = "1") | 16 | @ApiModelProperty(name = "收件地址编号", required = true, example = "1") |
| 16 | @NotNull(message = "收件地址不能为空") | 17 | @NotNull(message = "收件地址不能为空") |
| 17 | - private Integer addressId; | 18 | + private Long addressId; |
| 18 | 19 | ||
| 19 | @ApiModelProperty(name = "优惠劵编号", example = "1024") | 20 | @ApiModelProperty(name = "优惠劵编号", example = "1024") |
| 20 | private Long couponId; | 21 | private Long couponId; |
| @@ -29,7 +30,7 @@ public class AppTradeOrderCreateReqVO { | @@ -29,7 +30,7 @@ public class AppTradeOrderCreateReqVO { | ||
| 29 | /** | 30 | /** |
| 30 | * 订单商品项列表 | 31 | * 订单商品项列表 |
| 31 | */ | 32 | */ |
| 32 | - @NotNull(message = "必须选择购买的商品") | 33 | + @NotEmpty(message = "必须选择购买的商品") |
| 33 | private List<Item> items; | 34 | private List<Item> items; |
| 34 | 35 | ||
| 35 | @ApiModel(value = "订单商品项") | 36 | @ApiModel(value = "订单商品项") |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
| 1 | package cn.iocoder.yudao.module.trade.convert.order; | 1 | package cn.iocoder.yudao.module.trade.convert.order; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 4 | +import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | ||
| 5 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 3 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | 6 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; |
| 4 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; | 7 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; |
| 5 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| 9 | +import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; | ||
| 10 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemRefundStatusEnum; | ||
| 6 | import org.mapstruct.Mapper; | 11 | import org.mapstruct.Mapper; |
| 7 | import org.mapstruct.Mapping; | 12 | import org.mapstruct.Mapping; |
| 8 | import org.mapstruct.Mappings; | 13 | import org.mapstruct.Mappings; |
| 9 | import org.mapstruct.factory.Mappers; | 14 | import org.mapstruct.factory.Mappers; |
| 10 | 15 | ||
| 16 | +import java.util.List; | ||
| 17 | +import java.util.Map; | ||
| 18 | + | ||
| 19 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||
| 20 | + | ||
| 11 | @Mapper | 21 | @Mapper |
| 12 | public interface TradeOrderConvert { | 22 | public interface TradeOrderConvert { |
| 13 | 23 | ||
| 14 | TradeOrderConvert INSTANCE = Mappers.getMapper(TradeOrderConvert.class); | 24 | TradeOrderConvert INSTANCE = Mappers.getMapper(TradeOrderConvert.class); |
| 15 | 25 | ||
| 16 | @Mappings({ | 26 | @Mappings({ |
| 17 | - @Mapping(source = "order.couponId", target = "couponId"), | 27 | + @Mapping(source = "createReqVO.couponId", target = "couponId"), |
| 18 | @Mapping(target = "remark", ignore = true), | 28 | @Mapping(target = "remark", ignore = true), |
| 19 | - @Mapping(source = "createVO.remark", target = "userRemark"), | ||
| 20 | - @Mapping(source = "createVO.addressId", target = "receiverAreaId") | 29 | + @Mapping(source = "createReqVO.remark", target = "userRemark"), |
| 30 | + @Mapping(source = "address.name", target = "receiverName"), | ||
| 31 | + @Mapping(source = "address.mobile", target = "receiverMobile"), | ||
| 32 | + @Mapping(source = "address.areaId", target = "receiverAreaId"), | ||
| 33 | + @Mapping(source = "address.postCode", target = "receiverPostCode"), | ||
| 34 | + @Mapping(source = "address.detailAddress", target = "receiverDetailAddress"), | ||
| 35 | + }) | ||
| 36 | + TradeOrderDO convert(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO, | ||
| 37 | + PriceCalculateRespDTO.Order order, AddressRespDTO address); | ||
| 38 | + | ||
| 39 | + @Mappings({ | ||
| 40 | + @Mapping(target = "id", ignore = true), | ||
| 41 | + @Mapping(source = "sku.spuId", target = "spuId"), | ||
| 21 | }) | 42 | }) |
| 22 | - TradeOrderDO convert(AppTradeOrderCreateReqVO createVO, PriceCalculateRespDTO.Order order); | 43 | + TradeOrderItemDO convert(PriceCalculateRespDTO.OrderItem orderItem, ProductSkuRespDTO sku); |
| 44 | + | ||
| 45 | + default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrderDO, | ||
| 46 | + List<PriceCalculateRespDTO.OrderItem> orderItems, List<ProductSkuRespDTO> skus) { | ||
| 47 | + Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId); | ||
| 48 | + return CollectionUtils.convertList(orderItems, orderItem -> { | ||
| 49 | + TradeOrderItemDO tradeOrderItemDO = convert(orderItem, skuMap.get(orderItem.getSkuId())); | ||
| 50 | + tradeOrderItemDO.setOrderId(tradeOrderDO.getId()); | ||
| 51 | + tradeOrderItemDO.setUserId(tradeOrderDO.getUserId()); | ||
| 52 | + tradeOrderItemDO.setRefundStatus(TradeOrderItemRefundStatusEnum.NONE.getStatus()); | ||
| 53 | +// tradeOrderItemDO.setCommented(false); | ||
| 54 | + return tradeOrderItemDO; | ||
| 55 | + }); | ||
| 56 | + } | ||
| 23 | 57 | ||
| 24 | } | 58 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderItemConvert.java deleted
| 1 | -package cn.iocoder.yudao.module.trade.convert.order; | ||
| 2 | - | ||
| 3 | -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | ||
| 4 | -import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; | ||
| 5 | -import org.mapstruct.Mapper; | ||
| 6 | -import org.mapstruct.factory.Mappers; | ||
| 7 | - | ||
| 8 | -import java.util.List; | ||
| 9 | - | ||
| 10 | -@Mapper | ||
| 11 | -public interface TradeOrderItemConvert { | ||
| 12 | - | ||
| 13 | - TradeOrderItemConvert INSTANCE = Mappers.getMapper(TradeOrderItemConvert.class); | ||
| 14 | - | ||
| 15 | - List<TradeOrderItemDO> convertList(List<PriceCalculateRespDTO.OrderItem> items); | ||
| 16 | - | ||
| 17 | -} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
| @@ -70,13 +70,13 @@ public class TradeOrderItemDO extends BaseDO { | @@ -70,13 +70,13 @@ public class TradeOrderItemDO extends BaseDO { | ||
| 70 | * 购买数量 | 70 | * 购买数量 |
| 71 | */ | 71 | */ |
| 72 | private Integer count; | 72 | private Integer count; |
| 73 | - /** | ||
| 74 | - * 是否评论 TODO | ||
| 75 | - * | ||
| 76 | - * false - 未评论 | ||
| 77 | - * true - 已评论 | ||
| 78 | - */ | ||
| 79 | - private Boolean commented; | 73 | +// /** |
| 74 | +// * 是否评论 TODO | ||
| 75 | +// * | ||
| 76 | +// * false - 未评论 | ||
| 77 | +// * true - 已评论 | ||
| 78 | +// */ | ||
| 79 | +// private Boolean commented; | ||
| 80 | 80 | ||
| 81 | // ========== 价格 + 支付基本信息 ========== | 81 | // ========== 价格 + 支付基本信息 ========== |
| 82 | 82 | ||
| @@ -138,19 +138,19 @@ public class TradeOrderItemDO extends BaseDO { | @@ -138,19 +138,19 @@ public class TradeOrderItemDO extends BaseDO { | ||
| 138 | * 枚举 {@link TradeOrderItemRefundStatusEnum} | 138 | * 枚举 {@link TradeOrderItemRefundStatusEnum} |
| 139 | */ | 139 | */ |
| 140 | private Integer refundStatus; // TODO 芋艿:可以考虑去查 | 140 | private Integer refundStatus; // TODO 芋艿:可以考虑去查 |
| 141 | - // 如上字段,举个例子: | ||
| 142 | - // 假设购买三个,即 stock = 3 。 | ||
| 143 | - // originPrice = 15 | ||
| 144 | - // 使用限时折扣(单品优惠)8 折,buyPrice = 12 | ||
| 145 | - // 开始算总的价格 | ||
| 146 | - // buyTotal = buyPrice * stock = 12 * 3 = 36 | ||
| 147 | - // discountTotal ,假设有满减送(分组优惠)满 20 减 10 ,并且使用优惠劵满 1.01 减 1 ,则 discountTotal = 10 + 1 = 11 | ||
| 148 | - // presentTotal = buyTotal - discountTotal = 24 - 11 = 13 | ||
| 149 | - // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33 | ||
| 150 | - /** | ||
| 151 | - * 退款总金额,单位:分 TODO | ||
| 152 | - */ | ||
| 153 | - private Integer refundTotal; | 141 | +// // 如上字段,举个例子: |
| 142 | +// // 假设购买三个,即 stock = 3 。 | ||
| 143 | +// // originPrice = 15 | ||
| 144 | +// // 使用限时折扣(单品优惠)8 折,buyPrice = 12 | ||
| 145 | +// // 开始算总的价格 | ||
| 146 | +// // buyTotal = buyPrice * stock = 12 * 3 = 36 | ||
| 147 | +// // discountTotal ,假设有满减送(分组优惠)满 20 减 10 ,并且使用优惠劵满 1.01 减 1 ,则 discountTotal = 10 + 1 = 11 | ||
| 148 | +// // presentTotal = buyTotal - discountTotal = 24 - 11 = 13 | ||
| 149 | +// // 最终 presentPrice = presentTotal / stock = 13 / 3 = 4.33 | ||
| 150 | +// /** | ||
| 151 | +// * 退款总金额,单位:分 TODO | ||
| 152 | +// */ | ||
| 153 | +// private Integer refundTotal; | ||
| 154 | 154 | ||
| 155 | /** | 155 | /** |
| 156 | * 商品属性 | 156 | * 商品属性 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
| @@ -3,29 +3,27 @@ package cn.iocoder.yudao.module.trade.service.order; | @@ -3,29 +3,27 @@ package cn.iocoder.yudao.module.trade.service.order; | ||
| 3 | import cn.hutool.core.bean.BeanUtil; | 3 | import cn.hutool.core.bean.BeanUtil; |
| 4 | import cn.hutool.core.text.StrBuilder; | 4 | import cn.hutool.core.text.StrBuilder; |
| 5 | import cn.hutool.core.util.IdUtil; | 5 | import cn.hutool.core.util.IdUtil; |
| 6 | +import cn.hutool.core.util.ObjectUtil; | ||
| 6 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 7 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 7 | import cn.iocoder.yudao.framework.common.enums.TerminalEnum; | 8 | import cn.iocoder.yudao.framework.common.enums.TerminalEnum; |
| 8 | -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil; | ||
| 9 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 9 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 10 | import cn.iocoder.yudao.framework.common.util.string.StrUtils; | 10 | import cn.iocoder.yudao.framework.common.util.string.StrUtils; |
| 11 | -import cn.iocoder.yudao.module.promotion.api.price.PriceApi; | ||
| 12 | -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; | ||
| 13 | -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | 11 | +import cn.iocoder.yudao.module.member.api.address.AddressApi; |
| 12 | +import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | ||
| 14 | import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; | 13 | import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; |
| 15 | import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO; | 14 | import cn.iocoder.yudao.module.pay.api.order.PayOrderInfoCreateReqDTO; |
| 16 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | 15 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |
| 17 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | 16 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 18 | -import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; | ||
| 19 | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | 17 | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; |
| 20 | -import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; | 18 | +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; |
| 21 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | 19 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; |
| 20 | +import cn.iocoder.yudao.module.promotion.api.price.PriceApi; | ||
| 21 | +import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; | ||
| 22 | +import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | ||
| 22 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; | 23 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; |
| 23 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO.Item; | 24 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO.Item; |
| 24 | import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; | 25 | import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; |
| 25 | -import cn.iocoder.yudao.module.trade.convert.order.TradeOrderItemConvert; | ||
| 26 | -import cn.iocoder.yudao.module.trade.convert.pay.PayOrderConvert; | ||
| 27 | import cn.iocoder.yudao.module.trade.convert.price.PriceConvert; | 26 | import cn.iocoder.yudao.module.trade.convert.price.PriceConvert; |
| 28 | -import cn.iocoder.yudao.module.trade.convert.sku.ProductSkuConvert; | ||
| 29 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | 27 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| 30 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; | 28 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; |
| 31 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; | 29 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; |
| @@ -43,6 +41,12 @@ import javax.annotation.Resource; | @@ -43,6 +41,12 @@ import javax.annotation.Resource; | ||
| 43 | import java.util.List; | 41 | import java.util.List; |
| 44 | import java.util.Map; | 42 | import java.util.Map; |
| 45 | import java.util.Objects; | 43 | import java.util.Objects; |
| 44 | +import java.util.Set; | ||
| 45 | + | ||
| 46 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 47 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||
| 48 | +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_CREATE_SKU_NOT_SALE; | ||
| 49 | +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.ORDER_CREATE_SPU_NOT_FOUND; | ||
| 46 | 50 | ||
| 47 | /** | 51 | /** |
| 48 | * 交易订单 Service 实现类 | 52 | * 交易订单 Service 实现类 |
| @@ -70,66 +74,51 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -70,66 +74,51 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 70 | private ProductSpuApi productSpuApi; | 74 | private ProductSpuApi productSpuApi; |
| 71 | @Resource | 75 | @Resource |
| 72 | private PayOrderApi payOrderApi; | 76 | private PayOrderApi payOrderApi; |
| 77 | + @Resource | ||
| 78 | + private AddressApi addressApi; | ||
| 73 | 79 | ||
| 74 | @Resource | 80 | @Resource |
| 75 | private TradeOrderProperties tradeOrderProperties; | 81 | private TradeOrderProperties tradeOrderProperties; |
| 76 | 82 | ||
| 77 | @Override | 83 | @Override |
| 78 | @Transactional(rollbackFor = Exception.class) | 84 | @Transactional(rollbackFor = Exception.class) |
| 79 | - public Long createTradeOrder(Long loginUserId, String clientIp, AppTradeOrderCreateReqVO createReqVO) { | ||
| 80 | - List<Item> items = createReqVO.getItems(); | ||
| 81 | - // 商品SKU检查 sku可售状态,库存 | ||
| 82 | - List<ProductSkuRespDTO> skuInfos = productSkuApi.getSkuList(CollectionUtils.convertSet(items, Item::getSkuId)); | ||
| 83 | - Map<Long, ProductSkuRespDTO> skuInfoMap = CollectionUtils.convertMap(skuInfos, ProductSkuRespDTO::getId); | ||
| 84 | - checkSaleableAndStockFromSpu(skuInfoMap, items); | ||
| 85 | - | ||
| 86 | - // 商品SPU检查 sku可售状态,库存 | ||
| 87 | - List<SpuInfoRespDTO> spuInfos = productSpuApi.getSpuList(CollectionUtils.convertSet(skuInfos, ProductSkuRespDTO::getSpuId)); | ||
| 88 | - checkSaleableFromSpu(spuInfos); | 85 | + public Long createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO) { |
| 86 | + // 商品 SKU 检查:可售状态、库存 | ||
| 87 | + List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems()); | ||
| 88 | + // 商品 SPU 检查:可售状态 | ||
| 89 | + List<ProductSpuRespDTO> spus = validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId)); | ||
| 90 | + // 用户收件地址的校验 | ||
| 91 | + AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId()); | ||
| 89 | 92 | ||
| 90 | // 价格计算 | 93 | // 价格计算 |
| 91 | - PriceCalculateReqDTO priceCalculateReqDTO = PriceConvert.INSTANCE.convert(createReqVO, loginUserId); | 94 | + PriceCalculateReqDTO priceCalculateReqDTO = PriceConvert.INSTANCE.convert(createReqVO, userId); |
| 92 | PriceCalculateRespDTO priceResp = priceApi.calculatePrice(priceCalculateReqDTO); | 95 | PriceCalculateRespDTO priceResp = priceApi.calculatePrice(priceCalculateReqDTO); |
| 93 | - // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来! | ||
| 94 | 96 | ||
| 95 | - // 订单信息记录 | ||
| 96 | - TradeOrderDO tradeOrderDO = TradeOrderConvert.INSTANCE.convert(createReqVO, priceResp.getOrder()); | ||
| 97 | - fillTradeOrderInfoFromReqInfo(tradeOrderDO,createReqVO,loginUserId, clientIp); // TODO @LeeYan9: tradeOrderDO, createReqVO, loginUserId, clientIp | ||
| 98 | - tradeOrderMapper.insert(tradeOrderDO); | 97 | + // 插入 TradeOrderDO 订单 |
| 98 | + TradeOrderDO tradeOrderDO = createTradeOrder(userId, clientIp, createReqVO, priceResp.getOrder(), address); | ||
| 99 | + // 插入 TradeOrderItemDO 订单项 | ||
| 100 | + createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus); | ||
| 101 | + | ||
| 102 | + // 下单时扣减商品库存 TODO | ||
| 103 | +// List<SkuDecrementStockBatchReqDTO.Item> skuDecrementStockItems = ProductSkuConvert.INSTANCE.convert(tradeOrderItems); | ||
| 104 | +// productSkuApi.decrementStockBatch(SkuDecrementStockBatchReqDTO.of(skuDecrementStockItems)); | ||
| 105 | + | ||
| 106 | + // 删除购物车商品 TODO 芋艿:待实现 | ||
| 99 | 107 | ||
| 100 | - // 订单项信息记录 | ||
| 101 | - List<TradeOrderItemDO> tradeOrderItems = TradeOrderItemConvert.INSTANCE.convertList(priceResp.getOrder().getItems()); | ||
| 102 | - // 填充订单项-SKU信息 | ||
| 103 | - fillItemsInfoFromSkuAndOrder(tradeOrderDO, tradeOrderItems, skuInfoMap); | ||
| 104 | - tradeOrderItemMapper.insertBatch(tradeOrderItems); | 108 | + // 扣减积分,抵扣金额 TODO 芋艿:待实现 |
| 105 | 109 | ||
| 106 | - // TODO @LeeYan9: 先扣减库存哈; 可能会扣减失败; 毕竟 get 和 update 之间, 会有并发的可能性 | ||
| 107 | - // 库存扣减 | ||
| 108 | - List<SkuDecrementStockBatchReqDTO.Item> skuDecrementStockItems = ProductSkuConvert.INSTANCE.convert(tradeOrderItems); | ||
| 109 | - productSkuApi.decrementStockBatch(SkuDecrementStockBatchReqDTO.of(skuDecrementStockItems)); | 110 | + // 有使用优惠券时更新 |
| 111 | + | ||
| 112 | + // 增加订单日志 TODO 芋艿:待实现 | ||
| 110 | 113 | ||
| 111 | // 构建预支付请求参数 | 114 | // 构建预支付请求参数 |
| 112 | // TODO @LeeYan9: 需要更新到订单上 | 115 | // TODO @LeeYan9: 需要更新到订单上 |
| 113 | - PayOrderInfoCreateReqDTO payOrderCreateReqDTO = PayOrderConvert.INSTANCE.convert(tradeOrderDO); | ||
| 114 | - fillPayOrderInfoFromItems(payOrderCreateReqDTO, tradeOrderItems); | 116 | +// PayOrderInfoCreateReqDTO payOrderCreateReqDTO = PayOrderConvert.INSTANCE.convert(tradeOrderDO); |
| 117 | +// fillPayOrderInfoFromItems(payOrderCreateReqDTO, tradeOrderItems); | ||
| 115 | // 生成预支付 | 118 | // 生成预支付 |
| 116 | - return payOrderApi.createPayOrder(payOrderCreateReqDTO); | ||
| 117 | - } | ||
| 118 | - | ||
| 119 | - // TODO @LeeYan9: 填充就好, 不用 from 哈; | ||
| 120 | - private void fillTradeOrderInfoFromReqInfo(TradeOrderDO tradeOrderDO, AppTradeOrderCreateReqVO createReqVO, | ||
| 121 | - Long loginUserId, String clientIp) { | ||
| 122 | - tradeOrderDO.setUserId(loginUserId); | ||
| 123 | - tradeOrderDO.setUserIp(clientIp); | ||
| 124 | - tradeOrderDO.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的; | ||
| 125 | - tradeOrderDO.setStatus(TradeOrderStatusEnum.WAITING_PAYMENT.getStatus()); | ||
| 126 | - tradeOrderDO.setType(TradeOrderTypeEnum.NORMAL.getType()); | ||
| 127 | - tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); | ||
| 128 | - tradeOrderDO.setProductCount(CollectionUtils.getSumValue(createReqVO.getItems(), Item::getCount,Integer::sum)); | ||
| 129 | - // todo 地址&用户信息解析 | ||
| 130 | 119 | ||
| 131 | - // todo 数据来源? | ||
| 132 | - tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); | 120 | + // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来! |
| 121 | + return tradeOrderDO.getId(); | ||
| 133 | } | 122 | } |
| 134 | 123 | ||
| 135 | private void fillPayOrderInfoFromItems(PayOrderInfoCreateReqDTO payOrderInfoCreateReqDTO, | 124 | private void fillPayOrderInfoFromItems(PayOrderInfoCreateReqDTO payOrderInfoCreateReqDTO, |
| @@ -157,7 +146,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -157,7 +146,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 157 | payOrderInfoCreateReqDTO.setBody(StrUtils.maxLength(body.subString(1), 128)); | 146 | payOrderInfoCreateReqDTO.setBody(StrUtils.maxLength(body.subString(1), 128)); |
| 158 | } | 147 | } |
| 159 | 148 | ||
| 160 | - private void fillItemsInfoFromSkuAndOrder(TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItems, | 149 | + private void xfillItemsInfoFromSkuAndOrder(TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItems, |
| 161 | Map<Long, ProductSkuRespDTO> spuInfos) { | 150 | Map<Long, ProductSkuRespDTO> spuInfos) { |
| 162 | for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) { | 151 | for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) { |
| 163 | // 填充订单信息 | 152 | // 填充订单信息 |
| @@ -176,32 +165,87 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -176,32 +165,87 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 176 | } | 165 | } |
| 177 | } | 166 | } |
| 178 | 167 | ||
| 179 | - private void checkSaleableFromSpu(List<SpuInfoRespDTO> spuInfos) { | ||
| 180 | - SpuInfoRespDTO spu = CollectionUtils.findFirst(spuInfos, | ||
| 181 | - spuInfoDTO -> !Objects.equals(ProductSpuStatusEnum.ENABLE.getStatus(), spuInfoDTO.getStatus())); | ||
| 182 | - if (Objects.isNull(spu)) { | ||
| 183 | - throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SPU_NOT_SALE); | 168 | + /** |
| 169 | + * 校验商品 SKU 是否可出售 | ||
| 170 | + * | ||
| 171 | + * @param items 商品 SKU | ||
| 172 | + * @return 商品 SKU 数组 | ||
| 173 | + */ | ||
| 174 | + private List<ProductSkuRespDTO> validateSkuSaleable(List<Item> items) { | ||
| 175 | + List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(convertSet(items, Item::getSkuId)); | ||
| 176 | + // SKU 不存在 | ||
| 177 | + if (items.size() != skus.size()) { | ||
| 178 | + throw exception(ErrorCodeConstants.ORDER_CREATE_SKU_NOT_FOUND); | ||
| 184 | } | 179 | } |
| 180 | + // 校验是否禁用 or 库存不足 | ||
| 181 | + Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId); | ||
| 182 | + items.forEach(item -> { | ||
| 183 | + ProductSkuRespDTO sku = skuMap.get(item.getSkuId()); | ||
| 184 | + // SKU 禁用 | ||
| 185 | + if (ObjectUtil.notEqual(CommonStatusEnum.ENABLE.getStatus(), sku.getStatus())) { | ||
| 186 | + throw exception(ORDER_CREATE_SKU_NOT_SALE); | ||
| 187 | + } | ||
| 188 | + // SKU 库存不足 | ||
| 189 | + if (item.getCount() > sku.getStock()) { | ||
| 190 | + throw exception(ErrorCodeConstants.ORDER_CREATE_SKU_STOCK_NOT_ENOUGH); | ||
| 191 | + } | ||
| 192 | + }); | ||
| 193 | + return skus; | ||
| 185 | } | 194 | } |
| 186 | 195 | ||
| 187 | - // TODO @LeeYan9: checkSpuXXX 会不会好点哈? ps: 这个貌似是 sku 哈 | ||
| 188 | - private void checkSaleableAndStockFromSpu(Map<Long, ProductSkuRespDTO> skuInfoMap, | ||
| 189 | - List<Item> items) { | ||
| 190 | - // sku 不存在 | ||
| 191 | - if (items.size() != skuInfoMap.size()) { | ||
| 192 | - throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SKU_NOT_FOUND); | 196 | + /** |
| 197 | + * 校验商品 SPU 是否可出售 | ||
| 198 | + * | ||
| 199 | + * @param spuIds 商品 SPU 编号数组 | ||
| 200 | + * @return 商品 SPU 数组 | ||
| 201 | + */ | ||
| 202 | + private List<ProductSpuRespDTO> validateSpuSaleable(Set<Long> spuIds) { | ||
| 203 | + List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(spuIds); | ||
| 204 | + // SPU 不存在 | ||
| 205 | + if (spus.size() != spuIds.size()) { | ||
| 206 | + throw exception(ORDER_CREATE_SPU_NOT_FOUND); | ||
| 193 | } | 207 | } |
| 194 | - for (Item item : items) { | ||
| 195 | - ProductSkuRespDTO skuInfoDTO = skuInfoMap.get(item.getSkuId()); | ||
| 196 | - // sku禁用 | ||
| 197 | - if (!Objects.equals(CommonStatusEnum.ENABLE.getStatus(), skuInfoDTO.getStatus())) { | ||
| 198 | - throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SKU_NOT_SALE); | ||
| 199 | - } | ||
| 200 | - // sku库存不足 | ||
| 201 | - if (item.getCount() > skuInfoDTO.getStock()) { | ||
| 202 | - throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SKU_STOCK_NOT_ENOUGH); | ||
| 203 | - } | 208 | + // 校验是否存在禁用的 SPU |
| 209 | + ProductSpuRespDTO spu = CollectionUtils.findFirst(spus, | ||
| 210 | + spuDTO -> ObjectUtil.notEqual(ProductSpuStatusEnum.ENABLE.getStatus(), spuDTO.getStatus())); | ||
| 211 | + if (Objects.isNull(spu)) { | ||
| 212 | + throw exception(ErrorCodeConstants.ORDER_CREATE_SPU_NOT_SALE); | ||
| 204 | } | 213 | } |
| 214 | + return spus; | ||
| 215 | + } | ||
| 205 | 216 | ||
| 217 | + /** | ||
| 218 | + * 校验收件地址是否存在 | ||
| 219 | + * | ||
| 220 | + * @param userId 用户编号 | ||
| 221 | + * @param addressId 收件地址编号 | ||
| 222 | + * @return 收件地址 | ||
| 223 | + */ | ||
| 224 | + private AddressRespDTO validateAddress(Long userId, Long addressId) { | ||
| 225 | + AddressRespDTO address = addressApi.getAddress(userId, addressId); | ||
| 226 | + if (Objects.isNull(address)) { | ||
| 227 | + throw exception(ErrorCodeConstants.ORDER_CREATE_ADDRESS_NOT_FOUND); | ||
| 228 | + } | ||
| 229 | + return address; | ||
| 206 | } | 230 | } |
| 231 | + | ||
| 232 | + private TradeOrderDO createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO, | ||
| 233 | + PriceCalculateRespDTO.Order order, AddressRespDTO address) { | ||
| 234 | + TradeOrderDO tradeOrderDO = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, order, address); | ||
| 235 | + tradeOrderDO.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的; | ||
| 236 | + tradeOrderDO.setStatus(TradeOrderStatusEnum.WAITING_PAYMENT.getStatus()); | ||
| 237 | + tradeOrderDO.setType(TradeOrderTypeEnum.NORMAL.getType()); | ||
| 238 | + tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); | ||
| 239 | + tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum)); | ||
| 240 | + tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? | ||
| 241 | + tradeOrderMapper.insert(tradeOrderDO); | ||
| 242 | + return tradeOrderDO; | ||
| 243 | + } | ||
| 244 | + | ||
| 245 | + private void createTradeOrderItems(TradeOrderDO tradeOrderDO, | ||
| 246 | + List<PriceCalculateRespDTO.OrderItem> orderItems, List<ProductSkuRespDTO> skus) { | ||
| 247 | + List<TradeOrderItemDO> tradeOrderItemDOs = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, orderItems, skus); | ||
| 248 | + tradeOrderItemMapper.insertBatch(tradeOrderItemDOs); | ||
| 249 | + } | ||
| 250 | + | ||
| 207 | } | 251 | } |
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/AddressApi.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.member.api.address; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 用户收件地址 API 接口 | ||
| 7 | + * | ||
| 8 | + * @author 芋道源码 | ||
| 9 | + */ | ||
| 10 | +public interface AddressApi { | ||
| 11 | + | ||
| 12 | + /** | ||
| 13 | + * 获得用户收件地址 | ||
| 14 | + * | ||
| 15 | + * @param id 收件地址编号 | ||
| 16 | + * @param userId 用户编号 | ||
| 17 | + * @return 用户收件地址 | ||
| 18 | + */ | ||
| 19 | + AddressRespDTO getAddress(Long id, Long userId); | ||
| 20 | + | ||
| 21 | +} |
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/dto/AddressRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.member.api.address.dto; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 用户收件地址 Response DTO | ||
| 7 | + * | ||
| 8 | + * @author 芋道源码 | ||
| 9 | + */ | ||
| 10 | +@Data | ||
| 11 | +public class AddressRespDTO { | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * 编号 | ||
| 15 | + */ | ||
| 16 | + private Long id; | ||
| 17 | + /** | ||
| 18 | + * 用户编号 | ||
| 19 | + */ | ||
| 20 | + private Long userId; | ||
| 21 | + /** | ||
| 22 | + * 收件人名称 | ||
| 23 | + */ | ||
| 24 | + private String name; | ||
| 25 | + /** | ||
| 26 | + * 手机号 | ||
| 27 | + */ | ||
| 28 | + private String mobile; | ||
| 29 | + /** | ||
| 30 | + * 地区编号 | ||
| 31 | + */ | ||
| 32 | + private Long areaId; | ||
| 33 | + /** | ||
| 34 | + * 邮编 | ||
| 35 | + */ | ||
| 36 | + private String postCode; | ||
| 37 | + /** | ||
| 38 | + * 收件详细地址 | ||
| 39 | + */ | ||
| 40 | + private String detailAddress; | ||
| 41 | + /** | ||
| 42 | + * 是否默认 | ||
| 43 | + * | ||
| 44 | + * true - 默认收件地址 | ||
| 45 | + */ | ||
| 46 | + private Boolean defaulted; | ||
| 47 | + | ||
| 48 | +} |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/address/AddressApiImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.member.api.address; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | ||
| 4 | +import cn.iocoder.yudao.module.member.convert.address.AddressConvert; | ||
| 5 | +import cn.iocoder.yudao.module.member.service.address.AddressService; | ||
| 6 | +import org.springframework.stereotype.Service; | ||
| 7 | +import org.springframework.validation.annotation.Validated; | ||
| 8 | + | ||
| 9 | +import javax.annotation.Resource; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 用户收件地址 API 实现类 | ||
| 13 | + * | ||
| 14 | + * @author 芋道源码 | ||
| 15 | + */ | ||
| 16 | +@Service | ||
| 17 | +@Validated | ||
| 18 | +public class AddressApiImpl implements AddressApi { | ||
| 19 | + | ||
| 20 | + @Resource | ||
| 21 | + private AddressService addressService; | ||
| 22 | + | ||
| 23 | + @Override | ||
| 24 | + public AddressRespDTO getAddress(Long id, Long userId) { | ||
| 25 | + return AddressConvert.INSTANCE.convert02(addressService.getAddress(userId, id)); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | +} |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java
| 1 | package cn.iocoder.yudao.module.member.convert.address; | 1 | package cn.iocoder.yudao.module.member.convert.address; |
| 2 | 2 | ||
| 3 | -import java.util.*; | ||
| 4 | - | ||
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | - | 4 | +import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; |
| 5 | +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressRespVO; | ||
| 7 | +import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO; | ||
| 8 | +import cn.iocoder.yudao.module.member.dal.dataobject.address.AddressDO; | ||
| 7 | import org.mapstruct.Mapper; | 9 | import org.mapstruct.Mapper; |
| 8 | import org.mapstruct.factory.Mappers; | 10 | import org.mapstruct.factory.Mappers; |
| 9 | -import cn.iocoder.yudao.module.member.controller.app.address.vo.*; | ||
| 10 | -import cn.iocoder.yudao.module.member.dal.dataobject.address.AddressDO; | 11 | + |
| 12 | +import java.util.List; | ||
| 11 | 13 | ||
| 12 | /** | 14 | /** |
| 13 | * 用户收件地址 Convert | 15 | * 用户收件地址 Convert |
| @@ -29,4 +31,6 @@ public interface AddressConvert { | @@ -29,4 +31,6 @@ public interface AddressConvert { | ||
| 29 | 31 | ||
| 30 | PageResult<AppAddressRespVO> convertPage(PageResult<AddressDO> page); | 32 | PageResult<AppAddressRespVO> convertPage(PageResult<AddressDO> page); |
| 31 | 33 | ||
| 34 | + AddressRespDTO convert02(AddressDO bean); | ||
| 35 | + | ||
| 32 | } | 36 | } |