Commit 15798cea108390075f788ec491ecc3a1f5988d76
1 parent
67d36547
mall:价格计算的 API 简单实现
Showing
39 changed files
with
1017 additions
and
375 deletions
yudao-module-mall/yudao-module-market-api/src/main/java/cn/iocoder/yudao/module/market/api/price/dto/PriceCalculateRespDTO.java
| @@ -20,14 +20,9 @@ public class PriceCalculateRespDTO { | @@ -20,14 +20,9 @@ public class PriceCalculateRespDTO { | ||
| 20 | private Order order; | 20 | private Order order; |
| 21 | 21 | ||
| 22 | /** | 22 | /** |
| 23 | - * 商品 SKU 数组 | ||
| 24 | - */ | ||
| 25 | - private List<Item> items; | ||
| 26 | - | ||
| 27 | - /** | ||
| 28 | * 营销活动数组 | 23 | * 营销活动数组 |
| 29 | * | 24 | * |
| 30 | - * 只对应 {@link #items} 商品匹配的活动 | 25 | + * 只对应 {@link Order#items} 商品匹配的活动 |
| 31 | */ | 26 | */ |
| 32 | private List<Promotion> promotions; | 27 | private List<Promotion> promotions; |
| 33 | 28 | ||
| @@ -40,13 +35,13 @@ public class PriceCalculateRespDTO { | @@ -40,13 +35,13 @@ public class PriceCalculateRespDTO { | ||
| 40 | /** | 35 | /** |
| 41 | * 商品原价(总),单位:分 | 36 | * 商品原价(总),单位:分 |
| 42 | * | 37 | * |
| 43 | - * 基于 {@link Item#getTotalOriginalPrice()} 求和 | 38 | + * 基于 {@link OrderItem#getTotalOriginalPrice()} 求和 |
| 44 | */ | 39 | */ |
| 45 | private Integer skuOriginalPrice; | 40 | private Integer skuOriginalPrice; |
| 46 | /** | 41 | /** |
| 47 | * 商品优惠(总),单位:分 | 42 | * 商品优惠(总),单位:分 |
| 48 | * | 43 | * |
| 49 | - * 基于 {@link Item#getTotalPromotionPrice()} 求和 | 44 | + * 基于 {@link OrderItem#getTotalPromotionPrice()} 求和 |
| 50 | */ | 45 | */ |
| 51 | private Integer skuPromotionPrice; | 46 | private Integer skuPromotionPrice; |
| 52 | /** | 47 | /** |
| @@ -69,6 +64,10 @@ public class PriceCalculateRespDTO { | @@ -69,6 +64,10 @@ public class PriceCalculateRespDTO { | ||
| 69 | */ | 64 | */ |
| 70 | // * - {@link #couponPrice} // TODO 芋艿:靠营销表记录 | 65 | // * - {@link #couponPrice} // TODO 芋艿:靠营销表记录 |
| 71 | private Integer payPrice; | 66 | private Integer payPrice; |
| 67 | + /** | ||
| 68 | + * 商品 SKU 数组 | ||
| 69 | + */ | ||
| 70 | + private List<OrderItem> items; | ||
| 72 | 71 | ||
| 73 | // ========== 营销基本信息 ========== | 72 | // ========== 营销基本信息 ========== |
| 74 | /** | 73 | /** |
| @@ -85,10 +84,15 @@ public class PriceCalculateRespDTO { | @@ -85,10 +84,15 @@ public class PriceCalculateRespDTO { | ||
| 85 | } | 84 | } |
| 86 | 85 | ||
| 87 | /** | 86 | /** |
| 88 | - * 商品 SKU | 87 | + * 订单商品 SKU |
| 89 | */ | 88 | */ |
| 90 | @Data | 89 | @Data |
| 91 | - public static class Item extends PriceCalculateReqDTO.Item { | 90 | + public static class OrderItem extends PriceCalculateReqDTO.Item { |
| 91 | + | ||
| 92 | + /** | ||
| 93 | + * 购买数量 | ||
| 94 | + */ | ||
| 95 | + private Integer count; | ||
| 92 | 96 | ||
| 93 | /** | 97 | /** |
| 94 | * 商品原价(单),单位:分 | 98 | * 商品原价(单),单位:分 |
| @@ -141,6 +145,10 @@ public class PriceCalculateRespDTO { | @@ -141,6 +145,10 @@ public class PriceCalculateRespDTO { | ||
| 141 | */ | 145 | */ |
| 142 | private Long id; | 146 | private Long id; |
| 143 | /** | 147 | /** |
| 148 | + * 营销名字 | ||
| 149 | + */ | ||
| 150 | + private String name; | ||
| 151 | + /** | ||
| 144 | * 营销类型 | 152 | * 营销类型 |
| 145 | * | 153 | * |
| 146 | * 枚举 {@link PromotionTypeEnum} | 154 | * 枚举 {@link PromotionTypeEnum} |
| @@ -153,10 +161,6 @@ public class PriceCalculateRespDTO { | @@ -153,10 +161,6 @@ public class PriceCalculateRespDTO { | ||
| 153 | */ | 161 | */ |
| 154 | private Integer level; | 162 | private Integer level; |
| 155 | /** | 163 | /** |
| 156 | - * 匹配的商品 SKU 数组 | ||
| 157 | - */ | ||
| 158 | - private List<Item> items; | ||
| 159 | - /** | ||
| 160 | * 计算时的原价(总),单位:分 | 164 | * 计算时的原价(总),单位:分 |
| 161 | */ | 165 | */ |
| 162 | private Integer totalOriginalPrice; | 166 | private Integer totalOriginalPrice; |
| @@ -165,6 +169,13 @@ public class PriceCalculateRespDTO { | @@ -165,6 +169,13 @@ public class PriceCalculateRespDTO { | ||
| 165 | */ | 169 | */ |
| 166 | private Integer totalPromotionPrice; | 170 | private Integer totalPromotionPrice; |
| 167 | /** | 171 | /** |
| 172 | + * 匹配的商品 SKU 数组 | ||
| 173 | + */ | ||
| 174 | + private List<PromotionItem> items; | ||
| 175 | + | ||
| 176 | + // ========== 匹配情况 ========== | ||
| 177 | + | ||
| 178 | + /** | ||
| 168 | * 是否满足优惠条件 | 179 | * 是否满足优惠条件 |
| 169 | */ | 180 | */ |
| 170 | private Boolean meet; | 181 | private Boolean meet; |
| @@ -176,26 +187,26 @@ public class PriceCalculateRespDTO { | @@ -176,26 +187,26 @@ public class PriceCalculateRespDTO { | ||
| 176 | */ | 187 | */ |
| 177 | private String meetTip; | 188 | private String meetTip; |
| 178 | 189 | ||
| 179 | - /** | ||
| 180 | - * 匹配的商品 SKU | ||
| 181 | - */ | ||
| 182 | - @Data | ||
| 183 | - public static class Item { | 190 | + } |
| 184 | 191 | ||
| 185 | - /** | ||
| 186 | - * 商品 SKU 编号 | ||
| 187 | - */ | ||
| 188 | - private Long skuId; | ||
| 189 | - /** | ||
| 190 | - * 计算时的原价(总),单位:分 | ||
| 191 | - */ | ||
| 192 | - private Integer totalOriginalPrice; | ||
| 193 | - /** | ||
| 194 | - * 计算时的优惠(总),单位:分 | ||
| 195 | - */ | ||
| 196 | - private Integer totalPromotionPrice; | 192 | + /** |
| 193 | + * 营销匹配的商品 SKU | ||
| 194 | + */ | ||
| 195 | + @Data | ||
| 196 | + public static class PromotionItem { | ||
| 197 | 197 | ||
| 198 | - } | 198 | + /** |
| 199 | + * 商品 SKU 编号 | ||
| 200 | + */ | ||
| 201 | + private Long skuId; | ||
| 202 | + /** | ||
| 203 | + * 计算时的原价(总),单位:分 | ||
| 204 | + */ | ||
| 205 | + private Integer totalOriginalPrice; | ||
| 206 | + /** | ||
| 207 | + * 计算时的优惠(总),单位:分 | ||
| 208 | + */ | ||
| 209 | + private Integer totalPromotionPrice; | ||
| 199 | 210 | ||
| 200 | } | 211 | } |
| 201 | 212 |
yudao-module-mall/yudao-module-market-biz/pom.xml
| @@ -24,6 +24,11 @@ | @@ -24,6 +24,11 @@ | ||
| 24 | <artifactId>yudao-module-market-api</artifactId> | 24 | <artifactId>yudao-module-market-api</artifactId> |
| 25 | <version>${revision}</version> | 25 | <version>${revision}</version> |
| 26 | </dependency> | 26 | </dependency> |
| 27 | + <dependency> | ||
| 28 | + <groupId>cn.iocoder.boot</groupId> | ||
| 29 | + <artifactId>yudao-module-product-api</artifactId> | ||
| 30 | + <version>${revision}</version> | ||
| 31 | + </dependency> | ||
| 27 | 32 | ||
| 28 | <!-- 业务组件 --> | 33 | <!-- 业务组件 --> |
| 29 | <dependency> | 34 | <dependency> |
yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/api/discount/package-info.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.market.api.discount; |
yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceApiImpl.java renamed to yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/api/price/PriceApiImpl.java
| 1 | -package cn.iocoder.yudao.module.market.service.price; | 1 | +package cn.iocoder.yudao.module.market.api.price; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.market.api.price.PriceApi; | ||
| 4 | import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; | 3 | import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; |
| 5 | import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; | 4 | import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; |
| 5 | +import cn.iocoder.yudao.module.market.service.price.PriceService; | ||
| 6 | import org.springframework.stereotype.Service; | 6 | import org.springframework.stereotype.Service; |
| 7 | 7 | ||
| 8 | +import javax.annotation.Resource; | ||
| 9 | + | ||
| 8 | /** | 10 | /** |
| 9 | * 价格 API 实现类 | 11 | * 价格 API 实现类 |
| 10 | * | 12 | * |
| 11 | - * TODO 完善注释 | ||
| 12 | - * | ||
| 13 | - * @author TODO | 13 | + * @author 芋道源码 |
| 14 | */ | 14 | */ |
| 15 | @Service | 15 | @Service |
| 16 | public class PriceApiImpl implements PriceApi { | 16 | public class PriceApiImpl implements PriceApi { |
| 17 | 17 | ||
| 18 | + @Resource | ||
| 19 | + private PriceService priceService; | ||
| 20 | + | ||
| 18 | @Override | 21 | @Override |
| 19 | public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) { | 22 | public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) { |
| 20 | - // TODO fixme:实现逻辑 | ||
| 21 | - return new PriceCalculateRespDTO(); | 23 | + return priceService.calculatePrice(calculateReqDTO); |
| 22 | } | 24 | } |
| 23 | 25 | ||
| 24 | } | 26 | } |
yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/convert/price/PriceConvert.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.market.convert.price; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 4 | +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; | ||
| 5 | +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; | ||
| 6 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 7 | +import org.mapstruct.Mapper; | ||
| 8 | +import org.mapstruct.factory.Mappers; | ||
| 9 | + | ||
| 10 | +import java.util.ArrayList; | ||
| 11 | +import java.util.List; | ||
| 12 | +import java.util.Map; | ||
| 13 | + | ||
| 14 | +@Mapper | ||
| 15 | +public interface PriceConvert { | ||
| 16 | + | ||
| 17 | + PriceConvert INSTANCE = Mappers.getMapper(PriceConvert.class); | ||
| 18 | + | ||
| 19 | + default PriceCalculateRespDTO convert(PriceCalculateReqDTO calculateReqDTO, List<ProductSkuRespDTO> skuList) { | ||
| 20 | + // 创建 PriceCalculateRespDTO 对象 | ||
| 21 | + PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO(); | ||
| 22 | + priceCalculate.setOrder(new PriceCalculateRespDTO.Order().setSkuOriginalPrice(0).setSkuPromotionPrice(0) | ||
| 23 | + .setOrderPromotionPrice(0).setDeliveryPrice(0).setPayPrice(0).setItems(new ArrayList<>()) | ||
| 24 | + .setCouponId(calculateReqDTO.getCouponId())); | ||
| 25 | + priceCalculate.setPromotions(new ArrayList<>()); | ||
| 26 | + // 创建它的 OrderItem 属性 | ||
| 27 | + Map<Long, Integer> skuIdCountMap = CollectionUtils.convertMap(calculateReqDTO.getItems(), | ||
| 28 | + PriceCalculateReqDTO.Item::getSkuId, PriceCalculateReqDTO.Item::getCount); | ||
| 29 | + skuList.forEach(sku -> { | ||
| 30 | + Integer count = skuIdCountMap.get(sku.getId()); | ||
| 31 | + PriceCalculateRespDTO.OrderItem orderItem = new PriceCalculateRespDTO.OrderItem().setCount(count) | ||
| 32 | + .setOriginalPrice(sku.getPrice()).setTotalOriginalPrice(sku.getPrice() * count).setTotalPromotionPrice(0); | ||
| 33 | + orderItem.setTotalPresentPrice(orderItem.getTotalPresentPrice()).setPresentPrice(orderItem.getOriginalPrice()) | ||
| 34 | + .setTotalPayPrice(orderItem.getTotalPayPrice()); | ||
| 35 | + priceCalculate.getOrder().getItems().add(orderItem); | ||
| 36 | + }); | ||
| 37 | + return priceCalculate; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | +} |
yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.market.service.price; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; | ||
| 4 | +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 价格计算 Service 接口 | ||
| 8 | + * | ||
| 9 | + * @author 芋道源码 | ||
| 10 | + */ | ||
| 11 | +public interface PriceService { | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * 计算商品的价格 | ||
| 15 | + * | ||
| 16 | + * @param calculateReqDTO 价格请求 | ||
| 17 | + * @return 价格相应 | ||
| 18 | + */ | ||
| 19 | + PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO); | ||
| 20 | + | ||
| 21 | +} |
yudao-module-mall/yudao-module-market-biz/src/main/java/cn/iocoder/yudao/module/market/service/price/PriceServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.market.service.price; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 4 | +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; | ||
| 5 | +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; | ||
| 6 | +import cn.iocoder.yudao.module.market.convert.price.PriceConvert; | ||
| 7 | +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | ||
| 8 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 9 | +import org.springframework.stereotype.Service; | ||
| 10 | +import org.springframework.validation.annotation.Validated; | ||
| 11 | + | ||
| 12 | +import javax.annotation.Resource; | ||
| 13 | +import java.util.List; | ||
| 14 | +import java.util.Map; | ||
| 15 | + | ||
| 16 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 17 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; | ||
| 18 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * 价格计算 Service 实现类 | ||
| 22 | + * | ||
| 23 | + * @author 芋道源码 | ||
| 24 | + */ | ||
| 25 | +@Service | ||
| 26 | +@Validated | ||
| 27 | +public class PriceServiceImpl implements PriceService { | ||
| 28 | + | ||
| 29 | + @Resource | ||
| 30 | + private ProductSkuApi productSkuApi; | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) { | ||
| 34 | + // 获得商品 SKU 数组 | ||
| 35 | + List<ProductSkuRespDTO> skuList = checkProductSkus(calculateReqDTO); | ||
| 36 | + // 初始化 PriceCalculateRespDTO 对象 | ||
| 37 | + PriceCalculateRespDTO priceCalculate = PriceConvert.INSTANCE.convert(calculateReqDTO, skuList); | ||
| 38 | + | ||
| 39 | + // 计算【限时折扣】促销 TODO 待实现 | ||
| 40 | + // 计算【满减送】促销 TODO 待实现 | ||
| 41 | + // 计算【优惠劵】促销 TODO 待实现 | ||
| 42 | + return priceCalculate; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + private List<ProductSkuRespDTO> checkProductSkus(PriceCalculateReqDTO calculateReqDTO) { | ||
| 46 | + // 获得商品 SKU 数组 | ||
| 47 | + Map<Long, Integer> skuIdCountMap = CollectionUtils.convertMap(calculateReqDTO.getItems(), | ||
| 48 | + PriceCalculateReqDTO.Item::getSkuId, PriceCalculateReqDTO.Item::getCount); | ||
| 49 | + List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(skuIdCountMap.keySet()); | ||
| 50 | + | ||
| 51 | + // 校验商品 SKU | ||
| 52 | + skus.forEach(sku -> { | ||
| 53 | + Integer count = skuIdCountMap.get(sku.getId()); | ||
| 54 | + if (count == null) { | ||
| 55 | + throw exception(SKU_NOT_EXISTS); | ||
| 56 | + } | ||
| 57 | + if (count > sku.getStock()) { | ||
| 58 | + throw exception(SKU_STOCK_NOT_ENOUGH); | ||
| 59 | + } | ||
| 60 | + }); | ||
| 61 | + return skus; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | +} |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApi.java
| 1 | package cn.iocoder.yudao.module.product.api.sku; | 1 | package cn.iocoder.yudao.module.product.api.sku; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; | 3 | import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; |
| 4 | -import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO; | 4 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 5 | 5 | ||
| 6 | import java.util.Collection; | 6 | import java.util.Collection; |
| 7 | import java.util.List; | 7 | import java.util.List; |
| 8 | 8 | ||
| 9 | /** | 9 | /** |
| 10 | + * 商品 SKU API 接口 | ||
| 11 | + * | ||
| 10 | * @author LeeYan9 | 12 | * @author LeeYan9 |
| 11 | * @since 2022-08-26 | 13 | * @since 2022-08-26 |
| 12 | */ | 14 | */ |
| 13 | public interface ProductSkuApi { | 15 | public interface ProductSkuApi { |
| 14 | 16 | ||
| 17 | + /** | ||
| 18 | + * 查询 SKU 信息 | ||
| 19 | + * | ||
| 20 | + * @param id SKU 编号 | ||
| 21 | + * @return SKU 信息 | ||
| 22 | + */ | ||
| 23 | + ProductSkuRespDTO getSku(Long id); | ||
| 15 | 24 | ||
| 16 | /** | 25 | /** |
| 17 | - * 根据skuId列表 查询sku信息 | 26 | + * 批量查询 SKU 数组 |
| 18 | * | 27 | * |
| 19 | - * @param skuIds sku ID列表 | ||
| 20 | - * @return sku信息列表 | 28 | + * @param ids SKU 编号列表 |
| 29 | + * @return SKU 数组 | ||
| 21 | */ | 30 | */ |
| 22 | - List<SkuInfoRespDTO> getSkusByIds(Collection<Long> skuIds); | 31 | + List<ProductSkuRespDTO> getSkuList(Collection<Long> ids); |
| 23 | 32 | ||
| 24 | /** | 33 | /** |
| 25 | * 批量扣减sku库存 | 34 | * 批量扣减sku库存 |
| @@ -27,4 +36,5 @@ public interface ProductSkuApi { | @@ -27,4 +36,5 @@ public interface ProductSkuApi { | ||
| 27 | * @param batchReqDTO sku库存信息列表 | 36 | * @param batchReqDTO sku库存信息列表 |
| 28 | */ | 37 | */ |
| 29 | void decrementStockBatch(SkuDecrementStockBatchReqDTO batchReqDTO); | 38 | void decrementStockBatch(SkuDecrementStockBatchReqDTO batchReqDTO); |
| 39 | + | ||
| 30 | } | 40 | } |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/SkuInfoRespDTO.java renamed to yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
| @@ -6,11 +6,13 @@ import lombok.Data; | @@ -6,11 +6,13 @@ import lombok.Data; | ||
| 6 | import java.util.List; | 6 | import java.util.List; |
| 7 | 7 | ||
| 8 | /** | 8 | /** |
| 9 | + * 商品 SKU 信息 Response DTO | ||
| 10 | + * | ||
| 9 | * @author LeeYan9 | 11 | * @author LeeYan9 |
| 10 | * @since 2022-08-26 | 12 | * @since 2022-08-26 |
| 11 | */ | 13 | */ |
| 12 | @Data | 14 | @Data |
| 13 | -public class SkuInfoRespDTO { | 15 | +public class ProductSkuRespDTO { |
| 14 | 16 | ||
| 15 | /** | 17 | /** |
| 16 | * 商品 SKU 编号,自增 | 18 | * 商品 SKU 编号,自增 |
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.sku.dto.SkuInfoRespDTO; | ||
| 4 | import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; | 3 | import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; |
| 5 | 4 | ||
| 6 | import java.util.Collection; | 5 | import java.util.Collection; |
| 7 | import java.util.List; | 6 | import java.util.List; |
| 8 | 7 | ||
| 9 | /** | 8 | /** |
| 9 | + * 商品 SPU API 接口 | ||
| 10 | + * | ||
| 10 | * @author LeeYan9 | 11 | * @author LeeYan9 |
| 11 | * @since 2022-08-26 | 12 | * @since 2022-08-26 |
| 12 | */ | 13 | */ |
| 13 | public interface ProductSpuApi { | 14 | public interface ProductSpuApi { |
| 14 | 15 | ||
| 15 | - | ||
| 16 | /** | 16 | /** |
| 17 | - * 根据spuId列表 查询spu信息 | 17 | + * 批量查询 SPU 数组 |
| 18 | * | 18 | * |
| 19 | - * @param spuIds spu ID列表 | ||
| 20 | - * @return spu信息列表 | 19 | + * @param ids SPU 编号列表 |
| 20 | + * @return SPU 数组 | ||
| 21 | */ | 21 | */ |
| 22 | - List<SpuInfoRespDTO> getSpusByIds(Collection<Long> spuIds); | 22 | + List<SpuInfoRespDTO> getSpuList(Collection<Long> ids); |
| 23 | + | ||
| 23 | } | 24 | } |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/spu/dto/SpuInfoRespDTO.java
| 1 | package cn.iocoder.yudao.module.product.api.spu.dto; | 1 | package cn.iocoder.yudao.module.product.api.spu.dto; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO; | 3 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 4 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum; | 4 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum; |
| 5 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | 5 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; |
| 6 | import lombok.Data; | 6 | import lombok.Data; |
| @@ -80,25 +80,25 @@ public class SpuInfoRespDTO { | @@ -80,25 +80,25 @@ public class SpuInfoRespDTO { | ||
| 80 | /** | 80 | /** |
| 81 | * 最小价格,单位使用:分 | 81 | * 最小价格,单位使用:分 |
| 82 | * <p> | 82 | * <p> |
| 83 | - * 基于其对应的 {@link SkuInfoRespDTO#getPrice()} 最小值 | 83 | + * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最小值 |
| 84 | */ | 84 | */ |
| 85 | private Integer minPrice; | 85 | private Integer minPrice; |
| 86 | /** | 86 | /** |
| 87 | * 最大价格,单位使用:分 | 87 | * 最大价格,单位使用:分 |
| 88 | * <p> | 88 | * <p> |
| 89 | - * 基于其对应的 {@link SkuInfoRespDTO#getPrice()} 最大值 | 89 | + * 基于其对应的 {@link ProductSkuRespDTO#getPrice()} 最大值 |
| 90 | */ | 90 | */ |
| 91 | private Integer maxPrice; | 91 | private Integer maxPrice; |
| 92 | /** | 92 | /** |
| 93 | * 市场价,单位使用:分 | 93 | * 市场价,单位使用:分 |
| 94 | * <p> | 94 | * <p> |
| 95 | - * 基于其对应的 {@link SkuInfoRespDTO#getMarketPrice()} 最大值 | 95 | + * 基于其对应的 {@link ProductSkuRespDTO#getMarketPrice()} 最大值 |
| 96 | */ | 96 | */ |
| 97 | private Integer marketPrice; | 97 | private Integer marketPrice; |
| 98 | /** | 98 | /** |
| 99 | * 总库存 | 99 | * 总库存 |
| 100 | * <p> | 100 | * <p> |
| 101 | - * 基于其对应的 {@link SkuInfoRespDTO#getStock()} 求和 | 101 | + * 基于其对应的 {@link ProductSkuRespDTO#getStock()} 求和 |
| 102 | */ | 102 | */ |
| 103 | private Integer totalStock; | 103 | private Integer totalStock; |
| 104 | /** | 104 | /** |
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/enums/ErrorCodeConstants.java
| @@ -36,5 +36,6 @@ public interface ErrorCodeConstants { | @@ -36,5 +36,6 @@ public interface ErrorCodeConstants { | ||
| 36 | ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品 SKU 的属性组合存在重复"); | 36 | ErrorCode SKU_PROPERTIES_DUPLICATED = new ErrorCode(1008006001, "商品 SKU 的属性组合存在重复"); |
| 37 | ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 SPU 下的每个 SKU,其规格数必须一致"); | 37 | ErrorCode SPU_ATTR_NUMBERS_MUST_BE_EQUALS = new ErrorCode(1008006002, "一个 SPU 下的每个 SKU,其规格数必须一致"); |
| 38 | ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU,必须不重复"); | 38 | ErrorCode SPU_SKU_NOT_DUPLICATE = new ErrorCode(1008006003, "一个 SPU 下的每个 SKU,必须不重复"); |
| 39 | + ErrorCode SKU_STOCK_NOT_ENOUGH = new ErrorCode(1008006004, "商品 SKU 库存不足"); | ||
| 39 | 40 | ||
| 40 | } | 41 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/sku/ProductSkuApiImpl.java
| 1 | package cn.iocoder.yudao.module.product.api.sku; | 1 | package cn.iocoder.yudao.module.product.api.sku; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; | 3 | import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; |
| 4 | -import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO; | 4 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 5 | +import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert; | ||
| 6 | +import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | ||
| 7 | +import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; | ||
| 5 | import org.springframework.stereotype.Service; | 8 | import org.springframework.stereotype.Service; |
| 6 | 9 | ||
| 10 | +import javax.annotation.Resource; | ||
| 7 | import java.util.Collection; | 11 | import java.util.Collection; |
| 8 | import java.util.List; | 12 | import java.util.List; |
| 9 | 13 | ||
| 10 | /** | 14 | /** |
| 11 | - * todo 注释 | 15 | + * 商品 SKU API 实现类 |
| 16 | + * | ||
| 17 | + * @author 芋道源码 | ||
| 18 | + * @since 2022-08-26 | ||
| 12 | */ | 19 | */ |
| 13 | @Service | 20 | @Service |
| 14 | public class ProductSkuApiImpl implements ProductSkuApi { | 21 | public class ProductSkuApiImpl implements ProductSkuApi { |
| 15 | 22 | ||
| 23 | + @Resource | ||
| 24 | + private ProductSkuService productSkuService; | ||
| 25 | + | ||
| 26 | + @Override | ||
| 27 | + public ProductSkuRespDTO getSku(Long id) { | ||
| 28 | + ProductSkuDO skuDO = productSkuService.getSku(id); | ||
| 29 | + return ProductSkuConvert.INSTANCE.convert02(skuDO); | ||
| 30 | + } | ||
| 31 | + | ||
| 16 | @Override | 32 | @Override |
| 17 | - public List<SkuInfoRespDTO> getSkusByIds(Collection<Long> skuIds) { | ||
| 18 | - return null; | 33 | + public List<ProductSkuRespDTO> getSkuList(Collection<Long> ids) { |
| 34 | + List<ProductSkuDO> list = productSkuService.getSkuList(ids); | ||
| 35 | + return ProductSkuConvert.INSTANCE.convertList02(list); | ||
| 19 | } | 36 | } |
| 20 | 37 | ||
| 21 | @Override | 38 | @Override |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/api/spu/ProductSpuApiImpl.java
| @@ -7,13 +7,16 @@ import java.util.Collection; | @@ -7,13 +7,16 @@ import java.util.Collection; | ||
| 7 | import java.util.List; | 7 | import java.util.List; |
| 8 | 8 | ||
| 9 | /** | 9 | /** |
| 10 | - * todo 注释 | 10 | + * 商品 SPU API 实现类 |
| 11 | + * | ||
| 12 | + * @author LeeYan9 | ||
| 13 | + * @since 2022-08-26 | ||
| 11 | */ | 14 | */ |
| 12 | @Service | 15 | @Service |
| 13 | public class ProductSpuApiImpl implements ProductSpuApi { | 16 | public class ProductSpuApiImpl implements ProductSpuApi { |
| 14 | 17 | ||
| 15 | @Override | 18 | @Override |
| 16 | - public List<SpuInfoRespDTO> getSpusByIds(Collection<Long> spuIds) { | 19 | + public List<SpuInfoRespDTO> getSpuList(Collection<Long> spuIds) { |
| 17 | return null; | 20 | return null; |
| 18 | } | 21 | } |
| 19 | 22 |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
| @@ -33,7 +33,7 @@ public class ProductSkuBaseVO { | @@ -33,7 +33,7 @@ public class ProductSkuBaseVO { | ||
| 33 | @ApiModelProperty(value = "条形码", example = "haha") | 33 | @ApiModelProperty(value = "条形码", example = "haha") |
| 34 | private String barCode; | 34 | private String barCode; |
| 35 | 35 | ||
| 36 | - @ApiModelProperty(value = "图片地址") | 36 | + @ApiModelProperty(value = "图片地址", required = true, example = "https://www.iocoder.cn/xx.png") |
| 37 | @NotNull(message = "图片地址不能为空") | 37 | @NotNull(message = "图片地址不能为空") |
| 38 | private String picUrl; | 38 | private String picUrl; |
| 39 | 39 |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/sku/ProductSkuConvert.java
| 1 | package cn.iocoder.yudao.module.product.convert.sku; | 1 | package cn.iocoder.yudao.module.product.convert.sku; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 3 | import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; | 4 | import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO; |
| 4 | import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; | 5 | import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuRespVO; |
| 5 | import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; | 6 | import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; |
| 6 | import org.mapstruct.Mapper; | 7 | import org.mapstruct.Mapper; |
| 7 | -import org.mapstruct.Mapping; | ||
| 8 | import org.mapstruct.factory.Mappers; | 8 | import org.mapstruct.factory.Mappers; |
| 9 | 9 | ||
| 10 | import java.util.List; | 10 | import java.util.List; |
| @@ -21,11 +21,14 @@ public interface ProductSkuConvert { | @@ -21,11 +21,14 @@ public interface ProductSkuConvert { | ||
| 21 | 21 | ||
| 22 | ProductSkuDO convert(ProductSkuCreateOrUpdateReqVO bean); | 22 | ProductSkuDO convert(ProductSkuCreateOrUpdateReqVO bean); |
| 23 | 23 | ||
| 24 | - @Mapping(source = "properties", target = "properties") | ||
| 25 | ProductSkuRespVO convert(ProductSkuDO bean); | 24 | ProductSkuRespVO convert(ProductSkuDO bean); |
| 26 | 25 | ||
| 27 | List<ProductSkuRespVO> convertList(List<ProductSkuDO> list); | 26 | List<ProductSkuRespVO> convertList(List<ProductSkuDO> list); |
| 28 | 27 | ||
| 29 | List<ProductSkuDO> convertSkuDOList(List<ProductSkuCreateOrUpdateReqVO> list); | 28 | List<ProductSkuDO> convertSkuDOList(List<ProductSkuCreateOrUpdateReqVO> list); |
| 30 | 29 | ||
| 30 | + ProductSkuRespDTO convert02(ProductSkuDO bean); | ||
| 31 | + | ||
| 32 | + List<ProductSkuRespDTO> convertList02(List<ProductSkuDO> list); | ||
| 33 | + | ||
| 31 | } | 34 | } |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/enums/ErrorCodeConstants.java renamed to yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/ErrorCodeConstants.java
| 1 | -package cn.iocoder.yudao.module.trade.enums.enums; | 1 | +package cn.iocoder.yudao.module.trade.enums; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.exception.ErrorCode; | 3 | import cn.iocoder.yudao.framework.common.exception.ErrorCode; |
| 4 | 4 | ||
| 5 | /** | 5 | /** |
| 6 | - * Trade-Order 错误码 Core 枚举类 | ||
| 7 | - * <p> | ||
| 8 | - * Trade-Order 系统,使用 1-011-000-000 段 | 6 | + * 交易 错误码枚举类 |
| 7 | + * 交易系统,使用 1-011-000-000 段 | ||
| 9 | * | 8 | * |
| 10 | * @author LeeYan9 | 9 | * @author LeeYan9 |
| 11 | * @since 2022-08-26 | 10 | * @since 2022-08-26 |
| 12 | */ | 11 | */ |
| 13 | public interface ErrorCodeConstants { | 12 | public interface ErrorCodeConstants { |
| 14 | 13 | ||
| 15 | - /** | ||
| 16 | - * ========== Order 模块 1-011-000-000 ========== | ||
| 17 | - */ | 14 | + // ========== Order 模块 1-011-000-000 ========== |
| 18 | ErrorCode ORDER_SKU_NOT_FOUND = new ErrorCode(1011000001, "商品不存在"); | 15 | ErrorCode ORDER_SKU_NOT_FOUND = new ErrorCode(1011000001, "商品不存在"); |
| 19 | ErrorCode ORDER_SPU_NOT_SALE = new ErrorCode(1011000002, "商品不可售卖"); | 16 | ErrorCode ORDER_SPU_NOT_SALE = new ErrorCode(1011000002, "商品不可售卖"); |
| 20 | ErrorCode ORDER_SKU_NOT_SALE = new ErrorCode(1011000003, "商品Sku不可售卖"); | 17 | ErrorCode ORDER_SKU_NOT_SALE = new ErrorCode(1011000003, "商品Sku不可售卖"); |
| 21 | ErrorCode ORDER_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1011000004, "商品库存不足"); | 18 | ErrorCode ORDER_SKU_STOCK_NOT_ENOUGH = new ErrorCode(1011000004, "商品库存不足"); |
| 22 | 19 | ||
| 20 | + // ========== Cart 模块 1-011-001-000 ========== | ||
| 21 | + ErrorCode CARD_ITEM_NOT_FOUND = new ErrorCode(1001001000, "购物车项不存在"); | ||
| 22 | + | ||
| 23 | } | 23 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/package-info.java
0 → 100644
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/property/AppProductPropertyValueDetailRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.base.property; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +@ApiModel("用户 App - 规格 + 规格值 Response VO") | ||
| 8 | +@Data | ||
| 9 | +public class AppProductPropertyValueDetailRespVO { | ||
| 10 | + | ||
| 11 | + @ApiModelProperty(value = "属性的编号", required = true, example = "1") | ||
| 12 | + private Long propertyId; | ||
| 13 | + | ||
| 14 | + @ApiModelProperty(value = "属性的名称", required = true, example = "颜色") | ||
| 15 | + private String propertyName; | ||
| 16 | + | ||
| 17 | + @ApiModelProperty(value = "属性值的编号", required = true, example = "1024") | ||
| 18 | + private Long valueId; | ||
| 19 | + | ||
| 20 | + @ApiModelProperty(value = "属性值的名称", required = true, example = "红色") | ||
| 21 | + private String valueName; | ||
| 22 | + | ||
| 23 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/sku/AppProductSkuBaseRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.base.sku; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import java.util.List; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 商品 SKU 基础 Response VO | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +@Data | ||
| 15 | +public class AppProductSkuBaseRespVO { | ||
| 16 | + | ||
| 17 | + @ApiModelProperty(value = "主键", required = true, example = "1024") | ||
| 18 | + private Long id; | ||
| 19 | + | ||
| 20 | + @ApiModelProperty(value = "商品 SKU 名字", required = true, example = "芋道") | ||
| 21 | + private String name; | ||
| 22 | + | ||
| 23 | + @ApiModelProperty(value = "图片地址", example = "https://www.iocoder.cn/xx.png") | ||
| 24 | + private String picUrl; | ||
| 25 | + | ||
| 26 | + @ApiModelProperty(value = "库存", required = true, example = "1") | ||
| 27 | + private Integer stock; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * 规格数组 | ||
| 31 | + */ | ||
| 32 | + private List<AppProductPropertyValueDetailRespVO> properties; | ||
| 33 | + | ||
| 34 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/base/spu/AppProductSpuBaseRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.base.spu; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModelProperty; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +import java.util.List; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 商品 SPU 基础 Response VO | ||
| 10 | + * | ||
| 11 | + * @author 芋道源码 | ||
| 12 | + */ | ||
| 13 | +@Data | ||
| 14 | +public class AppProductSpuBaseRespVO { | ||
| 15 | + | ||
| 16 | + @ApiModelProperty(value = "主键", required = true, example = "1024") | ||
| 17 | + private Long id; | ||
| 18 | + | ||
| 19 | + @ApiModelProperty(value = "商品 SPU 名字", required = true, example = "芋道") | ||
| 20 | + private String name; | ||
| 21 | + | ||
| 22 | + @ApiModelProperty(value = "商品主图地址", example = "https://www.iocoder.cn/xx.png") | ||
| 23 | + private List<String> picUrls; | ||
| 24 | + | ||
| 25 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/CartController.java deleted
| 1 | -package cn.iocoder.yudao.module.trade.controller.app.cart; | ||
| 2 | - | ||
| 3 | -import io.swagger.annotations.Api; | ||
| 4 | -import org.springframework.validation.annotation.Validated; | ||
| 5 | -import org.springframework.web.bind.annotation.RequestMapping; | ||
| 6 | -import org.springframework.web.bind.annotation.RestController; | ||
| 7 | - | ||
| 8 | -@Api(tags = "购物车 API") | ||
| 9 | -@RestController | ||
| 10 | -@RequestMapping("/cart") | ||
| 11 | -@Validated | ||
| 12 | -public class CartController { | ||
| 13 | - | ||
| 14 | -// @Autowired | ||
| 15 | -// private CartManager cartManager; | ||
| 16 | -// | ||
| 17 | -// @PostMapping("add") | ||
| 18 | -// @ApiOperation("添加商品到购物车") | ||
| 19 | -// @ApiImplicitParams({ | ||
| 20 | -// @ApiImplicitParam(name = "skuId", value = "商品 SKU 编号", required = true, example = "1"), | ||
| 21 | -// @ApiImplicitParam(name = "quantity", value = "增加数量", required = true, example = "1024") | ||
| 22 | -// }) | ||
| 23 | -// @RequiresAuthenticate | ||
| 24 | -// public CommonResult<Boolean> addCartItem(@RequestParam("skuId") Integer skuId, | ||
| 25 | -// @RequestParam("quantity") Integer quantity) { | ||
| 26 | -// cartManager.addCartItem(UserSecurityContextHolder.getUserId(), skuId, quantity); | ||
| 27 | -// return success(true); | ||
| 28 | -// } | ||
| 29 | -// | ||
| 30 | -// @GetMapping("sum-quantity") | ||
| 31 | -// @ApiOperation("查询用户在购物车中的商品数量") | ||
| 32 | -// @RequiresAuthenticate | ||
| 33 | -// public CommonResult<Integer> sumCartItemQuantity() { | ||
| 34 | -// return success(cartManager.sumCartItemQuantity(UserSecurityContextHolder.getUserId())); | ||
| 35 | -// } | ||
| 36 | -// | ||
| 37 | -// @GetMapping("/get-detail") | ||
| 38 | -// @ApiOperation("查询用户的购物车的商品列表") | ||
| 39 | -// @RequiresAuthenticate | ||
| 40 | -// public CommonResult<CartDetailVO> getCartDetail() { | ||
| 41 | -// return success(cartManager.getCartDetail(UserSecurityContextHolder.getUserId())); | ||
| 42 | -// } | ||
| 43 | -// | ||
| 44 | -// @PostMapping("update-quantity") | ||
| 45 | -// @ApiOperation("更新购物车商品数量") | ||
| 46 | -// @ApiImplicitParams({ | ||
| 47 | -// @ApiImplicitParam(name = "skuId", value = "商品 SKU 编号", required = true, example = "1"), | ||
| 48 | -// @ApiImplicitParam(name = "quantity", value = "增加数量", required = true, example = "1024") | ||
| 49 | -// }) | ||
| 50 | -// @RequiresAuthenticate | ||
| 51 | -// public CommonResult<Boolean> updateCartItemQuantity(@RequestParam("skuId") Integer skuId, | ||
| 52 | -// @RequestParam("quantity") Integer quantity) { | ||
| 53 | -// cartManager.updateCartItemQuantity(UserSecurityContextHolder.getUserId(), skuId, quantity); | ||
| 54 | -// return success(true); | ||
| 55 | -// } | ||
| 56 | -// | ||
| 57 | -// @PostMapping("update-selected") | ||
| 58 | -// @ApiOperation("更新购物车商品是否选中") | ||
| 59 | -// @ApiImplicitParams({ | ||
| 60 | -// @ApiImplicitParam(name = "skuIds", value = "商品 SKU 编号数组", required = true, example = "1,3"), | ||
| 61 | -// @ApiImplicitParam(name = "selected", value = "是否选中", required = true, example = "true") | ||
| 62 | -// }) | ||
| 63 | -// @RequiresAuthenticate | ||
| 64 | -// public CommonResult<Boolean> updateCartItemSelected(@RequestParam("skuIds") Set<Integer> skuIds, | ||
| 65 | -// @RequestParam("selected") Boolean selected) { | ||
| 66 | -// cartManager.updateCartItemSelected(UserSecurityContextHolder.getUserId(), skuIds, selected); | ||
| 67 | -// // 获得目前购物车明细 | ||
| 68 | -// return success(true); | ||
| 69 | -// } | ||
| 70 | - | ||
| 71 | -} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.http
0 → 100644
| 1 | +### 请求 /trade/cart/add-count 接口 => 成功 | ||
| 2 | +POST {{appApi}}/trade/cart/add-count | ||
| 3 | +tenant-id: {{appTenentId}} | ||
| 4 | +Authorization: Bearer {{appToken}} | ||
| 5 | +Content-Type: application/json | ||
| 6 | + | ||
| 7 | +{ | ||
| 8 | + "skuId": 1, | ||
| 9 | + "count": 1 | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +### 请求 /trade/cart/update-count 接口 => 成功 | ||
| 13 | +PUT {{appApi}}/trade/cart/update-count | ||
| 14 | +tenant-id: {{appTenentId}} | ||
| 15 | +Authorization: Bearer {{appToken}} | ||
| 16 | +Content-Type: application/json | ||
| 17 | + | ||
| 18 | +{ | ||
| 19 | + "skuId": 1, | ||
| 20 | + "count": 5 | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +### 请求 /trade/cart/update-selected 接口 => 成功 | ||
| 24 | +PUT {{appApi}}/trade/cart/update-selected | ||
| 25 | +tenant-id: {{appTenentId}} | ||
| 26 | +Authorization: Bearer {{appToken}} | ||
| 27 | +Content-Type: application/json | ||
| 28 | + | ||
| 29 | +{ | ||
| 30 | + "skuIds": [1], | ||
| 31 | + "selected": false | ||
| 32 | +} | ||
| 33 | + | ||
| 34 | +### 请求 /trade/cart/delete 接口 => 成功 | ||
| 35 | +DELETE {{appApi}}/trade/cart/delete?skuIds=1 | ||
| 36 | +tenant-id: {{appTenentId}} | ||
| 37 | +Authorization: Bearer {{appToken}} | ||
| 38 | + | ||
| 39 | +### 请求 /trade/cart/get-count 接口 => 成功 | ||
| 40 | +GET {{appApi}}/trade/cart/get-count | ||
| 41 | +tenant-id: {{appTenentId}} | ||
| 42 | +Authorization: Bearer {{appToken}} | ||
| 43 | + | ||
| 44 | +### 请求 /trade/cart/get-detail 接口 => 成功 | ||
| 45 | +GET {{appApi}}/trade/cart/get-detail | ||
| 46 | +tenant-id: {{appTenentId}} | ||
| 47 | +Authorization: Bearer {{appToken}} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/TradeCartController.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.cart; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 4 | +import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | ||
| 5 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; | ||
| 6 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; | ||
| 9 | +import cn.iocoder.yudao.module.trade.service.cart.TradeCartService; | ||
| 10 | +import io.swagger.annotations.Api; | ||
| 11 | +import io.swagger.annotations.ApiImplicitParam; | ||
| 12 | +import io.swagger.annotations.ApiOperation; | ||
| 13 | +import lombok.RequiredArgsConstructor; | ||
| 14 | +import lombok.extern.slf4j.Slf4j; | ||
| 15 | +import org.springframework.validation.annotation.Validated; | ||
| 16 | +import org.springframework.web.bind.annotation.*; | ||
| 17 | + | ||
| 18 | +import javax.annotation.Resource; | ||
| 19 | +import javax.validation.Valid; | ||
| 20 | +import java.util.List; | ||
| 21 | + | ||
| 22 | +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||
| 23 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | ||
| 24 | + | ||
| 25 | +@Api(tags = "用户 App - 购物车") | ||
| 26 | +@RestController | ||
| 27 | +@RequestMapping("/trade/cart") | ||
| 28 | +@RequiredArgsConstructor | ||
| 29 | +@Validated | ||
| 30 | +@Slf4j | ||
| 31 | +public class TradeCartController { | ||
| 32 | + | ||
| 33 | + @Resource | ||
| 34 | + private TradeCartService cartService; | ||
| 35 | + | ||
| 36 | + @PostMapping("/add-count") | ||
| 37 | + @ApiOperation("添加商品到购物车") | ||
| 38 | + @PreAuthenticated | ||
| 39 | + public CommonResult<Boolean> addCartItemCount(@Valid @RequestBody AppTradeCartItemAddCountReqVO addCountReqVO) { | ||
| 40 | + cartService.addCartItemCount(getLoginUserId(), addCountReqVO); | ||
| 41 | + return success(true); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + @PutMapping("update-count") | ||
| 45 | + @ApiOperation("更新购物车商品数量") | ||
| 46 | + @PreAuthenticated | ||
| 47 | + public CommonResult<Boolean> updateCartItemQuantity(@Valid @RequestBody AppTradeCartItemUpdateCountReqVO updateCountReqVO) { | ||
| 48 | + cartService.updateCartItemCount(getLoginUserId(), updateCountReqVO); | ||
| 49 | + return success(true); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + @PutMapping("update-selected") | ||
| 53 | + @ApiOperation("更新购物车商品是否选中") | ||
| 54 | + @PreAuthenticated | ||
| 55 | + public CommonResult<Boolean> updateCartItemSelected(@Valid @RequestBody AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO) { | ||
| 56 | + cartService.updateCartItemSelected(getLoginUserId(), updateSelectedReqVO); | ||
| 57 | + // 获得目前购物车明细 | ||
| 58 | + return success(true); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + @DeleteMapping("/delete") | ||
| 62 | + @ApiOperation("删除购物车商品") | ||
| 63 | + @ApiImplicitParam(name = "skuId", value = "商品 SKU 编号的数组", required = true, example = "1024,2048", dataTypeClass = List.class) | ||
| 64 | + @PreAuthenticated | ||
| 65 | + public CommonResult<Boolean> deleteCartItem(@RequestParam("skuIds") List<Long> skuIds) { | ||
| 66 | + cartService.deleteCartItems(getLoginUserId(), skuIds); | ||
| 67 | + return success(true); | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + @GetMapping("get-count") | ||
| 71 | + @ApiOperation("查询用户在购物车中的商品数量") | ||
| 72 | + @PreAuthenticated | ||
| 73 | + public CommonResult<Integer> getCartCount() { | ||
| 74 | + return success(cartService.getCartCount(getLoginUserId())); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + @GetMapping("/get-detail") | ||
| 78 | + @ApiOperation("查询用户的购物车的详情") | ||
| 79 | + @PreAuthenticated | ||
| 80 | + public CommonResult<AppTradeCartDetailRespVO> getCartDetail() { | ||
| 81 | + return success(cartService.getCartDetail(getLoginUserId())); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartDetailRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.trade.controller.app.base.sku.AppProductSkuBaseRespVO; | ||
| 4 | +import io.swagger.annotations.ApiModel; | ||
| 5 | +import io.swagger.annotations.ApiModelProperty; | ||
| 6 | +import lombok.Data; | ||
| 7 | + | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +@ApiModel(value = "用户 App - 用户的购物车明细 Response VO") | ||
| 11 | +@Data | ||
| 12 | +public class AppTradeCartDetailRespVO { | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * 商品分组数组 | ||
| 16 | + */ | ||
| 17 | + private List<ItemGroup> itemGroups; | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 费用 | ||
| 21 | + */ | ||
| 22 | + private Order order; | ||
| 23 | + | ||
| 24 | + @ApiModel(value = "商品分组", description = "多个商品,参加同一个活动,从而形成分组") | ||
| 25 | + @Data | ||
| 26 | + public static class ItemGroup { | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * 商品数组 | ||
| 30 | + */ | ||
| 31 | + private List<Sku> items; | ||
| 32 | + /** | ||
| 33 | + * 营销活动,订单级别 | ||
| 34 | + */ | ||
| 35 | + private Promotion promotion; | ||
| 36 | + | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + @ApiModel(value = "商品 SKU") | ||
| 40 | + @Data | ||
| 41 | + public static class Sku extends AppProductSkuBaseRespVO { | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * SPU 信息 | ||
| 45 | + */ | ||
| 46 | + private AppProductSkuBaseRespVO spu; | ||
| 47 | + | ||
| 48 | + // ========== 购物车相关的字段 ========== | ||
| 49 | + | ||
| 50 | + @ApiModelProperty(value = "商品数量", required = true, example = "1") | ||
| 51 | + private Integer count; | ||
| 52 | + @ApiModelProperty(value = "是否选中", required = true, example = "true") | ||
| 53 | + private Boolean selected; | ||
| 54 | + | ||
| 55 | + // ========== 价格相关的字段,对应 PriceCalculateRespDTO.OrderItem 的属性 ========== | ||
| 56 | + | ||
| 57 | + // TODO 芋艿:后续可以去除一些无用的字段 | ||
| 58 | + | ||
| 59 | + @ApiModelProperty(value = "商品原价(单)", required = true, example = "100") | ||
| 60 | + private Integer originalPrice; | ||
| 61 | + @ApiModelProperty(value = "商品原价(总)", required = true, example = "200") | ||
| 62 | + private Integer totalOriginalPrice; | ||
| 63 | + @ApiModelProperty(value = "商品级优惠(总)", required = true, example = "300") | ||
| 64 | + private Integer totalPromotionPrice; | ||
| 65 | + @ApiModelProperty(value = "最终购买金额(总)", required = true, example = "400") | ||
| 66 | + private Integer totalPresentPrice; | ||
| 67 | + @ApiModelProperty(value = "最终购买金额(单)", required = true, example = "500") | ||
| 68 | + private Integer presentPrice; | ||
| 69 | + @ApiModelProperty(value = "应付金额(总)", required = true, example = "600") | ||
| 70 | + private Integer totalPayPrice; | ||
| 71 | + | ||
| 72 | + // ========== 营销相关的字段 ========== | ||
| 73 | + /** | ||
| 74 | + * 营销活动,商品级别 | ||
| 75 | + */ | ||
| 76 | + private Promotion promotion; | ||
| 77 | + | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + @ApiModel(value = "订单", description = "对应 PriceCalculateRespDTO.Order 类,用于费用(合计)") | ||
| 81 | + @Data | ||
| 82 | + public static class Order { | ||
| 83 | + | ||
| 84 | + // TODO 芋艿:后续可以去除一些无用的字段 | ||
| 85 | + | ||
| 86 | + @ApiModelProperty(value = "商品原价(总)", required = true, example = "100") | ||
| 87 | + private Integer skuOriginalPrice; | ||
| 88 | + @ApiModelProperty(value = "商品优惠(总)", required = true, example = "200") | ||
| 89 | + private Integer skuPromotionPrice; | ||
| 90 | + @ApiModelProperty(value = "订单优惠(总)", required = true, example = "300") | ||
| 91 | + private Integer orderPromotionPrice; | ||
| 92 | + @ApiModelProperty(value = "运费金额", required = true, example = "400") | ||
| 93 | + private Integer deliveryPrice; | ||
| 94 | + @ApiModelProperty(value = "应付金额(总)", required = true, example = "500") | ||
| 95 | + private Integer payPrice; | ||
| 96 | + | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + @ApiModel(value = "营销活动", description = "对应 PriceCalculateRespDTO.Promotion 类的属性") | ||
| 100 | + @Data | ||
| 101 | + public static class Promotion { | ||
| 102 | + | ||
| 103 | + @ApiModelProperty(value = "营销编号", required = true, example = "1024", notes = "营销活动的编号、优惠劵的编号") | ||
| 104 | + private Long id; | ||
| 105 | + @ApiModelProperty(value = "营销名字", required = true, example = "xx 活动") | ||
| 106 | + private String name; | ||
| 107 | + @ApiModelProperty(value = "营销类型", required = true, example = "1", notes = "参见 PromotionTypeEnum 枚举类") | ||
| 108 | + private Integer type; | ||
| 109 | + | ||
| 110 | + // ========== 匹配情况 ========== | ||
| 111 | + @ApiModelProperty(value = "是否满足优惠条件", required = true, example = "true") | ||
| 112 | + private Boolean meet; | ||
| 113 | + @ApiModelProperty(value = "满足条件的提示", required = true, example = "圣诞价:省 150.00 元") | ||
| 114 | + private String meetTip; | ||
| 115 | + | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemAddCountReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import javax.validation.constraints.Min; | ||
| 8 | +import javax.validation.constraints.NotNull; | ||
| 9 | + | ||
| 10 | +@ApiModel(value = "用户 App - 购物车添加购物项 Request VO") | ||
| 11 | +@Data | ||
| 12 | +public class AppTradeCartItemAddCountReqVO { | ||
| 13 | + | ||
| 14 | + @ApiModelProperty(value = "商品 SKU 编号", required = true,example = "1024") | ||
| 15 | + @NotNull(message = "商品 SKU 编号不能为空") | ||
| 16 | + private Long skuId; | ||
| 17 | + | ||
| 18 | + @ApiModelProperty(value = "商品数量", required = true, example = "1", notes = "注意,这是新增数量") | ||
| 19 | + @NotNull(message = "数量不能为空") | ||
| 20 | + @Min(message = "数量必须大于 0", value = 1L) | ||
| 21 | + private Integer count; | ||
| 22 | + | ||
| 23 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateCountReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import javax.validation.constraints.Min; | ||
| 8 | +import javax.validation.constraints.NotNull; | ||
| 9 | + | ||
| 10 | +@ApiModel(value = "用户 App - 购物车更新数量 Request VO") | ||
| 11 | +@Data | ||
| 12 | +public class AppTradeCartItemUpdateCountReqVO { | ||
| 13 | + | ||
| 14 | + @ApiModelProperty(value = "商品 SKU 编号", required = true, example = "1024") | ||
| 15 | + @NotNull(message = "商品 SKU 编号不能为空") | ||
| 16 | + private Long skuId; | ||
| 17 | + | ||
| 18 | + @ApiModelProperty(value = "商品数量", required = true, example = "1") | ||
| 19 | + @NotNull(message = "数量不能为空") | ||
| 20 | + @Min(message = "数量必须大于 0", value = 1L) | ||
| 21 | + private Integer count; | ||
| 22 | + | ||
| 23 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/AppTradeCartItemUpdateSelectedReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.app.cart.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +import javax.validation.constraints.NotNull; | ||
| 8 | +import java.util.Collection; | ||
| 9 | + | ||
| 10 | +@ApiModel(value = "用户 App - 购物车更新是否选中 Request VO") | ||
| 11 | +@Data | ||
| 12 | +public class AppTradeCartItemUpdateSelectedReqVO { | ||
| 13 | + | ||
| 14 | + @ApiModelProperty(value = "商品 SKU 编号列表", required = true, example = "1024,2048") | ||
| 15 | + @NotNull(message = "商品 SKU 编号列表不能为空") | ||
| 16 | + private Collection<Long> skuIds; | ||
| 17 | + | ||
| 18 | + @ApiModelProperty(value = "是否选中", required = true, example = "true") | ||
| 19 | + @NotNull(message = "是否选中不能为空") | ||
| 20 | + private Boolean selected; | ||
| 21 | + | ||
| 22 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/cart/vo/CartDetailVO.java deleted
| 1 | -package cn.iocoder.yudao.module.trade.controller.app.cart.vo; | ||
| 2 | - | ||
| 3 | -import io.swagger.annotations.ApiModel; | ||
| 4 | -import lombok.Data; | ||
| 5 | -import lombok.experimental.Accessors; | ||
| 6 | - | ||
| 7 | -import java.util.List; | ||
| 8 | - | ||
| 9 | -@ApiModel(value = "用户的购物车明细 Response VO") // TODO 芋艿:swagger 文档完善 | ||
| 10 | -@Data | ||
| 11 | -@Accessors(chain = true) | ||
| 12 | -public class CartDetailVO { | ||
| 13 | - | ||
| 14 | - /** | ||
| 15 | - * 商品分组数组 | ||
| 16 | - */ | ||
| 17 | - private List<ItemGroup> itemGroups; | ||
| 18 | - /** | ||
| 19 | - * 费用 | ||
| 20 | - */ | ||
| 21 | - private Fee fee; | ||
| 22 | - | ||
| 23 | - /** | ||
| 24 | - * 商品分组 | ||
| 25 | - * | ||
| 26 | - * 多个商品,参加同一个活动,从而形成分组。 | ||
| 27 | - */ | ||
| 28 | - @Data | ||
| 29 | - @Accessors(chain = true) | ||
| 30 | - public static class ItemGroup { | ||
| 31 | - | ||
| 32 | -// /** | ||
| 33 | -// * 优惠活动 | ||
| 34 | -// */ | ||
| 35 | -// private PromotionActivityRespDTO activity; // TODO 芋艿,偷懒 | ||
| 36 | - /** | ||
| 37 | - * 促销减少的金额 | ||
| 38 | - * | ||
| 39 | - * 1. 若未参与促销活动,或不满足促销条件,返回 null | ||
| 40 | - * 2. 该金额,已经分摊到每个 Item 的 discountTotal ,需要注意。 | ||
| 41 | - */ | ||
| 42 | - private Integer activityDiscountTotal; | ||
| 43 | - /** | ||
| 44 | - * 商品数组 | ||
| 45 | - */ | ||
| 46 | - private List<Sku> items; | ||
| 47 | - | ||
| 48 | - } | ||
| 49 | - | ||
| 50 | - @Data | ||
| 51 | - @Accessors(chain = true) | ||
| 52 | - public static class Sku { | ||
| 53 | - | ||
| 54 | - // SKU 自带信息 | ||
| 55 | - /** | ||
| 56 | - * sku 编号 | ||
| 57 | - */ | ||
| 58 | - private Integer id; | ||
| 59 | - /** | ||
| 60 | - * SPU 信息 | ||
| 61 | - */ | ||
| 62 | - private Spu spu; | ||
| 63 | - /** | ||
| 64 | - * 图片地址 | ||
| 65 | - */ | ||
| 66 | - private String picURL; | ||
| 67 | -// /** | ||
| 68 | -// * 规格值数组 | ||
| 69 | -// */ | ||
| 70 | -// private List<ProductAttrKeyValueRespVO> attrs; // TODO 后面改下 | ||
| 71 | - /** | ||
| 72 | - * 价格,单位:分 | ||
| 73 | - */ | ||
| 74 | - private Integer price; | ||
| 75 | - /** | ||
| 76 | - * 库存数量 | ||
| 77 | - */ | ||
| 78 | - private Integer quantity; | ||
| 79 | - | ||
| 80 | - // 非 SKU 自带信息 | ||
| 81 | - | ||
| 82 | - /** | ||
| 83 | - * 购买数量 | ||
| 84 | - */ | ||
| 85 | - private Integer buyQuantity; | ||
| 86 | - /** | ||
| 87 | - * 是否选中 | ||
| 88 | - */ | ||
| 89 | - private Boolean selected; | ||
| 90 | -// /** | ||
| 91 | -// * 优惠活动 | ||
| 92 | -// */ | ||
| 93 | -// private PromotionActivityRespDTO activity; // TODO 芋艿,偷懒 | ||
| 94 | - /** | ||
| 95 | - * 原始单价,单位:分。 | ||
| 96 | - */ | ||
| 97 | - private Integer originPrice; | ||
| 98 | - /** | ||
| 99 | - * 购买单价,单位:分 | ||
| 100 | - */ | ||
| 101 | - private Integer buyPrice; | ||
| 102 | - /** | ||
| 103 | - * 最终价格,单位:分。 | ||
| 104 | - */ | ||
| 105 | - private Integer presentPrice; | ||
| 106 | - /** | ||
| 107 | - * 购买总金额,单位:分 | ||
| 108 | - * | ||
| 109 | - * 用途类似 {@link #presentTotal} | ||
| 110 | - */ | ||
| 111 | - private Integer buyTotal; | ||
| 112 | - /** | ||
| 113 | - * 优惠总金额,单位:分。 | ||
| 114 | - */ | ||
| 115 | - private Integer discountTotal; | ||
| 116 | - /** | ||
| 117 | - * 最终总金额,单位:分。 | ||
| 118 | - * | ||
| 119 | - * 注意,presentPrice * quantity 不一定等于 presentTotal 。 | ||
| 120 | - * 因为,存在无法整除的情况。 | ||
| 121 | - * 举个例子,presentPrice = 8.33 ,quantity = 3 的情况,presentTotal 有可能是 24.99 ,也可能是 25 。 | ||
| 122 | - * 所以,需要存储一个该字段。 | ||
| 123 | - */ | ||
| 124 | - private Integer presentTotal; | ||
| 125 | - | ||
| 126 | - } | ||
| 127 | - | ||
| 128 | - @Data | ||
| 129 | - @Accessors(chain = true) | ||
| 130 | - public static class Spu { | ||
| 131 | - | ||
| 132 | - /** | ||
| 133 | - * SPU 编号 | ||
| 134 | - */ | ||
| 135 | - private Integer id; | ||
| 136 | - | ||
| 137 | - // ========== 基本信息 ========= | ||
| 138 | - /** | ||
| 139 | - * SPU 名字 | ||
| 140 | - */ | ||
| 141 | - private String name; | ||
| 142 | - /** | ||
| 143 | - * 分类编号 | ||
| 144 | - */ | ||
| 145 | - private Integer cid; | ||
| 146 | - /** | ||
| 147 | - * 商品主图地址 | ||
| 148 | - * | ||
| 149 | - * 数组,以逗号分隔 | ||
| 150 | - * | ||
| 151 | - * 建议尺寸:800*800像素,你可以拖拽图片调整顺序,最多上传15张 | ||
| 152 | - */ | ||
| 153 | - private List<String> picUrls; | ||
| 154 | - | ||
| 155 | - } | ||
| 156 | - | ||
| 157 | - /** | ||
| 158 | - * 费用(合计) | ||
| 159 | - */ | ||
| 160 | - @Data | ||
| 161 | - @Accessors(chain = true) | ||
| 162 | - public static class Fee { | ||
| 163 | - | ||
| 164 | - /** | ||
| 165 | - * 购买总价 | ||
| 166 | - */ | ||
| 167 | - private Integer buyTotal; | ||
| 168 | - /** | ||
| 169 | - * 优惠总价 | ||
| 170 | - * | ||
| 171 | - * 注意,满多少元包邮,不算在优惠中。 | ||
| 172 | - */ | ||
| 173 | - private Integer discountTotal; | ||
| 174 | - /** | ||
| 175 | - * 邮费 | ||
| 176 | - */ | ||
| 177 | - private Integer postageTotal; | ||
| 178 | - /** | ||
| 179 | - * 最终价格 | ||
| 180 | - * | ||
| 181 | - * 计算公式 = 总价 - 优惠总价 + 邮费 | ||
| 182 | - */ | ||
| 183 | - private Integer presentTotal; | ||
| 184 | - | ||
| 185 | - public Fee() { | ||
| 186 | - } | ||
| 187 | - | ||
| 188 | - public Fee(Integer buyTotal, Integer discountTotal, Integer postageTotal, Integer presentTotal) { | ||
| 189 | - this.buyTotal = buyTotal; | ||
| 190 | - this.discountTotal = discountTotal; | ||
| 191 | - this.postageTotal = postageTotal; | ||
| 192 | - this.presentTotal = presentTotal; | ||
| 193 | - } | ||
| 194 | - | ||
| 195 | - } | ||
| 196 | - | ||
| 197 | - /** | ||
| 198 | - * 邮费信息 TODO 芋艿,未完成 | ||
| 199 | - */ | ||
| 200 | - @Data | ||
| 201 | - @Accessors(chain = true) | ||
| 202 | - public static class Postage { | ||
| 203 | - | ||
| 204 | - /** | ||
| 205 | - * 需要满足多少钱,可以包邮。单位:分 | ||
| 206 | - */ | ||
| 207 | - private Integer threshold; | ||
| 208 | - | ||
| 209 | - } | ||
| 210 | - | ||
| 211 | -} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
| @@ -60,8 +60,8 @@ public class AppTradeOrderController { | @@ -60,8 +60,8 @@ public class AppTradeOrderController { | ||
| 60 | 60 | ||
| 61 | @GetMapping("/get") | 61 | @GetMapping("/get") |
| 62 | @ApiOperation("获得交易订单") | 62 | @ApiOperation("获得交易订单") |
| 63 | - @ApiImplicitParam(name = "tradeOrderId", value = "交易订单编号", required = true) | ||
| 64 | - public CommonResult<TradeOrderRespVO> getTradeOrder(@RequestParam("tradeOrderId") Integer tradeOrderId) { | 63 | + @ApiImplicitParam(name = "id", value = "交易订单编号", required = true, dataTypeClass = Long.class) |
| 64 | + public CommonResult<TradeOrderRespVO> getTradeOrder(@RequestParam("id") Integer id) { | ||
| 65 | // return success(tradeOrderService.getTradeOrder(tradeOrderId)); | 65 | // return success(tradeOrderService.getTradeOrder(tradeOrderId)); |
| 66 | return null; | 66 | return null; |
| 67 | } | 67 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/cart/TradeCartConvert.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.convert.cart; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateReqDTO; | ||
| 4 | +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; | ||
| 5 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; | ||
| 6 | +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; | ||
| 7 | +import org.mapstruct.Mapper; | ||
| 8 | +import org.mapstruct.Mapping; | ||
| 9 | +import org.mapstruct.Mappings; | ||
| 10 | +import org.mapstruct.factory.Mappers; | ||
| 11 | + | ||
| 12 | +import java.util.Collections; | ||
| 13 | +import java.util.List; | ||
| 14 | + | ||
| 15 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | ||
| 16 | + | ||
| 17 | +@Mapper | ||
| 18 | +public interface TradeCartConvert { | ||
| 19 | + | ||
| 20 | + TradeCartConvert INSTANCE = Mappers.getMapper(TradeCartConvert.class); | ||
| 21 | + | ||
| 22 | + default AppTradeCartDetailRespVO buildEmptyAppTradeCartDetailRespVO() { | ||
| 23 | + return new AppTradeCartDetailRespVO().setItemGroups(Collections.emptyList()) | ||
| 24 | + .setOrder(new AppTradeCartDetailRespVO.Order().setSkuOriginalPrice(0).setSkuPromotionPrice(0) | ||
| 25 | + .setOrderPromotionPrice(0).setDeliveryPrice(0).setPayPrice(0)); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + default PriceCalculateReqDTO convert(Long userId, List<TradeCartItemDO> cartItems) { | ||
| 29 | + return new PriceCalculateReqDTO().setUserId(userId) | ||
| 30 | + .setItems(convertList(cartItems, cartItem -> new PriceCalculateReqDTO.Item().setSkuId(cartItem.getSkuId()) | ||
| 31 | + .setCount(cartItem.getSelected() ? cartItem.getCount() : 0))); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + // ========== AppTradeCartDetailRespVO 相关 ========== | ||
| 35 | + | ||
| 36 | + AppTradeCartDetailRespVO.Promotion convert(PriceCalculateRespDTO.Promotion bean); | ||
| 37 | + | ||
| 38 | + @Mappings({ | ||
| 39 | + @Mapping(source = "cartItem.count", target = "count") | ||
| 40 | + }) | ||
| 41 | + AppTradeCartDetailRespVO.Sku convert(PriceCalculateRespDTO.OrderItem orderItem, TradeCartItemDO cartItem); | ||
| 42 | + | ||
| 43 | + AppTradeCartDetailRespVO.Order convert(PriceCalculateRespDTO.Order bean); | ||
| 44 | + | ||
| 45 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderItemConvert.java
| @@ -29,7 +29,7 @@ public interface TradeOrderItemConvert { | @@ -29,7 +29,7 @@ public interface TradeOrderItemConvert { | ||
| 29 | @Mapping(source = "tradeOrder.userId", target = "userId"), | 29 | @Mapping(source = "tradeOrder.userId", target = "userId"), |
| 30 | @Mapping(source = "tradeOrder.orderId", target = "orderId") | 30 | @Mapping(source = "tradeOrder.orderId", target = "orderId") |
| 31 | }) | 31 | }) |
| 32 | - default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrder, List<PriceCalculateRespDTO.Item> items) { | 32 | + default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrder, List<PriceCalculateRespDTO.OrderItem> items) { |
| 33 | // TODO @Com: Mapstruct 生成会报错 | 33 | // TODO @Com: Mapstruct 生成会报错 |
| 34 | throw new UnsupportedOperationException("无法实现"); | 34 | throw new UnsupportedOperationException("无法实现"); |
| 35 | } | 35 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/sku/ProductSkuConvert.java
| @@ -7,6 +7,7 @@ import org.mapstruct.factory.Mappers; | @@ -7,6 +7,7 @@ import org.mapstruct.factory.Mappers; | ||
| 7 | 7 | ||
| 8 | import java.util.List; | 8 | import java.util.List; |
| 9 | 9 | ||
| 10 | +// TODO @LeeYan9:挪到 OrderConvert 那 | ||
| 10 | /** | 11 | /** |
| 11 | * @author LeeYan9 | 12 | * @author LeeYan9 |
| 12 | * @since 2022-08-26 | 13 | * @since 2022-08-26 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartItemDO.java renamed to yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/TradeCartItemDO.java
| @@ -6,16 +6,16 @@ import lombok.Data; | @@ -6,16 +6,16 @@ import lombok.Data; | ||
| 6 | import lombok.EqualsAndHashCode; | 6 | import lombok.EqualsAndHashCode; |
| 7 | import lombok.experimental.Accessors; | 7 | import lombok.experimental.Accessors; |
| 8 | 8 | ||
| 9 | -import java.util.Date; | ||
| 10 | - | ||
| 11 | /** | 9 | /** |
| 12 | * 购物车的商品信息 DO | 10 | * 购物车的商品信息 DO |
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | */ | 13 | */ |
| 14 | @TableName("trade_cart_item") | 14 | @TableName("trade_cart_item") |
| 15 | @Data | 15 | @Data |
| 16 | @EqualsAndHashCode(callSuper = true) | 16 | @EqualsAndHashCode(callSuper = true) |
| 17 | @Accessors(chain = true) | 17 | @Accessors(chain = true) |
| 18 | -public class CartItemDO extends BaseDO { | 18 | +public class TradeCartItemDO extends BaseDO { |
| 19 | 19 | ||
| 20 | // ========= 基础字段 BEGIN ========= | 20 | // ========= 基础字段 BEGIN ========= |
| 21 | 21 | ||
| @@ -27,10 +27,6 @@ public class CartItemDO extends BaseDO { | @@ -27,10 +27,6 @@ public class CartItemDO extends BaseDO { | ||
| 27 | * 是否选中 | 27 | * 是否选中 |
| 28 | */ | 28 | */ |
| 29 | private Boolean selected; | 29 | private Boolean selected; |
| 30 | - /** | ||
| 31 | - * 购物时间 | ||
| 32 | - */ | ||
| 33 | - private Date buyTime; // basket_date | ||
| 34 | 30 | ||
| 35 | // ========= 基础字段 END ========= | 31 | // ========= 基础字段 END ========= |
| 36 | 32 | ||
| @@ -62,7 +58,7 @@ public class CartItemDO extends BaseDO { | @@ -62,7 +58,7 @@ public class CartItemDO extends BaseDO { | ||
| 62 | /** | 58 | /** |
| 63 | * 商品购买数量 | 59 | * 商品购买数量 |
| 64 | */ | 60 | */ |
| 65 | - private Integer stock; | 61 | + private Integer count; |
| 66 | 62 | ||
| 67 | // ========= 商品信息 END ========= | 63 | // ========= 商品信息 END ========= |
| 68 | 64 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartItemMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.dal.mysql.cart; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.map.MapUtil; | ||
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||
| 6 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||
| 7 | +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; | ||
| 8 | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||
| 9 | +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | ||
| 10 | +import org.apache.ibatis.annotations.Mapper; | ||
| 11 | + | ||
| 12 | +import java.util.Collection; | ||
| 13 | +import java.util.List; | ||
| 14 | +import java.util.Map; | ||
| 15 | + | ||
| 16 | +@Mapper | ||
| 17 | +public interface TradeCartItemMapper extends BaseMapperX<TradeCartItemDO> { | ||
| 18 | + | ||
| 19 | + default TradeCartItemDO selectByUserIdAndSkuId(Long userId, Long skuId) { | ||
| 20 | + return selectOne(TradeCartItemDO::getUserId, userId, | ||
| 21 | + TradeCartItemDO::getSkuId, skuId); | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + default List<TradeCartItemDO> selectListByUserIdAndSkuIds(Long userId, Collection<Long> skuIds) { | ||
| 25 | + return selectList(new LambdaQueryWrapper<TradeCartItemDO>().eq(TradeCartItemDO::getUserId, userId) | ||
| 26 | + .in(TradeCartItemDO::getSkuId, skuIds)); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + default void updateByIds(Collection<Long> ids, TradeCartItemDO updateObject) { | ||
| 30 | + update(updateObject, new LambdaQueryWrapper<TradeCartItemDO>().in(TradeCartItemDO::getId, ids)); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + default Integer selectSumByUserId(Long userId) { | ||
| 34 | + // SQL sum 查询 | ||
| 35 | + List<Map<String, Object>> result = selectMaps(new QueryWrapper<TradeCartItemDO>() | ||
| 36 | + .select("SUM(count) AS sumCount") | ||
| 37 | + .eq("user_id", userId)); | ||
| 38 | + // 获得数量 | ||
| 39 | + return CollUtil.isNotEmpty(result) ? MapUtil.getInt(result.get(0), "sumCount") : 0; | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + default List<TradeCartItemDO> selectListByUserId(Long userId, Boolean selected) { | ||
| 43 | + return selectList(new LambdaQueryWrapperX<TradeCartItemDO>().eq(TradeCartItemDO::getUserId, userId) | ||
| 44 | + .eqIfPresent(TradeCartItemDO::getSelected, selected)); | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.cart; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; | ||
| 4 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; | ||
| 5 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; | ||
| 6 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; | ||
| 7 | + | ||
| 8 | +import javax.validation.Valid; | ||
| 9 | +import java.util.Collection; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 购物车 Service 接口 | ||
| 13 | + * | ||
| 14 | + * @author 芋道源码 | ||
| 15 | + */ | ||
| 16 | +public interface TradeCartService { | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 添加商品到购物车 | ||
| 20 | + * | ||
| 21 | + * @param userId 用户编号 | ||
| 22 | + * @param addCountReqVO 添加信息 | ||
| 23 | + */ | ||
| 24 | + void addCartItemCount(Long userId, @Valid AppTradeCartItemAddCountReqVO addCountReqVO); | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 更新购物车商品数量 | ||
| 28 | + * | ||
| 29 | + * @param userId 用户编号 | ||
| 30 | + * @param updateCountReqVO 更新信息 | ||
| 31 | + */ | ||
| 32 | + void updateCartItemCount(Long userId, AppTradeCartItemUpdateCountReqVO updateCountReqVO); | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * 更新购物车商品是否选中 | ||
| 36 | + * | ||
| 37 | + * @param userId 用户编号 | ||
| 38 | + * @param updateSelectedReqVO 更新信息 | ||
| 39 | + */ | ||
| 40 | + void updateCartItemSelected(Long userId, AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO); | ||
| 41 | + | ||
| 42 | + /** | ||
| 43 | + * 删除购物车商品 | ||
| 44 | + * | ||
| 45 | + * @param userId 用户编号 | ||
| 46 | + * @param skuIds SKU 编号的数组 | ||
| 47 | + */ | ||
| 48 | + void deleteCartItems(Long userId, Collection<Long> skuIds); | ||
| 49 | + | ||
| 50 | + /** | ||
| 51 | + * 查询用户在购物车中的商品数量 | ||
| 52 | + * | ||
| 53 | + * @param userId 用户编号 | ||
| 54 | + * @return 商品数量 | ||
| 55 | + */ | ||
| 56 | + Integer getCartCount(Long userId); | ||
| 57 | + | ||
| 58 | + /** | ||
| 59 | + * 查询用户的购物车详情 | ||
| 60 | + * | ||
| 61 | + * @param userId 用户编号 | ||
| 62 | + * @return 购物车详情 | ||
| 63 | + */ | ||
| 64 | + AppTradeCartDetailRespVO getCartDetail(Long userId); | ||
| 65 | + | ||
| 66 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.cart; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.lang.Assert; | ||
| 5 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 6 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 7 | +import cn.iocoder.yudao.module.market.api.price.PriceApi; | ||
| 8 | +import cn.iocoder.yudao.module.market.api.price.dto.PriceCalculateRespDTO; | ||
| 9 | +import cn.iocoder.yudao.module.market.enums.common.PromotionLevelEnum; | ||
| 10 | +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | ||
| 11 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 12 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartDetailRespVO; | ||
| 13 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemAddCountReqVO; | ||
| 14 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateCountReqVO; | ||
| 15 | +import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartItemUpdateSelectedReqVO; | ||
| 16 | +import cn.iocoder.yudao.module.trade.convert.cart.TradeCartConvert; | ||
| 17 | +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartItemDO; | ||
| 18 | +import cn.iocoder.yudao.module.trade.dal.mysql.cart.TradeCartItemMapper; | ||
| 19 | +import org.springframework.stereotype.Service; | ||
| 20 | +import org.springframework.validation.annotation.Validated; | ||
| 21 | + | ||
| 22 | +import javax.annotation.Resource; | ||
| 23 | +import java.util.ArrayList; | ||
| 24 | +import java.util.Collection; | ||
| 25 | +import java.util.List; | ||
| 26 | +import java.util.Map; | ||
| 27 | + | ||
| 28 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||
| 29 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||
| 30 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; | ||
| 31 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; | ||
| 32 | +import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.CARD_ITEM_NOT_FOUND; | ||
| 33 | + | ||
| 34 | +/** | ||
| 35 | + * 购物车 Service 实现类 | ||
| 36 | + * | ||
| 37 | + * @author 芋道源码 | ||
| 38 | + */ | ||
| 39 | +@Service | ||
| 40 | +@Validated | ||
| 41 | +public class TradeCartServiceImpl implements TradeCartService { | ||
| 42 | + | ||
| 43 | + @Resource | ||
| 44 | + private TradeCartItemMapper cartItemMapper; | ||
| 45 | + | ||
| 46 | + @Resource | ||
| 47 | + private ProductSkuApi productSkuApi; | ||
| 48 | + @Resource | ||
| 49 | + private PriceApi priceApi; | ||
| 50 | + | ||
| 51 | + @Override | ||
| 52 | + public void addCartItemCount(Long userId, AppTradeCartItemAddCountReqVO addCountReqVO) { | ||
| 53 | + Long skuId = addCountReqVO.getSkuId(); | ||
| 54 | + Integer count = addCountReqVO.getCount(); | ||
| 55 | + // 查询 CartItemDO | ||
| 56 | + TradeCartItemDO tradeItem = cartItemMapper.selectByUserIdAndSkuId(userId, addCountReqVO.getSkuId()); | ||
| 57 | + | ||
| 58 | + // 存在,则进行数量更新 | ||
| 59 | + if (tradeItem != null) { | ||
| 60 | + checkProductSku(skuId, tradeItem.getCount() + count); | ||
| 61 | + cartItemMapper.updateById(new TradeCartItemDO().setId(tradeItem.getId()) | ||
| 62 | + .setSelected(true).setCount(tradeItem.getCount() + count)); | ||
| 63 | + return; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + // 不存在,则进行插入 | ||
| 67 | + ProductSkuRespDTO sku = checkProductSku(skuId, count); | ||
| 68 | + cartItemMapper.insert(new TradeCartItemDO().setUserId(userId).setSpuId(sku.getSpuId()).setSkuId(sku.getId()) | ||
| 69 | + .setSelected(true).setCount(count)); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Override | ||
| 73 | + public void updateCartItemCount(Long userId, AppTradeCartItemUpdateCountReqVO updateCountReqVO) { | ||
| 74 | + // 校验 TradeCartItemDO 存在 | ||
| 75 | + TradeCartItemDO tradeItem = cartItemMapper.selectByUserIdAndSkuId(userId, updateCountReqVO.getSkuId()); | ||
| 76 | + if (tradeItem == null) { | ||
| 77 | + throw exception(CARD_ITEM_NOT_FOUND); | ||
| 78 | + } | ||
| 79 | + // 校验商品 SKU | ||
| 80 | + checkProductSku(updateCountReqVO.getSkuId(), updateCountReqVO.getCount()); | ||
| 81 | + | ||
| 82 | + // 更新数量 | ||
| 83 | + cartItemMapper.updateById(new TradeCartItemDO().setId(tradeItem.getId()).setCount(updateCountReqVO.getCount())); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + @Override | ||
| 87 | + public void updateCartItemSelected(Long userId, AppTradeCartItemUpdateSelectedReqVO updateSelectedReqVO) { | ||
| 88 | + // 查询 CartItemDO 列表 | ||
| 89 | + List<TradeCartItemDO> cartItems = cartItemMapper.selectListByUserIdAndSkuIds(userId, updateSelectedReqVO.getSkuIds()); | ||
| 90 | + if (CollUtil.isEmpty(cartItems)) { | ||
| 91 | + return; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + // 更新选中 | ||
| 95 | + cartItemMapper.updateByIds(CollectionUtils.convertList(cartItems, TradeCartItemDO::getId), | ||
| 96 | + new TradeCartItemDO().setSelected(updateSelectedReqVO.getSelected())); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + /** | ||
| 100 | + * 购物车删除商品 | ||
| 101 | + * | ||
| 102 | + * @param userId 用户编号 | ||
| 103 | + * @param skuIds 商品 SKU 编号的数组 | ||
| 104 | + */ | ||
| 105 | + @Override | ||
| 106 | + public void deleteCartItems(Long userId, Collection<Long> skuIds) { | ||
| 107 | + // 查询 CartItemDO 列表 | ||
| 108 | + List<TradeCartItemDO> cartItems = cartItemMapper.selectListByUserIdAndSkuIds(userId, skuIds); | ||
| 109 | + if (CollUtil.isEmpty(cartItems)) { | ||
| 110 | + return; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + // 批量标记删除 | ||
| 114 | + cartItemMapper.deleteBatchIds(CollectionUtils.convertSet(cartItems, TradeCartItemDO::getId)); | ||
| 115 | + } | ||
| 116 | + | ||
| 117 | + @Override | ||
| 118 | + public Integer getCartCount(Long userId) { | ||
| 119 | + return cartItemMapper.selectSumByUserId(userId); | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + @Override | ||
| 123 | + public AppTradeCartDetailRespVO getCartDetail(Long userId) { | ||
| 124 | + // 获得购物车的商品 | ||
| 125 | + List<TradeCartItemDO> cartItems = cartItemMapper.selectListByUserId(userId, null); | ||
| 126 | + // 如果未空,则返回空结果 | ||
| 127 | + if (CollUtil.isEmpty(cartItems)) { | ||
| 128 | + return TradeCartConvert.INSTANCE.buildEmptyAppTradeCartDetailRespVO(); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + // 调用价格服务,计算价格 | ||
| 132 | + PriceCalculateRespDTO priceCalculate = priceApi.calculatePrice(TradeCartConvert.INSTANCE.convert(userId, cartItems)); | ||
| 133 | + | ||
| 134 | + // 转换返回 | ||
| 135 | + Map<Long, TradeCartItemDO> cartItemMap = convertMap(cartItems, TradeCartItemDO::getSkuId); | ||
| 136 | + Map<Long, PriceCalculateRespDTO.OrderItem> orderItemMap = convertMap(priceCalculate.getOrder().getItems(), | ||
| 137 | + PriceCalculateRespDTO.OrderItem::getSkuId); | ||
| 138 | + List<AppTradeCartDetailRespVO.ItemGroup> itemGroups = new ArrayList<>(cartItems.size()); | ||
| 139 | + // ① 场景一,营销活动,订单级别 TODO 芋艿:待测试 | ||
| 140 | + priceCalculate.getPromotions().stream().filter(promotion -> PromotionLevelEnum.ORDER.getLevel().equals(promotion.getLevel())) | ||
| 141 | + .forEach(promotion -> { | ||
| 142 | + AppTradeCartDetailRespVO.ItemGroup itemGroup = new AppTradeCartDetailRespVO.ItemGroup().setItems(new ArrayList<>()) | ||
| 143 | + .setPromotion(TradeCartConvert.INSTANCE.convert(promotion)); | ||
| 144 | + itemGroups.add(itemGroup); | ||
| 145 | + promotion.getItems().forEach(promotionItem -> { | ||
| 146 | + PriceCalculateRespDTO.OrderItem orderItem = orderItemMap.remove(promotionItem.getSkuId()); | ||
| 147 | + Assert.notNull(orderItem, "商品 SKU({}) 对应的订单项不能为空", promotionItem.getSkuId()); | ||
| 148 | + TradeCartItemDO cartItem = cartItemMap.get(orderItem.getSkuId()); | ||
| 149 | + itemGroup.getItems().add(TradeCartConvert.INSTANCE.convert(orderItem, cartItem)); // TODO spu | ||
| 150 | + }); | ||
| 151 | + }); | ||
| 152 | + // ② 场景二,营销活动,商品级别 | ||
| 153 | + orderItemMap.values().forEach(orderItem -> { | ||
| 154 | + AppTradeCartDetailRespVO.ItemGroup itemGroup = new AppTradeCartDetailRespVO.ItemGroup().setItems(new ArrayList<>(1)).setPromotion(null); | ||
| 155 | + itemGroups.add(itemGroup); | ||
| 156 | + TradeCartItemDO cartItem = cartItemMap.get(orderItem.getSkuId()); | ||
| 157 | + itemGroup.getItems().add(TradeCartConvert.INSTANCE.convert(orderItem, cartItem)); // TODO spu | ||
| 158 | + }); | ||
| 159 | + return new AppTradeCartDetailRespVO().setItemGroups(itemGroups) | ||
| 160 | + .setOrder(TradeCartConvert.INSTANCE.convert(priceCalculate.getOrder())); | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + /** | ||
| 164 | + * 校验商品 SKU 是否合法 | ||
| 165 | + * 1. 是否存在 | ||
| 166 | + * 2. 是否下架 | ||
| 167 | + * 3. 库存不足 | ||
| 168 | + * | ||
| 169 | + * @param skuId 商品 SKU 编号 | ||
| 170 | + * @param count 商品数量 | ||
| 171 | + * @return 商品 SKU | ||
| 172 | + */ | ||
| 173 | + private ProductSkuRespDTO checkProductSku(Long skuId, Integer count) { | ||
| 174 | + ProductSkuRespDTO sku = productSkuApi.getSku(skuId); | ||
| 175 | + if (sku == null || CommonStatusEnum.DISABLE.getStatus().equals(sku.getStatus())) { | ||
| 176 | + throw exception(SKU_NOT_EXISTS); | ||
| 177 | + } | ||
| 178 | + if (count > sku.getStock()) { | ||
| 179 | + throw exception(SKU_STOCK_NOT_ENOUGH); | ||
| 180 | + } | ||
| 181 | + return sku; | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
| @@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; | @@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; | ||
| 11 | import cn.iocoder.yudao.module.pay.api.order.PayOrderDataCreateReqDTO; | 11 | import cn.iocoder.yudao.module.pay.api.order.PayOrderDataCreateReqDTO; |
| 12 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | 12 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |
| 13 | import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; | 13 | import cn.iocoder.yudao.module.product.api.sku.dto.SkuDecrementStockBatchReqDTO; |
| 14 | -import cn.iocoder.yudao.module.product.api.sku.dto.SkuInfoRespDTO; | 14 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 15 | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | 15 | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; |
| 16 | import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; | 16 | import cn.iocoder.yudao.module.product.api.spu.dto.SpuInfoRespDTO; |
| 17 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | 17 | import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; |
| @@ -26,7 +26,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | @@ -26,7 +26,7 @@ import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | ||
| 26 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; | 26 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; |
| 27 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; | 27 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; |
| 28 | import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper; | 28 | import cn.iocoder.yudao.module.trade.dal.mysql.orderitem.TradeOrderItemMapper; |
| 29 | -import cn.iocoder.yudao.module.trade.enums.enums.ErrorCodeConstants; | 29 | +import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; |
| 30 | import lombok.RequiredArgsConstructor; | 30 | import lombok.RequiredArgsConstructor; |
| 31 | import org.springframework.stereotype.Service; | 31 | import org.springframework.stereotype.Service; |
| 32 | import org.springframework.transaction.annotation.Transactional; | 32 | import org.springframework.transaction.annotation.Transactional; |
| @@ -62,12 +62,12 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -62,12 +62,12 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 62 | 62 | ||
| 63 | List<Item> items = createReqVO.getItems(); | 63 | List<Item> items = createReqVO.getItems(); |
| 64 | // 商品SKU检查 sku可售状态,库存 | 64 | // 商品SKU检查 sku可售状态,库存 |
| 65 | - List<SkuInfoRespDTO> skuInfos = productSkuApi.getSkusByIds(CollectionUtils.convertSet(items, Item::getSkuId)); | ||
| 66 | - Map<Long, SkuInfoRespDTO> skuInfoMap = CollectionUtils.convertMap(skuInfos, SkuInfoRespDTO::getId); | 65 | + List<ProductSkuRespDTO> skuInfos = productSkuApi.getSkuList(CollectionUtils.convertSet(items, Item::getSkuId)); |
| 66 | + Map<Long, ProductSkuRespDTO> skuInfoMap = CollectionUtils.convertMap(skuInfos, ProductSkuRespDTO::getId); | ||
| 67 | checkSaleableAndStockFromSpu(skuInfoMap, items); | 67 | checkSaleableAndStockFromSpu(skuInfoMap, items); |
| 68 | 68 | ||
| 69 | // 商品SPU检查 sku可售状态,库存 | 69 | // 商品SPU检查 sku可售状态,库存 |
| 70 | - List<SpuInfoRespDTO> spuInfos = productSpuApi.getSpusByIds(CollectionUtils.convertSet(skuInfos, SkuInfoRespDTO::getSpuId)); | 70 | + List<SpuInfoRespDTO> spuInfos = productSpuApi.getSpuList(CollectionUtils.convertSet(skuInfos, ProductSkuRespDTO::getSpuId)); |
| 71 | checkSaleableFromSpu(spuInfos); | 71 | checkSaleableFromSpu(spuInfos); |
| 72 | 72 | ||
| 73 | // 价格计算 | 73 | // 价格计算 |
| @@ -79,7 +79,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -79,7 +79,7 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 79 | tradeOrderMapper.insert(tradeOrderDO); | 79 | tradeOrderMapper.insert(tradeOrderDO); |
| 80 | 80 | ||
| 81 | // 订单项信息记录 | 81 | // 订单项信息记录 |
| 82 | - List<TradeOrderItemDO> tradeOrderItems = TradeOrderItemConvert.INSTANCE.convertList(tradeOrderDO, priceResp.getItems()); | 82 | + List<TradeOrderItemDO> tradeOrderItems = TradeOrderItemConvert.INSTANCE.convertList(tradeOrderDO, priceResp.getOrder().getItems()); |
| 83 | //-填充订单项-SKU信息 | 83 | //-填充订单项-SKU信息 |
| 84 | fillItemsInfoFromSku(tradeOrderItems, skuInfoMap); | 84 | fillItemsInfoFromSku(tradeOrderItems, skuInfoMap); |
| 85 | tradeOrderItemMapper.insertBatch(tradeOrderItems); | 85 | tradeOrderItemMapper.insertBatch(tradeOrderItems); |
| @@ -94,10 +94,10 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -94,10 +94,10 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | private void fillItemsInfoFromSku(List<TradeOrderItemDO> tradeOrderItems, | 96 | private void fillItemsInfoFromSku(List<TradeOrderItemDO> tradeOrderItems, |
| 97 | - Map<Long, SkuInfoRespDTO> spuInfos) { | 97 | + Map<Long, ProductSkuRespDTO> spuInfos) { |
| 98 | for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) { | 98 | for (TradeOrderItemDO tradeOrderItem : tradeOrderItems) { |
| 99 | // 填充SKU信息 | 99 | // 填充SKU信息 |
| 100 | - SkuInfoRespDTO skuInfoRespDTO = spuInfos.get(tradeOrderItem.getSkuId()); | 100 | + ProductSkuRespDTO skuInfoRespDTO = spuInfos.get(tradeOrderItem.getSkuId()); |
| 101 | tradeOrderItem.setSpuId(skuInfoRespDTO.getSpuId()); | 101 | tradeOrderItem.setSpuId(skuInfoRespDTO.getSpuId()); |
| 102 | tradeOrderItem.setPicUrl(skuInfoRespDTO.getPicUrl()); | 102 | tradeOrderItem.setPicUrl(skuInfoRespDTO.getPicUrl()); |
| 103 | tradeOrderItem.setName(skuInfoRespDTO.getName()); | 103 | tradeOrderItem.setName(skuInfoRespDTO.getName()); |
| @@ -116,14 +116,14 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -116,14 +116,14 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 116 | } | 116 | } |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | - private void checkSaleableAndStockFromSpu(Map<Long, SkuInfoRespDTO> skuInfoMap, | 119 | + private void checkSaleableAndStockFromSpu(Map<Long, ProductSkuRespDTO> skuInfoMap, |
| 120 | List<Item> items) { | 120 | List<Item> items) { |
| 121 | // sku 不存在 | 121 | // sku 不存在 |
| 122 | if (items.size() != skuInfoMap.size()) { | 122 | if (items.size() != skuInfoMap.size()) { |
| 123 | throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SKU_NOT_FOUND); | 123 | throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SKU_NOT_FOUND); |
| 124 | } | 124 | } |
| 125 | for (Item item : items) { | 125 | for (Item item : items) { |
| 126 | - SkuInfoRespDTO skuInfoDTO = skuInfoMap.get(item.getSkuId()); | 126 | + ProductSkuRespDTO skuInfoDTO = skuInfoMap.get(item.getSkuId()); |
| 127 | // sku禁用 | 127 | // sku禁用 |
| 128 | if (!Objects.equals(CommonStatusEnum.ENABLE.getStatus(), skuInfoDTO.getStatus())) { | 128 | if (!Objects.equals(CommonStatusEnum.ENABLE.getStatus(), skuInfoDTO.getStatus())) { |
| 129 | throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SKU_NOT_SALE); | 129 | throw ServiceExceptionUtil.exception(ErrorCodeConstants.ORDER_SKU_NOT_SALE); |
yudao-server/src/main/resources/application-local.yaml
| @@ -173,6 +173,7 @@ logging: | @@ -173,6 +173,7 @@ logging: | ||
| 173 | cn.iocoder.yudao.module.system.dal.mysql: debug | 173 | cn.iocoder.yudao.module.system.dal.mysql: debug |
| 174 | cn.iocoder.yudao.module.tool.dal.mysql: debug | 174 | cn.iocoder.yudao.module.tool.dal.mysql: debug |
| 175 | cn.iocoder.yudao.module.member.dal.mysql: debug | 175 | cn.iocoder.yudao.module.member.dal.mysql: debug |
| 176 | + cn.iocoder.yudao.module.trade.dal.mysql: debug | ||
| 176 | 177 | ||
| 177 | --- #################### 微信公众号、小程序相关配置 #################### | 178 | --- #################### 微信公众号、小程序相关配置 #################### |
| 178 | wx: | 179 | wx: |