Commit ba380ea615fb6d5f9fcf7a061a0858a88e65bf7a
Merge remote-tracking branch 'yudao/feature/mall_product' into feature/mall_product
# Conflicts: # yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java # yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java # yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java
Showing
44 changed files
with
1381 additions
and
780 deletions
yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/sku/dto/ProductSkuRespDTO.java
| 1 | package cn.iocoder.yudao.module.product.api.sku.dto; | 1 | package cn.iocoder.yudao.module.product.api.sku.dto; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; | ||
| 3 | import lombok.Data; | 4 | import lombok.Data; |
| 4 | 5 | ||
| 5 | import java.util.List; | 6 | import java.util.List; |
| @@ -25,7 +26,7 @@ public class ProductSkuRespDTO { | @@ -25,7 +26,7 @@ public class ProductSkuRespDTO { | ||
| 25 | /** | 26 | /** |
| 26 | * 属性数组 | 27 | * 属性数组 |
| 27 | */ | 28 | */ |
| 28 | - private List<Property> properties; | 29 | + private List<ProductPropertyValueDetailRespDTO> properties; |
| 29 | /** | 30 | /** |
| 30 | * 销售价格,单位:分 | 31 | * 销售价格,单位:分 |
| 31 | */ | 32 | */ |
| @@ -51,10 +52,6 @@ public class ProductSkuRespDTO { | @@ -51,10 +52,6 @@ public class ProductSkuRespDTO { | ||
| 51 | */ | 52 | */ |
| 52 | private Integer stock; | 53 | private Integer stock; |
| 53 | /** | 54 | /** |
| 54 | - * 预警预存 | ||
| 55 | - */ | ||
| 56 | - private Integer warnStock; | ||
| 57 | - /** | ||
| 58 | * 商品重量,单位:kg 千克 | 55 | * 商品重量,单位:kg 千克 |
| 59 | */ | 56 | */ |
| 60 | private Double weight; | 57 | private Double weight; |
| @@ -63,30 +60,4 @@ public class ProductSkuRespDTO { | @@ -63,30 +60,4 @@ public class ProductSkuRespDTO { | ||
| 63 | */ | 60 | */ |
| 64 | private Double volume; | 61 | private Double volume; |
| 65 | 62 | ||
| 66 | - /** | ||
| 67 | - * 商品属性 | ||
| 68 | - */ | ||
| 69 | - @Data | ||
| 70 | - public static class Property { | ||
| 71 | - | ||
| 72 | - /** | ||
| 73 | - * 属性编号 | ||
| 74 | - */ | ||
| 75 | - private Long propertyId; | ||
| 76 | - /** | ||
| 77 | - * 属性名字 | ||
| 78 | - */ | ||
| 79 | - private String propertyName; | ||
| 80 | - | ||
| 81 | - /** | ||
| 82 | - * 属性值编号 | ||
| 83 | - */ | ||
| 84 | - private Long valueId; | ||
| 85 | - /** | ||
| 86 | - * 属性值名字 | ||
| 87 | - */ | ||
| 88 | - private String valueName; | ||
| 89 | - | ||
| 90 | - } | ||
| 91 | - | ||
| 92 | } | 63 | } |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/spu/vo/AppProductSpuDetailRespVO.java
| @@ -18,6 +18,9 @@ public class AppProductSpuDetailRespVO { | @@ -18,6 +18,9 @@ public class AppProductSpuDetailRespVO { | ||
| 18 | @Schema(description = "商品名称", required = true, example = "芋道") | 18 | @Schema(description = "商品名称", required = true, example = "芋道") |
| 19 | private String name; | 19 | private String name; |
| 20 | 20 | ||
| 21 | + @Schema(description = "商品简介", required = true, example = "我是一个快乐简介") | ||
| 22 | + private String introduction; | ||
| 23 | + | ||
| 21 | @Schema(description = "商品详情", required = true, example = "我是商品描述") | 24 | @Schema(description = "商品详情", required = true, example = "我是商品描述") |
| 22 | private String description; | 25 | private String description; |
| 23 | 26 |
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/dataobject/spu/ProductSpuDO.java
| @@ -141,7 +141,7 @@ public class ProductSpuDO extends BaseDO { | @@ -141,7 +141,7 @@ public class ProductSpuDO extends BaseDO { | ||
| 141 | /** | 141 | /** |
| 142 | * 物流配置模板编号 | 142 | * 物流配置模板编号 |
| 143 | * | 143 | * |
| 144 | - * 关联 { TradeDeliveryExpressTemplateDO#getId()} | 144 | + * 对应 TradeDeliveryExpressTemplateDO 的 id 编号 |
| 145 | */ | 145 | */ |
| 146 | private Long deliveryTemplateId; | 146 | private Long deliveryTemplateId; |
| 147 | 147 |
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/price/dto/PriceCalculateReqDTO.java
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/price/PriceServiceTest.java
| 1 | package cn.iocoder.yudao.module.promotion.service.price; | 1 | package cn.iocoder.yudao.module.promotion.service.price; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.map.MapUtil; | ||
| 4 | import cn.iocoder.yudao.framework.common.exception.ServiceException; | 3 | import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 5 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | 4 | import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; |
| 6 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | 5 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |
| 7 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | 6 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 8 | import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO; | 7 | import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO; |
| 9 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; | 8 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; |
| 10 | -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | ||
| 11 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; | 9 | import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO; |
| 12 | -import cn.iocoder.yudao.module.promotion.dal.dataobject.reward.RewardActivityDO; | ||
| 13 | -import cn.iocoder.yudao.module.promotion.enums.common.*; | 10 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; |
| 14 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; | 11 | import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum; |
| 15 | import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; | 12 | import cn.iocoder.yudao.module.promotion.service.coupon.CouponService; |
| 16 | -import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService; | ||
| 17 | import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; | 13 | import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService; |
| 18 | import org.junit.jupiter.api.Test; | 14 | import org.junit.jupiter.api.Test; |
| 19 | import org.mockito.InjectMocks; | 15 | import org.mockito.InjectMocks; |
| 20 | import org.mockito.Mock; | 16 | import org.mockito.Mock; |
| 21 | 17 | ||
| 22 | -import java.util.LinkedHashMap; | ||
| 23 | import java.util.List; | 18 | import java.util.List; |
| 24 | -import java.util.Map; | ||
| 25 | -import java.util.Set; | ||
| 26 | 19 | ||
| 27 | import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; | 20 | import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; |
| 28 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | 21 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| 29 | -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; | ||
| 30 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | 22 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 31 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW; | 23 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW; |
| 32 | import static java.util.Arrays.asList; | 24 | import static java.util.Arrays.asList; |
| @@ -47,413 +39,18 @@ public class PriceServiceTest extends BaseMockitoUnitTest { | @@ -47,413 +39,18 @@ public class PriceServiceTest extends BaseMockitoUnitTest { | ||
| 47 | private PriceServiceImpl priceService; | 39 | private PriceServiceImpl priceService; |
| 48 | 40 | ||
| 49 | @Mock | 41 | @Mock |
| 50 | - private DiscountActivityService discountService; | ||
| 51 | - @Mock | ||
| 52 | private RewardActivityService rewardActivityService; | 42 | private RewardActivityService rewardActivityService; |
| 53 | @Mock | 43 | @Mock |
| 54 | private CouponService couponService; | 44 | private CouponService couponService; |
| 55 | @Mock | 45 | @Mock |
| 56 | private ProductSkuApi productSkuApi; | 46 | private ProductSkuApi productSkuApi; |
| 57 | 47 | ||
| 58 | - @Test | ||
| 59 | - public void testCalculatePrice_memberDiscount() { | ||
| 60 | - // 准备参数 | ||
| 61 | - // TODO 芋艿:userId = 1,实现 9 折;后续改成 mock | ||
| 62 | - PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(1L) | ||
| 63 | - .setItems(singletonList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2))); | ||
| 64 | - // mock 方法(商品 SKU 信息) | ||
| 65 | - ProductSkuRespDTO productSku = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100)); | ||
| 66 | - when(productSkuApi.getSkuList(eq(asSet(10L)))).thenReturn(singletonList(productSku)); | ||
| 67 | - | ||
| 68 | - // 调用 | ||
| 69 | - //PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); TODO 没有这个方法 | ||
| 70 | - PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO(); | ||
| 71 | - // 断言 Order 部分 | ||
| 72 | - PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); | ||
| 73 | - assertEquals(order.getTotalPrice(), 200); | ||
| 74 | - assertEquals(order.getDiscountPrice(), 0); | ||
| 75 | - assertEquals(order.getPointPrice(), 0); | ||
| 76 | - assertEquals(order.getDeliveryPrice(), 0); | ||
| 77 | - assertEquals(order.getPayPrice(), 180); | ||
| 78 | - assertNull(order.getCouponId()); | ||
| 79 | - // 断言 OrderItem 部分 | ||
| 80 | - assertEquals(order.getItems().size(), 1); | ||
| 81 | - PriceCalculateRespDTO.OrderItem orderItem = order.getItems().get(0); | ||
| 82 | - assertEquals(orderItem.getSkuId(), 10L); | ||
| 83 | - assertEquals(orderItem.getCount(), 2); | ||
| 84 | - assertEquals(orderItem.getOriginalPrice(), 200); | ||
| 85 | - assertEquals(orderItem.getOriginalUnitPrice(), 100); | ||
| 86 | - assertEquals(orderItem.getDiscountPrice(), 20); | ||
| 87 | - assertEquals(orderItem.getPayPrice(), 180); | ||
| 88 | - assertEquals(orderItem.getOrderPartPrice(), 0); | ||
| 89 | - assertEquals(orderItem.getOrderDividePrice(), 180); | ||
| 90 | - // 断言 Promotion 部分 | ||
| 91 | - assertEquals(priceCalculate.getPromotions().size(), 1); | ||
| 92 | - PriceCalculateRespDTO.Promotion promotion = priceCalculate.getPromotions().get(0); | ||
| 93 | - assertNull(promotion.getId()); | ||
| 94 | - assertEquals(promotion.getName(), "会员折扣"); | ||
| 95 | - assertEquals(promotion.getType(), PromotionTypeEnum.MEMBER.getType()); | ||
| 96 | - //assertEquals(promotion.getLevel(), PromotionLevelEnum.SKU.getLevel()); TODO 没有这个枚举类 | ||
| 97 | - assertEquals(promotion.getTotalPrice(), 200); | ||
| 98 | - assertEquals(promotion.getDiscountPrice(), 20); | ||
| 99 | - assertTrue(promotion.getMatch()); | ||
| 100 | - assertEquals(promotion.getDescription(), "会员折扣:省 0.20 元"); | ||
| 101 | - PriceCalculateRespDTO.PromotionItem promotionItem = promotion.getItems().get(0); | ||
| 102 | - assertEquals(promotion.getItems().size(), 1); | ||
| 103 | - assertEquals(promotionItem.getSkuId(), 10L); | ||
| 104 | - assertEquals(promotionItem.getOriginalPrice(), 200); | ||
| 105 | - assertEquals(promotionItem.getDiscountPrice(), 20); | ||
| 106 | - } | ||
| 107 | - | ||
| 108 | - @Test | ||
| 109 | - public void testCalculatePrice_discountActivity() { | ||
| 110 | - // 准备参数 | ||
| 111 | - PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(randomLongId()) | ||
| 112 | - .setItems(asList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2), | ||
| 113 | - new PriceCalculateReqDTO.Item().setSkuId(20L).setCount(3))); | ||
| 114 | - // mock 方法(商品 SKU 信息) | ||
| 115 | - ProductSkuRespDTO productSku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100)); | ||
| 116 | - ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50)); | ||
| 117 | - when(productSkuApi.getSkuList(eq(asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02)); | ||
| 118 | - // mock 方法(限时折扣 DiscountActivity 信息)TODO 没找到 DiscountProductDetailBO | ||
| 119 | - //DiscountProductDetailBO discountProduct01 = randomPojo(DiscountProductDetailBO.class, o -> o.setActivityId(1000L) | ||
| 120 | - // .setActivityName("活动 1000 号").setSkuId(10L) | ||
| 121 | - // .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(40)); | ||
| 122 | - //DiscountProductDetailBO discountProduct02 = randomPojo(DiscountProductDetailBO.class, o -> o.setActivityId(2000L) | ||
| 123 | - // .setActivityName("活动 2000 号").setSkuId(20L) | ||
| 124 | - // .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(60)); | ||
| 125 | - //when(discountService.getMatchDiscountProductList(eq(asSet(10L, 20L)))).thenReturn( | ||
| 126 | - // MapUtil.builder(10L, discountProduct01).put(20L, discountProduct02).map()); | ||
| 127 | - | ||
| 128 | - // 10L: 100 * 2 - 40 * 2 = 120 | ||
| 129 | - // 20L:50 * 3 - 50 * 3 * 0.4 = 90 | ||
| 130 | - | ||
| 131 | - // 调用 | ||
| 132 | - //PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); TODO 没有这个方法 | ||
| 133 | - PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO(); | ||
| 134 | - // 断言 Order 部分 | ||
| 135 | - PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); | ||
| 136 | - assertEquals(order.getTotalPrice(), 350); | ||
| 137 | - assertEquals(order.getDiscountPrice(), 0); | ||
| 138 | - assertEquals(order.getPointPrice(), 0); | ||
| 139 | - assertEquals(order.getDeliveryPrice(), 0); | ||
| 140 | - assertEquals(order.getPayPrice(), 210); | ||
| 141 | - assertNull(order.getCouponId()); | ||
| 142 | - // 断言 OrderItem 部分 | ||
| 143 | - assertEquals(order.getItems().size(), 2); | ||
| 144 | - PriceCalculateRespDTO.OrderItem orderItem01 = order.getItems().get(0); | ||
| 145 | - assertEquals(orderItem01.getSkuId(), 10L); | ||
| 146 | - assertEquals(orderItem01.getCount(), 2); | ||
| 147 | - assertEquals(orderItem01.getOriginalPrice(), 200); | ||
| 148 | - assertEquals(orderItem01.getOriginalUnitPrice(), 100); | ||
| 149 | - assertEquals(orderItem01.getDiscountPrice(), 80); | ||
| 150 | - assertEquals(orderItem01.getPayPrice(), 120); | ||
| 151 | - assertEquals(orderItem01.getOrderPartPrice(), 0); | ||
| 152 | - assertEquals(orderItem01.getOrderDividePrice(), 120); | ||
| 153 | - PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1); | ||
| 154 | - assertEquals(orderItem02.getSkuId(), 20L); | ||
| 155 | - assertEquals(orderItem02.getCount(), 3); | ||
| 156 | - assertEquals(orderItem02.getOriginalPrice(), 150); | ||
| 157 | - assertEquals(orderItem02.getOriginalUnitPrice(), 50); | ||
| 158 | - assertEquals(orderItem02.getDiscountPrice(), 60); | ||
| 159 | - assertEquals(orderItem02.getPayPrice(), 90); | ||
| 160 | - assertEquals(orderItem02.getOrderPartPrice(), 0); | ||
| 161 | - assertEquals(orderItem02.getOrderDividePrice(), 90); | ||
| 162 | - // 断言 Promotion 部分 | ||
| 163 | - assertEquals(priceCalculate.getPromotions().size(), 2); | ||
| 164 | - PriceCalculateRespDTO.Promotion promotion01 = priceCalculate.getPromotions().get(0); | ||
| 165 | - assertEquals(promotion01.getId(), 1000L); | ||
| 166 | - assertEquals(promotion01.getName(), "活动 1000 号"); | ||
| 167 | - assertEquals(promotion01.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()); | ||
| 168 | - //assertEquals(promotion01.getLevel(), PromotionLevelEnum.SKU.getLevel()); TODO PromotionLevelEnum 没有这个枚举类 | ||
| 169 | - assertEquals(promotion01.getTotalPrice(), 200); | ||
| 170 | - assertEquals(promotion01.getDiscountPrice(), 80); | ||
| 171 | - assertTrue(promotion01.getMatch()); | ||
| 172 | - assertEquals(promotion01.getDescription(), "限时折扣:省 0.80 元"); | ||
| 173 | - PriceCalculateRespDTO.PromotionItem promotionItem01 = promotion01.getItems().get(0); | ||
| 174 | - assertEquals(promotion01.getItems().size(), 1); | ||
| 175 | - assertEquals(promotionItem01.getSkuId(), 10L); | ||
| 176 | - assertEquals(promotionItem01.getOriginalPrice(), 200); | ||
| 177 | - assertEquals(promotionItem01.getDiscountPrice(), 80); | ||
| 178 | - PriceCalculateRespDTO.Promotion promotion02 = priceCalculate.getPromotions().get(1); | ||
| 179 | - assertEquals(promotion02.getId(), 2000L); | ||
| 180 | - assertEquals(promotion02.getName(), "活动 2000 号"); | ||
| 181 | - assertEquals(promotion02.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()); | ||
| 182 | - //assertEquals(promotion02.getLevel(), PromotionLevelEnum.SKU.getLevel()); TODO PromotionLevelEnum 没有这个枚举类 | ||
| 183 | - assertEquals(promotion02.getTotalPrice(), 150); | ||
| 184 | - assertEquals(promotion02.getDiscountPrice(), 60); | ||
| 185 | - assertTrue(promotion02.getMatch()); | ||
| 186 | - assertEquals(promotion02.getDescription(), "限时折扣:省 0.60 元"); | ||
| 187 | - PriceCalculateRespDTO.PromotionItem promotionItem02 = promotion02.getItems().get(0); | ||
| 188 | - assertEquals(promotion02.getItems().size(), 1); | ||
| 189 | - assertEquals(promotionItem02.getSkuId(), 20L); | ||
| 190 | - assertEquals(promotionItem02.getOriginalPrice(), 150); | ||
| 191 | - assertEquals(promotionItem02.getDiscountPrice(), 60); | ||
| 192 | - } | ||
| 193 | - | ||
| 194 | - /** | ||
| 195 | - * 测试满减送活动,匹配的情况 | ||
| 196 | - */ | ||
| 197 | - @Test | ||
| 198 | - public void testCalculatePrice_rewardActivity() { | ||
| 199 | - // 准备参数 | ||
| 200 | - PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(randomLongId()) | ||
| 201 | - .setItems(asList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2), | ||
| 202 | - new PriceCalculateReqDTO.Item().setSkuId(20L).setCount(3), | ||
| 203 | - new PriceCalculateReqDTO.Item().setSkuId(30L).setCount(4))); | ||
| 204 | - // mock 方法(商品 SKU 信息) | ||
| 205 | - ProductSkuRespDTO productSku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100).setSpuId(1L)); | ||
| 206 | - ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50).setSpuId(2L)); | ||
| 207 | - ProductSkuRespDTO productSku03 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(30L).setPrice(30).setSpuId(3L)); | ||
| 208 | - when(productSkuApi.getSkuList(eq(asSet(10L, 20L, 30L)))).thenReturn(asList(productSku01, productSku02, productSku03)); | ||
| 209 | - // mock 方法(限时折扣 DiscountActivity 信息) | ||
| 210 | - RewardActivityDO rewardActivity01 = randomPojo(RewardActivityDO.class, o -> o.setId(1000L).setName("活动 1000 号") | ||
| 211 | - .setProductSpuIds(asList(10L, 20L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) | ||
| 212 | - .setRules(singletonList(new RewardActivityDO.Rule().setLimit(200).setDiscountPrice(70)))); | ||
| 213 | - RewardActivityDO rewardActivity02 = randomPojo(RewardActivityDO.class, o -> o.setId(2000L).setName("活动 2000 号") | ||
| 214 | - .setProductSpuIds(singletonList(30L)).setConditionType(PromotionConditionTypeEnum.COUNT.getType()) | ||
| 215 | - .setRules(asList(new RewardActivityDO.Rule().setLimit(1).setDiscountPrice(10), | ||
| 216 | - new RewardActivityDO.Rule().setLimit(2).setDiscountPrice(60), // 最大可满足,因为是 4 个 | ||
| 217 | - new RewardActivityDO.Rule().setLimit(10).setDiscountPrice(100)))); | ||
| 218 | - Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>(); | ||
| 219 | - matchRewardActivities.put(rewardActivity01, asSet(1L, 2L)); | ||
| 220 | - matchRewardActivities.put(rewardActivity02, asSet(3L)); | ||
| 221 | - // TODO getMatchRewardActivities 没有这个方法,但是找到了 getMatchRewardActivityList | ||
| 222 | - //when(rewardActivityService.getMatchRewardActivities(eq(asSet(1L, 2L, 3L)))).thenReturn(matchRewardActivities); | ||
| 223 | - | ||
| 224 | - // 调用 | ||
| 225 | - //PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); TODO 没有这个方法 | ||
| 226 | - PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO(); | ||
| 227 | - // 断言 Order 部分 | ||
| 228 | - PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); | ||
| 229 | - assertEquals(order.getTotalPrice(), 470); | ||
| 230 | - assertEquals(order.getDiscountPrice(), 130); | ||
| 231 | - assertEquals(order.getPointPrice(), 0); | ||
| 232 | - assertEquals(order.getDeliveryPrice(), 0); | ||
| 233 | - assertEquals(order.getPayPrice(), 340); | ||
| 234 | - assertNull(order.getCouponId()); | ||
| 235 | - // 断言 OrderItem 部分 | ||
| 236 | - assertEquals(order.getItems().size(), 3); | ||
| 237 | - PriceCalculateRespDTO.OrderItem orderItem01 = order.getItems().get(0); | ||
| 238 | - assertEquals(orderItem01.getSkuId(), 10L); | ||
| 239 | - assertEquals(orderItem01.getCount(), 2); | ||
| 240 | - assertEquals(orderItem01.getOriginalPrice(), 200); | ||
| 241 | - assertEquals(orderItem01.getOriginalUnitPrice(), 100); | ||
| 242 | - assertEquals(orderItem01.getDiscountPrice(), 0); | ||
| 243 | - assertEquals(orderItem01.getPayPrice(), 200); | ||
| 244 | - assertEquals(orderItem01.getOrderPartPrice(), 40); | ||
| 245 | - assertEquals(orderItem01.getOrderDividePrice(), 160); | ||
| 246 | - PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1); | ||
| 247 | - assertEquals(orderItem02.getSkuId(), 20L); | ||
| 248 | - assertEquals(orderItem02.getCount(), 3); | ||
| 249 | - assertEquals(orderItem02.getOriginalPrice(), 150); | ||
| 250 | - assertEquals(orderItem02.getOriginalUnitPrice(), 50); | ||
| 251 | - assertEquals(orderItem02.getDiscountPrice(), 0); | ||
| 252 | - assertEquals(orderItem02.getPayPrice(), 150); | ||
| 253 | - assertEquals(orderItem02.getOrderPartPrice(), 30); | ||
| 254 | - assertEquals(orderItem02.getOrderDividePrice(), 120); | ||
| 255 | - PriceCalculateRespDTO.OrderItem orderItem03 = order.getItems().get(2); | ||
| 256 | - assertEquals(orderItem03.getSkuId(), 30L); | ||
| 257 | - assertEquals(orderItem03.getCount(), 4); | ||
| 258 | - assertEquals(orderItem03.getOriginalPrice(), 120); | ||
| 259 | - assertEquals(orderItem03.getOriginalUnitPrice(), 30); | ||
| 260 | - assertEquals(orderItem03.getDiscountPrice(), 0); | ||
| 261 | - assertEquals(orderItem03.getPayPrice(), 120); | ||
| 262 | - assertEquals(orderItem03.getOrderPartPrice(), 60); | ||
| 263 | - assertEquals(orderItem03.getOrderDividePrice(), 60); | ||
| 264 | - // 断言 Promotion 部分(第一个) | ||
| 265 | - assertEquals(priceCalculate.getPromotions().size(), 2); | ||
| 266 | - PriceCalculateRespDTO.Promotion promotion01 = priceCalculate.getPromotions().get(0); | ||
| 267 | - assertEquals(promotion01.getId(), 1000L); | ||
| 268 | - assertEquals(promotion01.getName(), "活动 1000 号"); | ||
| 269 | - assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); | ||
| 270 | - //assertEquals(promotion01.getLevel(), PromotionLevelEnum.ORDER.getLevel()); TODO PromotionLevelEnum 没有这个枚举类 | ||
| 271 | - assertEquals(promotion01.getTotalPrice(), 350); | ||
| 272 | - assertEquals(promotion01.getDiscountPrice(), 70); | ||
| 273 | - assertTrue(promotion01.getMatch()); | ||
| 274 | - assertEquals(promotion01.getDescription(), "满减送:省 0.70 元"); | ||
| 275 | - assertEquals(promotion01.getItems().size(), 2); | ||
| 276 | - PriceCalculateRespDTO.PromotionItem promotionItem011 = promotion01.getItems().get(0); | ||
| 277 | - assertEquals(promotionItem011.getSkuId(), 10L); | ||
| 278 | - assertEquals(promotionItem011.getOriginalPrice(), 200); | ||
| 279 | - assertEquals(promotionItem011.getDiscountPrice(), 40); | ||
| 280 | - PriceCalculateRespDTO.PromotionItem promotionItem012 = promotion01.getItems().get(1); | ||
| 281 | - assertEquals(promotionItem012.getSkuId(), 20L); | ||
| 282 | - assertEquals(promotionItem012.getOriginalPrice(), 150); | ||
| 283 | - assertEquals(promotionItem012.getDiscountPrice(), 30); | ||
| 284 | - // 断言 Promotion 部分(第二个) | ||
| 285 | - PriceCalculateRespDTO.Promotion promotion02 = priceCalculate.getPromotions().get(1); | ||
| 286 | - assertEquals(promotion02.getId(), 2000L); | ||
| 287 | - assertEquals(promotion02.getName(), "活动 2000 号"); | ||
| 288 | - assertEquals(promotion02.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); | ||
| 289 | - //assertEquals(promotion02.getLevel(), PromotionLevelEnum.ORDER.getLevel()); TODO PromotionLevelEnum 没有这个枚举类 | ||
| 290 | - assertEquals(promotion02.getTotalPrice(), 120); | ||
| 291 | - assertEquals(promotion02.getDiscountPrice(), 60); | ||
| 292 | - assertTrue(promotion02.getMatch()); | ||
| 293 | - assertEquals(promotion02.getDescription(), "满减送:省 0.60 元"); | ||
| 294 | - PriceCalculateRespDTO.PromotionItem promotionItem02 = promotion02.getItems().get(0); | ||
| 295 | - assertEquals(promotion02.getItems().size(), 1); | ||
| 296 | - assertEquals(promotionItem02.getSkuId(), 30L); | ||
| 297 | - assertEquals(promotionItem02.getOriginalPrice(), 120); | ||
| 298 | - assertEquals(promotionItem02.getDiscountPrice(), 60); | ||
| 299 | - } | ||
| 300 | - | ||
| 301 | /** | 48 | /** |
| 302 | * 测试满减送活动,不匹配的情况 | 49 | * 测试满减送活动,不匹配的情况 |
| 303 | */ | 50 | */ |
| 304 | @Test | 51 | @Test |
| 305 | public void testCalculatePrice_rewardActivityNotMeet() { | 52 | public void testCalculatePrice_rewardActivityNotMeet() { |
| 306 | - // 准备参数 | ||
| 307 | - PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(randomLongId()) | ||
| 308 | - .setItems(asList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2), | ||
| 309 | - new PriceCalculateReqDTO.Item().setSkuId(20L).setCount(3))); | ||
| 310 | - // mock 方法(商品 SKU 信息) | ||
| 311 | - ProductSkuRespDTO productSku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100).setSpuId(1L)); | ||
| 312 | - ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50).setSpuId(2L)); | ||
| 313 | - when(productSkuApi.getSkuList(eq(asSet(10L, 20L)))).thenReturn(asList(productSku01, productSku02)); | ||
| 314 | - // mock 方法(限时折扣 DiscountActivity 信息) | ||
| 315 | - RewardActivityDO rewardActivity01 = randomPojo(RewardActivityDO.class, o -> o.setId(1000L).setName("活动 1000 号") | ||
| 316 | - .setProductSpuIds(asList(10L, 20L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) | ||
| 317 | - .setRules(singletonList(new RewardActivityDO.Rule().setLimit(351).setDiscountPrice(70)))); | ||
| 318 | - Map<RewardActivityDO, Set<Long>> matchRewardActivities = new LinkedHashMap<>(); | ||
| 319 | - matchRewardActivities.put(rewardActivity01, asSet(1L, 2L)); | ||
| 320 | - //TODO getMatchRewardActivities 没有这个方法,但是找到了 getMatchRewardActivityList | ||
| 321 | - //when(rewardActivityService.getMatchRewardActivities(eq(asSet(1L, 2L)))).thenReturn(matchRewardActivities); | ||
| 322 | 53 | ||
| 323 | - // 调用 | ||
| 324 | - //PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); TODO 没有这个方法 | ||
| 325 | - PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO(); | ||
| 326 | - // 断言 Order 部分 | ||
| 327 | - PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); | ||
| 328 | - assertEquals(order.getTotalPrice(), 350); | ||
| 329 | - assertEquals(order.getDiscountPrice(), 0); | ||
| 330 | - assertEquals(order.getPointPrice(), 0); | ||
| 331 | - assertEquals(order.getDeliveryPrice(), 0); | ||
| 332 | - assertEquals(order.getPayPrice(), 350); | ||
| 333 | - assertNull(order.getCouponId()); | ||
| 334 | - // 断言 OrderItem 部分 | ||
| 335 | - assertEquals(order.getItems().size(), 2); | ||
| 336 | - PriceCalculateRespDTO.OrderItem orderItem01 = order.getItems().get(0); | ||
| 337 | - assertEquals(orderItem01.getSkuId(), 10L); | ||
| 338 | - assertEquals(orderItem01.getCount(), 2); | ||
| 339 | - assertEquals(orderItem01.getOriginalPrice(), 200); | ||
| 340 | - assertEquals(orderItem01.getOriginalUnitPrice(), 100); | ||
| 341 | - assertEquals(orderItem01.getDiscountPrice(), 0); | ||
| 342 | - assertEquals(orderItem01.getPayPrice(), 200); | ||
| 343 | - assertEquals(orderItem01.getOrderPartPrice(), 0); | ||
| 344 | - assertEquals(orderItem01.getOrderDividePrice(), 200); | ||
| 345 | - PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1); | ||
| 346 | - assertEquals(orderItem02.getSkuId(), 20L); | ||
| 347 | - assertEquals(orderItem02.getCount(), 3); | ||
| 348 | - assertEquals(orderItem02.getOriginalPrice(), 150); | ||
| 349 | - assertEquals(orderItem02.getOriginalUnitPrice(), 50); | ||
| 350 | - assertEquals(orderItem02.getDiscountPrice(), 0); | ||
| 351 | - assertEquals(orderItem02.getPayPrice(), 150); | ||
| 352 | - assertEquals(orderItem02.getOrderPartPrice(), 0); | ||
| 353 | - assertEquals(orderItem02.getOrderDividePrice(), 150); | ||
| 354 | - // 断言 Promotion 部分 | ||
| 355 | - assertEquals(priceCalculate.getPromotions().size(), 1); | ||
| 356 | - PriceCalculateRespDTO.Promotion promotion01 = priceCalculate.getPromotions().get(0); | ||
| 357 | - assertEquals(promotion01.getId(), 1000L); | ||
| 358 | - assertEquals(promotion01.getName(), "活动 1000 号"); | ||
| 359 | - assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); | ||
| 360 | - //assertEquals(promotion01.getLevel(), PromotionLevelEnum.ORDER.getLevel()); TODO PromotionLevelEnum 没有这个枚举类 | ||
| 361 | - assertEquals(promotion01.getTotalPrice(), 350); | ||
| 362 | - assertEquals(promotion01.getDiscountPrice(), 0); | ||
| 363 | - assertFalse(promotion01.getMatch()); | ||
| 364 | - assertEquals(promotion01.getDescription(), "TODO"); // TODO 芋艿:后面再想想 | ||
| 365 | - assertEquals(promotion01.getItems().size(), 2); | ||
| 366 | - PriceCalculateRespDTO.PromotionItem promotionItem011 = promotion01.getItems().get(0); | ||
| 367 | - assertEquals(promotionItem011.getSkuId(), 10L); | ||
| 368 | - assertEquals(promotionItem011.getOriginalPrice(), 200); | ||
| 369 | - assertEquals(promotionItem011.getDiscountPrice(), 0); | ||
| 370 | - PriceCalculateRespDTO.PromotionItem promotionItem012 = promotion01.getItems().get(1); | ||
| 371 | - assertEquals(promotionItem012.getSkuId(), 20L); | ||
| 372 | - assertEquals(promotionItem012.getOriginalPrice(), 150); | ||
| 373 | - assertEquals(promotionItem012.getDiscountPrice(), 0); | ||
| 374 | - } | ||
| 375 | - | ||
| 376 | - @Test | ||
| 377 | - public void testCalculatePrice_coupon() { | ||
| 378 | - // 准备参数 | ||
| 379 | - PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(randomLongId()) | ||
| 380 | - .setItems(asList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2), | ||
| 381 | - new PriceCalculateReqDTO.Item().setSkuId(20L).setCount(3), | ||
| 382 | - new PriceCalculateReqDTO.Item().setSkuId(30L).setCount(4))) | ||
| 383 | - .setCouponId(1024L); | ||
| 384 | - // mock 方法(商品 SKU 信息) | ||
| 385 | - ProductSkuRespDTO productSku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100).setSpuId(1L)); | ||
| 386 | - ProductSkuRespDTO productSku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(20L).setPrice(50).setSpuId(2L)); | ||
| 387 | - ProductSkuRespDTO productSku03 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(30L).setPrice(30).setSpuId(3L)); | ||
| 388 | - when(productSkuApi.getSkuList(eq(asSet(10L, 20L, 30L)))).thenReturn(asList(productSku01, productSku02, productSku03)); | ||
| 389 | - // mock 方法(优惠劵 Coupon 信息) | ||
| 390 | - CouponDO coupon = randomPojo(CouponDO.class, o -> o.setId(1024L).setName("程序员节") | ||
| 391 | - .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L)) | ||
| 392 | - .setUsePrice(350).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()) | ||
| 393 | - .setDiscountPercent(50).setDiscountLimitPrice(70)); | ||
| 394 | - when(couponService.validCoupon(eq(1024L), eq(calculateReqDTO.getUserId()))).thenReturn(coupon); | ||
| 395 | - | ||
| 396 | - // 调用 | ||
| 397 | - //PriceCalculateRespDTO priceCalculate = priceService.calculatePrice(calculateReqDTO); TODO 没有这个方法 | ||
| 398 | - PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO(); | ||
| 399 | - // 断言 Order 部分 | ||
| 400 | - PriceCalculateRespDTO.Order order = priceCalculate.getOrder(); | ||
| 401 | - assertEquals(order.getTotalPrice(), 470); | ||
| 402 | - assertEquals(order.getDiscountPrice(), 0); | ||
| 403 | - assertEquals(order.getPointPrice(), 0); | ||
| 404 | - assertEquals(order.getDeliveryPrice(), 0); | ||
| 405 | - assertEquals(order.getPayPrice(), 400); | ||
| 406 | - assertEquals(order.getCouponId(), 1024L); | ||
| 407 | - assertEquals(order.getCouponPrice(), 70); | ||
| 408 | - // 断言 OrderItem 部分 | ||
| 409 | - assertEquals(order.getItems().size(), 3); | ||
| 410 | - PriceCalculateRespDTO.OrderItem orderItem01 = order.getItems().get(0); | ||
| 411 | - assertEquals(orderItem01.getSkuId(), 10L); | ||
| 412 | - assertEquals(orderItem01.getCount(), 2); | ||
| 413 | - assertEquals(orderItem01.getOriginalPrice(), 200); | ||
| 414 | - assertEquals(orderItem01.getOriginalUnitPrice(), 100); | ||
| 415 | - assertEquals(orderItem01.getDiscountPrice(), 0); | ||
| 416 | - assertEquals(orderItem01.getPayPrice(), 200); | ||
| 417 | - assertEquals(orderItem01.getOrderPartPrice(), 40); | ||
| 418 | - assertEquals(orderItem01.getOrderDividePrice(), 160); | ||
| 419 | - PriceCalculateRespDTO.OrderItem orderItem02 = order.getItems().get(1); | ||
| 420 | - assertEquals(orderItem02.getSkuId(), 20L); | ||
| 421 | - assertEquals(orderItem02.getCount(), 3); | ||
| 422 | - assertEquals(orderItem02.getOriginalPrice(), 150); | ||
| 423 | - assertEquals(orderItem02.getOriginalUnitPrice(), 50); | ||
| 424 | - assertEquals(orderItem02.getDiscountPrice(), 0); | ||
| 425 | - assertEquals(orderItem02.getPayPrice(), 150); | ||
| 426 | - assertEquals(orderItem02.getOrderPartPrice(), 30); | ||
| 427 | - assertEquals(orderItem02.getOrderDividePrice(), 120); | ||
| 428 | - PriceCalculateRespDTO.OrderItem orderItem03 = order.getItems().get(2); | ||
| 429 | - assertEquals(orderItem03.getSkuId(), 30L); | ||
| 430 | - assertEquals(orderItem03.getCount(), 4); | ||
| 431 | - assertEquals(orderItem03.getOriginalPrice(), 120); | ||
| 432 | - assertEquals(orderItem03.getOriginalUnitPrice(), 30); | ||
| 433 | - assertEquals(orderItem03.getDiscountPrice(), 0); | ||
| 434 | - assertEquals(orderItem03.getPayPrice(), 120); | ||
| 435 | - assertEquals(orderItem03.getOrderPartPrice(), 0); | ||
| 436 | - assertEquals(orderItem03.getOrderDividePrice(), 120); | ||
| 437 | - // 断言 Promotion 部分 | ||
| 438 | - assertEquals(priceCalculate.getPromotions().size(), 1); | ||
| 439 | - PriceCalculateRespDTO.Promotion promotion01 = priceCalculate.getPromotions().get(0); | ||
| 440 | - assertEquals(promotion01.getId(), 1024L); | ||
| 441 | - assertEquals(promotion01.getName(), "程序员节"); | ||
| 442 | - assertEquals(promotion01.getType(), PromotionTypeEnum.COUPON.getType()); | ||
| 443 | - //assertEquals(promotion01.getLevel(), PromotionLevelEnum.COUPON.getLevel()); TODO PromotionLevelEnum 没有这个枚举类 | ||
| 444 | - assertEquals(promotion01.getTotalPrice(), 350); | ||
| 445 | - assertEquals(promotion01.getDiscountPrice(), 70); | ||
| 446 | - assertTrue(promotion01.getMatch()); | ||
| 447 | - assertEquals(promotion01.getDescription(), "优惠劵:省 0.70 元"); | ||
| 448 | - assertEquals(promotion01.getItems().size(), 2); | ||
| 449 | - PriceCalculateRespDTO.PromotionItem promotionItem011 = promotion01.getItems().get(0); | ||
| 450 | - assertEquals(promotionItem011.getSkuId(), 10L); | ||
| 451 | - assertEquals(promotionItem011.getOriginalPrice(), 200); | ||
| 452 | - assertEquals(promotionItem011.getDiscountPrice(), 40); | ||
| 453 | - PriceCalculateRespDTO.PromotionItem promotionItem012 = promotion01.getItems().get(1); | ||
| 454 | - assertEquals(promotionItem012.getSkuId(), 20L); | ||
| 455 | - assertEquals(promotionItem012.getOriginalPrice(), 150); | ||
| 456 | - assertEquals(promotionItem012.getDiscountPrice(), 30); | ||
| 457 | } | 54 | } |
| 458 | 55 | ||
| 459 | @Test | 56 | @Test |
yudao-module-mall/yudao-module-trade-api/src/main/java/cn/iocoder/yudao/module/trade/enums/delivery/DeliveryExpressChargeModeEnum.java
| 1 | package cn.iocoder.yudao.module.trade.enums.delivery; | 1 | package cn.iocoder.yudao.module.trade.enums.delivery; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.util.ArrayUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | 4 | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; |
| 4 | import lombok.AllArgsConstructor; | 5 | import lombok.AllArgsConstructor; |
| 5 | import lombok.Getter; | 6 | import lombok.Getter; |
| @@ -35,4 +36,8 @@ public enum DeliveryExpressChargeModeEnum implements IntArrayValuable { | @@ -35,4 +36,8 @@ public enum DeliveryExpressChargeModeEnum implements IntArrayValuable { | ||
| 35 | return ARRAYS; | 36 | return ARRAYS; |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 39 | + public static DeliveryExpressChargeModeEnum valueOf(Integer value) { | ||
| 40 | + return ArrayUtil.firstMatch(chargeMode -> chargeMode.getType().equals(value), DeliveryExpressChargeModeEnum.values()); | ||
| 41 | + } | ||
| 42 | + | ||
| 38 | } | 43 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java
| @@ -58,7 +58,7 @@ public class DeliveryExpressTemplateController { | @@ -58,7 +58,7 @@ public class DeliveryExpressTemplateController { | ||
| 58 | @Operation(summary = "获得快递运费模板") | 58 | @Operation(summary = "获得快递运费模板") |
| 59 | @Parameter(name = "id", description = "编号", required = true, example = "1024") | 59 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 60 | @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')") | 60 | @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')") |
| 61 | - public CommonResult<DeliveryExpressTemplateRespVO> getDeliveryExpressTemplate(@RequestParam("id") Long id) { | 61 | + public CommonResult<DeliveryExpressTemplateDetailRespVO> getDeliveryExpressTemplate(@RequestParam("id") Long id) { |
| 62 | return success(deliveryExpressTemplateService.getDeliveryExpressTemplate(id)); | 62 | return success(deliveryExpressTemplateService.getDeliveryExpressTemplate(id)); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| @@ -66,7 +66,7 @@ public class DeliveryExpressTemplateController { | @@ -66,7 +66,7 @@ public class DeliveryExpressTemplateController { | ||
| 66 | @Operation(summary = "获得快递运费模板列表") | 66 | @Operation(summary = "获得快递运费模板列表") |
| 67 | @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") | 67 | @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") |
| 68 | @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')") | 68 | @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')") |
| 69 | - public CommonResult<List<DeliveryExpressTemplateSimpleRespVO>> getDeliveryExpressTemplateList(@RequestParam("ids") Collection<Long> ids) { | 69 | + public CommonResult<List<DeliveryExpressTemplateRespVO>> getDeliveryExpressTemplateList(@RequestParam("ids") Collection<Long> ids) { |
| 70 | List<DeliveryExpressTemplateDO> list = deliveryExpressTemplateService.getDeliveryExpressTemplateList(ids); | 70 | List<DeliveryExpressTemplateDO> list = deliveryExpressTemplateService.getDeliveryExpressTemplateList(ids); |
| 71 | return success(DeliveryExpressTemplateConvert.INSTANCE.convertList(list)); | 71 | return success(DeliveryExpressTemplateConvert.INSTANCE.convertList(list)); |
| 72 | } | 72 | } |
| @@ -83,7 +83,7 @@ public class DeliveryExpressTemplateController { | @@ -83,7 +83,7 @@ public class DeliveryExpressTemplateController { | ||
| 83 | @GetMapping("/page") | 83 | @GetMapping("/page") |
| 84 | @Operation(summary = "获得快递运费模板分页") | 84 | @Operation(summary = "获得快递运费模板分页") |
| 85 | @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')") | 85 | @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')") |
| 86 | - public CommonResult<PageResult<DeliveryExpressTemplateSimpleRespVO>> getDeliveryExpressTemplatePage(@Valid DeliveryExpressTemplatePageReqVO pageVO) { | 86 | + public CommonResult<PageResult<DeliveryExpressTemplateRespVO>> getDeliveryExpressTemplatePage(@Valid DeliveryExpressTemplatePageReqVO pageVO) { |
| 87 | PageResult<DeliveryExpressTemplateDO> pageResult = deliveryExpressTemplateService.getDeliveryExpressTemplatePage(pageVO); | 87 | PageResult<DeliveryExpressTemplateDO> pageResult = deliveryExpressTemplateService.getDeliveryExpressTemplatePage(pageVO); |
| 88 | return success(DeliveryExpressTemplateConvert.INSTANCE.convertPage(pageResult)); | 88 | return success(DeliveryExpressTemplateConvert.INSTANCE.convertPage(pageResult)); |
| 89 | } | 89 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateDetailRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import lombok.Data; | ||
| 5 | +import lombok.EqualsAndHashCode; | ||
| 6 | +import lombok.ToString; | ||
| 7 | + | ||
| 8 | +import java.util.List; | ||
| 9 | + | ||
| 10 | +@Schema(description = "管理后台 - 快递运费模板的详细 Response VO") | ||
| 11 | +@Data | ||
| 12 | +@EqualsAndHashCode(callSuper = true) | ||
| 13 | +@ToString(callSuper = true) | ||
| 14 | +public class DeliveryExpressTemplateDetailRespVO extends DeliveryExpressTemplateBaseVO { | ||
| 15 | + | ||
| 16 | + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "371") | ||
| 17 | + private Long id; | ||
| 18 | + | ||
| 19 | + @Schema(description = "运费模板运费设置", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 20 | + private List<ExpressTemplateChargeBaseVO> templateCharge; | ||
| 21 | + | ||
| 22 | + @Schema(description = "运费模板包邮区域", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 23 | + private List<ExpressTemplateFreeBaseVO> templateFree; | ||
| 24 | + | ||
| 25 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateRespVO.java
| 1 | package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; | 1 | package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; |
| 2 | 2 | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import lombok.Data; | ||
| 5 | -import lombok.EqualsAndHashCode; | ||
| 6 | -import lombok.ToString; | 4 | +import lombok.*; |
| 5 | +import java.time.LocalDateTime; | ||
| 7 | 6 | ||
| 8 | -import java.util.List; | ||
| 9 | - | ||
| 10 | -/** | ||
| 11 | - * @author jason | ||
| 12 | - */ | ||
| 13 | @Schema(description = "管理后台 - 快递运费模板 Response VO") | 7 | @Schema(description = "管理后台 - 快递运费模板 Response VO") |
| 14 | @Data | 8 | @Data |
| 15 | @EqualsAndHashCode(callSuper = true) | 9 | @EqualsAndHashCode(callSuper = true) |
| 16 | @ToString(callSuper = true) | 10 | @ToString(callSuper = true) |
| 17 | public class DeliveryExpressTemplateRespVO extends DeliveryExpressTemplateBaseVO { | 11 | public class DeliveryExpressTemplateRespVO extends DeliveryExpressTemplateBaseVO { |
| 18 | 12 | ||
| 19 | - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "371") | 13 | + @Schema(description = "编号,自增", required = true, example = "371") |
| 20 | private Long id; | 14 | private Long id; |
| 21 | 15 | ||
| 22 | - @Schema(description = "运费模板运费设置", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 23 | - private List<ExpressTemplateChargeBaseVO> templateCharge; | ||
| 24 | - | ||
| 25 | - @Schema(description = "运费模板包邮区域", requiredMode = Schema.RequiredMode.REQUIRED) | ||
| 26 | - private List<ExpressTemplateFreeBaseVO> templateFree; | 16 | + @Schema(description = "创建时间", required = true) |
| 17 | + private LocalDateTime createTime; | ||
| 27 | 18 | ||
| 28 | } | 19 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java deleted
| 1 | -package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate; | ||
| 2 | - | ||
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | -import lombok.*; | ||
| 5 | -import java.time.LocalDateTime; | ||
| 6 | - | ||
| 7 | -// TODO @jason:simplae 是不是不用继承 DeliveryExpressTemplateBaseVO,直接 id name 属性就够了。 | ||
| 8 | -// @芋艿 这里给列表显示用的。 需要显示计费方式和排序, 所以继承 DeliveryExpressTemplateBaseVO。 这是去掉了包邮区域和 区域运费列表 | ||
| 9 | -@Schema(description = "管理后台 - 快递运费模板 精简 Response VO") | ||
| 10 | -@Data | ||
| 11 | -@EqualsAndHashCode(callSuper = true) | ||
| 12 | -@ToString(callSuper = true) | ||
| 13 | -public class DeliveryExpressTemplateSimpleRespVO extends DeliveryExpressTemplateBaseVO { | ||
| 14 | - | ||
| 15 | - @Schema(description = "编号,自增", required = true, example = "371") | ||
| 16 | - private Long id; | ||
| 17 | - | ||
| 18 | - @Schema(description = "创建时间", required = true) | ||
| 19 | - private LocalDateTime createTime; | ||
| 20 | - | ||
| 21 | -} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.http
| 1 | -### /trade-order/settlement 获得订单结算信息 | ||
| 2 | -GET {{appApi}}/trade/order/settlement?cartIds=1 | 1 | +### /trade-order/settlement 获得订单结算信息(基于商品) |
| 2 | +GET {{appApi}}/trade/order/settlement?type=0&items[0].skuId=1&items[0].count=2&items[1].skuId=2&items[1].count=3&couponId=1 | ||
| 3 | Authorization: Bearer {{appToken}} | 3 | Authorization: Bearer {{appToken}} |
| 4 | tenant-id: {{appTenentId}} | 4 | tenant-id: {{appTenentId}} |
| 5 | 5 | ||
| 6 | -### /trade-order/confirm-create-order-info-from-cart 基于购物车,确认创建订单 | ||
| 7 | -GET {{shop-api-base-url}}/trade-order/confirm-create-order-info-from-cart | ||
| 8 | -Content-Type: application/x-www-form-urlencoded | ||
| 9 | -Authorization: Bearer {{user-access-token}} | 6 | +### /trade-order/settlement 获得订单结算信息(基于购物车) |
| 7 | +GET {{appApi}}/trade/order/settlement?type=0&items[0].cartId=50&couponId=1 | ||
| 8 | +Authorization: Bearer {{appToken}} | ||
| 9 | +tenant-id: {{appTenentId}} | ||
| 10 | 10 | ||
| 11 | -### /trade-order/create 基于商品,创建订单 | 11 | +### /trade-order/create 创建订单(基于商品) |
| 12 | POST {{appApi}}/trade/order/create | 12 | POST {{appApi}}/trade/order/create |
| 13 | Content-Type: application/json | 13 | Content-Type: application/json |
| 14 | Authorization: Bearer {{appToken}} | 14 | Authorization: Bearer {{appToken}} |
| 15 | tenant-id: {{appTenentId}} | 15 | tenant-id: {{appTenentId}} |
| 16 | 16 | ||
| 17 | { | 17 | { |
| 18 | + "type": 0, | ||
| 18 | "addressId": 21, | 19 | "addressId": 21, |
| 19 | - "remark": "我是备注", | ||
| 20 | - "fromCart": false, | ||
| 21 | "items": [ | 20 | "items": [ |
| 22 | { | 21 | { |
| 23 | - "skuId": 29, | ||
| 24 | - "count": 1 | 22 | + "skuId": 1, |
| 23 | + "count": 2 | ||
| 25 | } | 24 | } |
| 26 | - ] | 25 | + ], |
| 26 | + "remark": "我是备注" | ||
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | ### 获得订单交易的分页 | 29 | ### 获得订单交易的分页 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/AppTradeOrderController.java
| @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | @@ -6,7 +6,6 @@ import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated; | ||
| 6 | import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; | 6 | import cn.iocoder.yudao.module.pay.api.notify.dto.PayOrderNotifyReqDTO; |
| 7 | import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi; | 7 | import cn.iocoder.yudao.module.product.api.property.ProductPropertyValueApi; |
| 8 | import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; | 8 | import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; |
| 9 | -import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; | ||
| 10 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; | 9 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; |
| 11 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; | 10 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; |
| 12 | import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; | 11 | import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; |
| @@ -23,15 +22,14 @@ import org.springframework.validation.annotation.Validated; | @@ -23,15 +22,14 @@ import org.springframework.validation.annotation.Validated; | ||
| 23 | import org.springframework.web.bind.annotation.*; | 22 | import org.springframework.web.bind.annotation.*; |
| 24 | 23 | ||
| 25 | import javax.annotation.Resource; | 24 | import javax.annotation.Resource; |
| 26 | -import javax.servlet.http.HttpServletRequest; | ||
| 27 | import javax.validation.Valid; | 25 | import javax.validation.Valid; |
| 28 | -import java.util.ArrayList; | ||
| 29 | import java.util.HashMap; | 26 | import java.util.HashMap; |
| 30 | import java.util.List; | 27 | import java.util.List; |
| 31 | import java.util.Map; | 28 | import java.util.Map; |
| 32 | 29 | ||
| 33 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | 30 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 34 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 31 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 32 | +import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; | ||
| 35 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | 33 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 36 | 34 | ||
| 37 | @Tag(name = "用户 App - 交易订单") | 35 | @Tag(name = "用户 App - 交易订单") |
| @@ -53,92 +51,16 @@ public class AppTradeOrderController { | @@ -53,92 +51,16 @@ public class AppTradeOrderController { | ||
| 53 | @GetMapping("/settlement") | 51 | @GetMapping("/settlement") |
| 54 | @Operation(summary = "获得订单结算信息") | 52 | @Operation(summary = "获得订单结算信息") |
| 55 | @PreAuthenticated | 53 | @PreAuthenticated |
| 56 | - public CommonResult<AppTradeOrderSettlementRespVO> settlementOrder( | ||
| 57 | - @Valid AppTradeOrderSettlementReqVO settlementReqVO) { | ||
| 58 | - if (true) { | ||
| 59 | - return success(tradeOrderService.settlementOrder(getLoginUserId(), settlementReqVO)); | ||
| 60 | - } | ||
| 61 | -// return success(tradeOrderService.getOrderConfirmCreateInfo(UserSecurityContextHolder.getUserId(), skuId, quantity, couponCardId)); | ||
| 62 | - AppTradeOrderSettlementRespVO settlement = new AppTradeOrderSettlementRespVO(); | ||
| 63 | - | ||
| 64 | - AppTradeOrderSettlementRespVO.Price price = new AppTradeOrderSettlementRespVO.Price(); | ||
| 65 | - price.setTotalPrice(1000); | ||
| 66 | - price.setDeliveryPrice(200); | ||
| 67 | - price.setCouponPrice(100); | ||
| 68 | - price.setPointPrice(50); | ||
| 69 | - price.setPayPrice(950); | ||
| 70 | - | ||
| 71 | - List<AppTradeOrderSettlementRespVO.Item> skus = new ArrayList<>(); | ||
| 72 | - | ||
| 73 | - AppTradeOrderSettlementRespVO.Item item1 = new AppTradeOrderSettlementRespVO.Item(); | ||
| 74 | - item1.setCartId(1L); | ||
| 75 | - item1.setSpuId(2048L); | ||
| 76 | - item1.setSpuName("Apple iPhone 12"); | ||
| 77 | - item1.setSkuId(1024); | ||
| 78 | - item1.setPrice(500); | ||
| 79 | - item1.setPicUrl("https://pro.crmeb.net/uploads/attach/2022/10/12/0c56f9abb80d2775fc1e80dbe4f8826a.jpg"); | ||
| 80 | - item1.setCount(2); | ||
| 81 | - List<AppProductPropertyValueDetailRespVO> properties1 = new ArrayList<>(); | ||
| 82 | - AppProductPropertyValueDetailRespVO property1 = new AppProductPropertyValueDetailRespVO(); | ||
| 83 | - property1.setPropertyId(1L); | ||
| 84 | - property1.setPropertyName("尺寸"); | ||
| 85 | - property1.setValueId(2L); | ||
| 86 | - property1.setValueName("大"); | ||
| 87 | - properties1.add(property1); | ||
| 88 | - item1.setProperties(properties1); | ||
| 89 | - | ||
| 90 | - AppTradeOrderSettlementRespVO.Item item2 = new AppTradeOrderSettlementRespVO.Item(); | ||
| 91 | - item2.setCartId(2L); | ||
| 92 | - item2.setSpuId(3072L); | ||
| 93 | - item2.setSpuName("Samsung Galaxy S21"); | ||
| 94 | - item2.setSkuId(2048); | ||
| 95 | - item2.setPrice(800); | ||
| 96 | - item2.setPicUrl("https://pro.crmeb.net/uploads/attach/2022/10/12/0c56f9abb80d2775fc1e80dbe4f8826a.jpg"); | ||
| 97 | - item2.setCount(1); | ||
| 98 | - List<AppProductPropertyValueDetailRespVO> properties2 = new ArrayList<>(); | ||
| 99 | - AppProductPropertyValueDetailRespVO property2 = new AppProductPropertyValueDetailRespVO(); | ||
| 100 | - property2.setPropertyId(10L); | ||
| 101 | - property2.setPropertyName("颜色"); | ||
| 102 | - property2.setValueId(20L); | ||
| 103 | - property2.setValueName("白色"); | ||
| 104 | - properties2.add(property2); | ||
| 105 | - item2.setProperties(properties2); | ||
| 106 | - | ||
| 107 | - skus.add(item1); | ||
| 108 | - skus.add(item2); | ||
| 109 | - | ||
| 110 | - settlement.setItems(skus); | ||
| 111 | - settlement.setPrice(price); | ||
| 112 | - | ||
| 113 | - AppTradeOrderSettlementRespVO.Address address = new AppTradeOrderSettlementRespVO.Address(); | ||
| 114 | - address.setId(1L); | ||
| 115 | - address.setName("John"); | ||
| 116 | - address.setMobile("18888888888"); | ||
| 117 | - address.setProvinceId(1L); | ||
| 118 | - address.setProvinceName("Beijing"); | ||
| 119 | - address.setCityId(1L); | ||
| 120 | - address.setCityName("Beijing"); | ||
| 121 | - address.setDistrictId(1L); | ||
| 122 | - address.setDistrictName("Chaoyang Distripct"); | ||
| 123 | - address.setDetailAddress("No. 10, Xinzhong Street, Chaoyang District"); | ||
| 124 | - address.setDefaulted(true); | ||
| 125 | - settlement.setAddress(address); | ||
| 126 | - | ||
| 127 | - return success(settlement); | 54 | + public CommonResult<AppTradeOrderSettlementRespVO> settlementOrder(@Valid AppTradeOrderSettlementReqVO settlementReqVO) { |
| 55 | + return success(tradeOrderService.settlementOrder(getLoginUserId(), settlementReqVO)); | ||
| 128 | } | 56 | } |
| 129 | 57 | ||
| 130 | @PostMapping("/create") | 58 | @PostMapping("/create") |
| 131 | @Operation(summary = "创建订单") | 59 | @Operation(summary = "创建订单") |
| 132 | @PreAuthenticated | 60 | @PreAuthenticated |
| 133 | - public CommonResult<Long> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO, | ||
| 134 | - HttpServletRequest servletRequest) { | ||
| 135 | - return success(1L); | ||
| 136 | -// // 获取登录用户、用户 IP 地址 | ||
| 137 | -// Long loginUserId = getLoginUserId(); | ||
| 138 | -// String clientIp = ServletUtils.getClientIP(servletRequest); | ||
| 139 | -// // 创建交易订单,预支付记录 | ||
| 140 | -// Long orderId = tradeOrderService.createOrder(loginUserId, clientIp, createReqVO); | ||
| 141 | -// return success(orderId); | 61 | + public CommonResult<Long> createOrder(@RequestBody AppTradeOrderCreateReqVO createReqVO) { |
| 62 | + Long orderId = tradeOrderService.createOrder(getLoginUserId(), getClientIP(), createReqVO); | ||
| 63 | + return success(orderId); | ||
| 142 | } | 64 | } |
| 143 | 65 | ||
| 144 | @PostMapping("/update-paid") | 66 | @PostMapping("/update-paid") |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderCreateReqVO.java
| @@ -3,26 +3,9 @@ package cn.iocoder.yudao.module.trade.controller.app.order.vo; | @@ -3,26 +3,9 @@ package cn.iocoder.yudao.module.trade.controller.app.order.vo; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import lombok.Data; | 4 | import lombok.Data; |
| 5 | 5 | ||
| 6 | -import javax.validation.constraints.NotEmpty; | ||
| 7 | -import javax.validation.constraints.NotNull; | ||
| 8 | -import java.util.List; | ||
| 9 | - | ||
| 10 | @Schema(description = "用户 App - 交易订单创建 Request VO") | 6 | @Schema(description = "用户 App - 交易订单创建 Request VO") |
| 11 | @Data | 7 | @Data |
| 12 | -public class AppTradeOrderCreateReqVO { | ||
| 13 | - | ||
| 14 | - @Schema(description = "收件地址编号", required = true, example = "1") | ||
| 15 | - @NotNull(message = "收件地址不能为空") | ||
| 16 | - private Long addressId; | ||
| 17 | - | ||
| 18 | - @Schema(description = "优惠劵编号", example = "1024") | ||
| 19 | - private Long couponId; | ||
| 20 | - | ||
| 21 | - @Schema(description = "购物车项的编号数组", required = true, example = "true") | ||
| 22 | - @NotEmpty(message = "购物车项不能为空") | ||
| 23 | - private List<Long> cartIds; | ||
| 24 | - | ||
| 25 | - // ========== 非 AppTradeOrderSettlementReqVO 字段 ========== | 8 | +public class AppTradeOrderCreateReqVO extends AppTradeOrderSettlementReqVO { |
| 26 | 9 | ||
| 27 | @Schema(description = "备注", example = "这个是我的订单哟") | 10 | @Schema(description = "备注", example = "这个是我的订单哟") |
| 28 | private String remark; | 11 | private String remark; |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementReqVO.java
| 1 | package cn.iocoder.yudao.module.trade.controller.app.order.vo; | 1 | package cn.iocoder.yudao.module.trade.controller.app.order.vo; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | ||
| 4 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | ||
| 5 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import lombok.Data; | 7 | import lombok.Data; |
| 5 | 8 | ||
| 6 | -import javax.validation.constraints.NotEmpty; | 9 | +import javax.validation.Valid; |
| 10 | +import javax.validation.constraints.AssertTrue; | ||
| 11 | +import javax.validation.constraints.Min; | ||
| 12 | +import javax.validation.constraints.NotNull; | ||
| 7 | import java.util.List; | 13 | import java.util.List; |
| 8 | 14 | ||
| 9 | @Schema(description = "用户 App - 交易订单结算 Request VO") | 15 | @Schema(description = "用户 App - 交易订单结算 Request VO") |
| 10 | @Data | 16 | @Data |
| 11 | public class AppTradeOrderSettlementReqVO { | 17 | public class AppTradeOrderSettlementReqVO { |
| 12 | 18 | ||
| 19 | + @NotNull(message = "交易类型不能为空") | ||
| 20 | + @InEnum(value = TradeOrderTypeEnum.class, message = "交易类型必须是 {value}") | ||
| 21 | + private Integer type; | ||
| 22 | + | ||
| 23 | + @Schema(description = "商品项数组", required = true) | ||
| 24 | + @NotNull(message = "商品不能为空") | ||
| 25 | + private List<Item> items; | ||
| 26 | + | ||
| 13 | @Schema(description = "收件地址编号", example = "1") | 27 | @Schema(description = "收件地址编号", example = "1") |
| 14 | private Long addressId; | 28 | private Long addressId; |
| 15 | 29 | ||
| 16 | @Schema(description = "优惠劵编号", example = "1024") | 30 | @Schema(description = "优惠劵编号", example = "1024") |
| 17 | private Long couponId; | 31 | private Long couponId; |
| 18 | 32 | ||
| 19 | - @Schema(description = "购物车项的编号数组", required = true, example = "true") | ||
| 20 | - @NotEmpty(message = "购物车项不能为空") | ||
| 21 | - private List<Long> cartIds; | 33 | + @Data |
| 34 | + @Schema(description = "用户 App - 商品项") | ||
| 35 | + @Valid | ||
| 36 | + public static class Item { | ||
| 37 | + | ||
| 38 | + @Schema(description = "商品 SKU 编号", example = "2048") | ||
| 39 | + private Long skuId; | ||
| 40 | + @Schema(description = "购买数量", example = "1") | ||
| 41 | + @Min(value = 1, message = "购买数量最小值为 {value}") | ||
| 42 | + private Integer count; | ||
| 43 | + | ||
| 44 | + @Schema(description = "购物车项的编号", example = "1024") | ||
| 45 | + private Long cartId; | ||
| 46 | + | ||
| 47 | + @AssertTrue(message = "商品不正确") | ||
| 48 | + @JsonIgnore | ||
| 49 | + public boolean isValid() { | ||
| 50 | + // 组合一:skuId + count 使用商品 SKU | ||
| 51 | + if (skuId != null && count != null) { | ||
| 52 | + return true; | ||
| 53 | + } | ||
| 54 | + // 组合二:cartId 使用购物车项 | ||
| 55 | + return cartId != null; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + } | ||
| 22 | 59 | ||
| 23 | } | 60 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/app/order/vo/AppTradeOrderSettlementRespVO.java
| @@ -91,17 +91,17 @@ public class AppTradeOrderSettlementRespVO { | @@ -91,17 +91,17 @@ public class AppTradeOrderSettlementRespVO { | ||
| 91 | private String mobile; | 91 | private String mobile; |
| 92 | 92 | ||
| 93 | @Schema(description = "省份编号", required = true, example = "1") | 93 | @Schema(description = "省份编号", required = true, example = "1") |
| 94 | - private Long provinceId; | 94 | + private Integer provinceId; |
| 95 | @Schema(description = "省份名字", required = true, example = "北京") | 95 | @Schema(description = "省份名字", required = true, example = "北京") |
| 96 | private String provinceName; | 96 | private String provinceName; |
| 97 | 97 | ||
| 98 | @Schema(description = "城市编号", required = true, example = "1") | 98 | @Schema(description = "城市编号", required = true, example = "1") |
| 99 | - private Long cityId; | 99 | + private Integer cityId; |
| 100 | @Schema(description = "城市名字", required = true, example = "北京") | 100 | @Schema(description = "城市名字", required = true, example = "北京") |
| 101 | private String cityName; | 101 | private String cityName; |
| 102 | 102 | ||
| 103 | @Schema(description = "地区编号", required = true, example = "1") | 103 | @Schema(description = "地区编号", required = true, example = "1") |
| 104 | - private Long districtId; | 104 | + private Integer districtId; |
| 105 | @Schema(description = "地区名字", required = true, example = "朝阳区") | 105 | @Schema(description = "地区名字", required = true, example = "朝阳区") |
| 106 | private String districtName; | 106 | private String districtName; |
| 107 | 107 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/delivery/DeliveryExpressTemplateConvert.java
| @@ -22,18 +22,18 @@ public interface DeliveryExpressTemplateConvert { | @@ -22,18 +22,18 @@ public interface DeliveryExpressTemplateConvert { | ||
| 22 | 22 | ||
| 23 | DeliveryExpressTemplateDO convert(DeliveryExpressTemplateUpdateReqVO bean); | 23 | DeliveryExpressTemplateDO convert(DeliveryExpressTemplateUpdateReqVO bean); |
| 24 | 24 | ||
| 25 | - DeliveryExpressTemplateSimpleRespVO convert(DeliveryExpressTemplateDO bean); | 25 | + DeliveryExpressTemplateRespVO convert(DeliveryExpressTemplateDO bean); |
| 26 | 26 | ||
| 27 | - DeliveryExpressTemplateRespVO convert2(DeliveryExpressTemplateDO bean); | 27 | + DeliveryExpressTemplateDetailRespVO convert2(DeliveryExpressTemplateDO bean); |
| 28 | 28 | ||
| 29 | - List<DeliveryExpressTemplateSimpleRespVO> convertList(List<DeliveryExpressTemplateDO> list); | 29 | + List<DeliveryExpressTemplateRespVO> convertList(List<DeliveryExpressTemplateDO> list); |
| 30 | 30 | ||
| 31 | - PageResult<DeliveryExpressTemplateSimpleRespVO> convertPage(PageResult<DeliveryExpressTemplateDO> page); | 31 | + PageResult<DeliveryExpressTemplateRespVO> convertPage(PageResult<DeliveryExpressTemplateDO> page); |
| 32 | 32 | ||
| 33 | - default DeliveryExpressTemplateRespVO convert(DeliveryExpressTemplateDO bean, | ||
| 34 | - List<DeliveryExpressTemplateChargeDO> chargeList, | ||
| 35 | - List<DeliveryExpressTemplateFreeDO> freeList){ | ||
| 36 | - DeliveryExpressTemplateRespVO respVO = convert2(bean); | 33 | + default DeliveryExpressTemplateDetailRespVO convert(DeliveryExpressTemplateDO bean, |
| 34 | + List<DeliveryExpressTemplateChargeDO> chargeList, | ||
| 35 | + List<DeliveryExpressTemplateFreeDO> freeList){ | ||
| 36 | + DeliveryExpressTemplateDetailRespVO respVO = convert2(bean); | ||
| 37 | respVO.setTemplateCharge(convertTemplateChargeList(chargeList)); | 37 | respVO.setTemplateCharge(convertTemplateChargeList(chargeList)); |
| 38 | respVO.setTemplateFree(convertTemplateFreeList(freeList)); | 38 | respVO.setTemplateFree(convertTemplateFreeList(freeList)); |
| 39 | return respVO; | 39 | return respVO; |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/convert/order/TradeOrderConvert.java
| @@ -3,29 +3,28 @@ package cn.iocoder.yudao.module.trade.convert.order; | @@ -3,29 +3,28 @@ package cn.iocoder.yudao.module.trade.convert.order; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 5 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 6 | +import cn.iocoder.yudao.framework.ip.core.Area; | ||
| 6 | import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; | 7 | import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils; |
| 7 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | 8 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; |
| 8 | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; | 9 | import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; |
| 9 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; | 10 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; |
| 10 | import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; | 11 | import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; |
| 11 | -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 12 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; | 12 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; |
| 13 | -import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | ||
| 14 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; | 13 | import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO; |
| 15 | -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | ||
| 16 | import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; | 14 | import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO; |
| 17 | import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; | 15 | import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO; |
| 18 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO; | 16 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDetailRespVO; |
| 19 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageItemRespVO; | 17 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageItemRespVO; |
| 20 | import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; | 18 | import cn.iocoder.yudao.module.trade.controller.app.base.property.AppProductPropertyValueDetailRespVO; |
| 21 | -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; | ||
| 22 | -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderDetailRespVO; | ||
| 23 | -import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageItemRespVO; | 19 | +import cn.iocoder.yudao.module.trade.controller.app.order.vo.*; |
| 24 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; | 20 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.item.AppTradeOrderItemRespVO; |
| 21 | +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; | ||
| 25 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | 22 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| 26 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; | 23 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; |
| 27 | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; | 24 | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderItemAfterSaleStatusEnum; |
| 28 | import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; | 25 | import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; |
| 26 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||
| 27 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||
| 29 | import org.mapstruct.Mapper; | 28 | import org.mapstruct.Mapper; |
| 30 | import org.mapstruct.Mapping; | 29 | import org.mapstruct.Mapping; |
| 31 | import org.mapstruct.Mappings; | 30 | import org.mapstruct.Mappings; |
| @@ -48,32 +47,32 @@ public interface TradeOrderConvert { | @@ -48,32 +47,32 @@ public interface TradeOrderConvert { | ||
| 48 | @Mapping(source = "createReqVO.couponId", target = "couponId"), | 47 | @Mapping(source = "createReqVO.couponId", target = "couponId"), |
| 49 | @Mapping(target = "remark", ignore = true), | 48 | @Mapping(target = "remark", ignore = true), |
| 50 | @Mapping(source = "createReqVO.remark", target = "userRemark"), | 49 | @Mapping(source = "createReqVO.remark", target = "userRemark"), |
| 50 | + @Mapping(source = "createReqVO.type", target = "type"), | ||
| 51 | + @Mapping(source = "calculateRespBO.price.totalPrice", target = "totalPrice"), | ||
| 52 | + @Mapping(source = "calculateRespBO.price.discountPrice", target = "discountPrice"), | ||
| 53 | + @Mapping(source = "calculateRespBO.price.deliveryPrice", target = "deliveryPrice"), | ||
| 54 | + @Mapping(source = "calculateRespBO.price.couponPrice", target = "couponPrice"), | ||
| 55 | + @Mapping(source = "calculateRespBO.price.pointPrice", target = "pointPrice"), | ||
| 56 | + @Mapping(source = "calculateRespBO.price.payPrice", target = "payPrice"), | ||
| 51 | @Mapping(source = "address.name", target = "receiverName"), | 57 | @Mapping(source = "address.name", target = "receiverName"), |
| 52 | @Mapping(source = "address.mobile", target = "receiverMobile"), | 58 | @Mapping(source = "address.mobile", target = "receiverMobile"), |
| 53 | @Mapping(source = "address.areaId", target = "receiverAreaId"), | 59 | @Mapping(source = "address.areaId", target = "receiverAreaId"), |
| 54 | @Mapping(source = "address.detailAddress", target = "receiverDetailAddress"), | 60 | @Mapping(source = "address.detailAddress", target = "receiverDetailAddress"), |
| 55 | }) | 61 | }) |
| 56 | TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO, | 62 | TradeOrderDO convert(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO, |
| 57 | - PriceCalculateRespDTO.Order order, AddressRespDTO address); | 63 | + TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address); |
| 58 | 64 | ||
| 59 | - @Mappings({ | ||
| 60 | - @Mapping(target = "id", ignore = true), | ||
| 61 | - @Mapping(source = "sku.spuId", target = "spuId"), | ||
| 62 | - }) | ||
| 63 | - TradeOrderItemDO convert(PriceCalculateRespDTO.OrderItem orderItem, ProductSkuRespDTO sku); | ||
| 64 | - | ||
| 65 | - default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrderDO, | ||
| 66 | - List<PriceCalculateRespDTO.OrderItem> orderItems, List<ProductSkuRespDTO> skus) { | ||
| 67 | - Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId); | ||
| 68 | - return CollectionUtils.convertList(orderItems, orderItem -> { | ||
| 69 | - TradeOrderItemDO tradeOrderItemDO = convert(orderItem, skuMap.get(orderItem.getSkuId())); | ||
| 70 | - tradeOrderItemDO.setOrderId(tradeOrderDO.getId()); | ||
| 71 | - tradeOrderItemDO.setUserId(tradeOrderDO.getUserId()); | ||
| 72 | - tradeOrderItemDO.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); // 退款信息 | ||
| 73 | -// tradeOrderItemDO.setCommented(false); | ||
| 74 | - return tradeOrderItemDO; | 65 | + default List<TradeOrderItemDO> convertList(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) { |
| 66 | + return CollectionUtils.convertList(calculateRespBO.getItems(), item -> { | ||
| 67 | + TradeOrderItemDO orderItem = convert(item); | ||
| 68 | + orderItem.setOrderId(tradeOrderDO.getId()); | ||
| 69 | + orderItem.setUserId(tradeOrderDO.getUserId()); | ||
| 70 | + orderItem.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); | ||
| 71 | + orderItem.setCommentStatus(false); | ||
| 72 | + return orderItem; | ||
| 75 | }); | 73 | }); |
| 76 | } | 74 | } |
| 75 | + TradeOrderItemDO convert(TradePriceCalculateRespBO.OrderItem item); | ||
| 77 | 76 | ||
| 78 | @Mapping(source = "userId" , target = "userId") | 77 | @Mapping(source = "userId" , target = "userId") |
| 79 | PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId); | 78 | PriceCalculateReqDTO convert(AppTradeOrderCreateReqVO createReqVO, Long userId); |
| @@ -85,19 +84,20 @@ public interface TradeOrderConvert { | @@ -85,19 +84,20 @@ public interface TradeOrderConvert { | ||
| 85 | ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean); | 84 | ProductSkuUpdateStockReqDTO.Item convert(TradeOrderItemDO bean); |
| 86 | List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list); | 85 | List<ProductSkuUpdateStockReqDTO.Item> convertList(List<TradeOrderItemDO> list); |
| 87 | 86 | ||
| 88 | - default PayOrderCreateReqDTO convert(TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs, | ||
| 89 | - List<ProductSpuRespDTO> spus, TradeOrderProperties tradeOrderProperties) { | 87 | + default PayOrderCreateReqDTO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems, |
| 88 | + TradePriceCalculateRespBO calculateRespBO, TradeOrderProperties orderProperties) { | ||
| 90 | PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO() | 89 | PayOrderCreateReqDTO createReqDTO = new PayOrderCreateReqDTO() |
| 91 | - .setAppId(tradeOrderProperties.getAppId()).setUserIp(tradeOrderDO.getUserIp()); | 90 | + .setAppId(orderProperties.getAppId()).setUserIp(order.getUserIp()); |
| 92 | // 商户相关字段 | 91 | // 商户相关字段 |
| 93 | - createReqDTO.setMerchantOrderId(String.valueOf(tradeOrderDO.getId())); | ||
| 94 | - String subject = spus.get(0).getName(); | ||
| 95 | - if (spus.size() > 1) { | 92 | + createReqDTO.setMerchantOrderId(String.valueOf(order.getId())); |
| 93 | + String subject = calculateRespBO.getItems().get(0).getSpuName(); | ||
| 94 | + if (calculateRespBO.getItems().size() > 1) { | ||
| 96 | subject += " 等多件"; | 95 | subject += " 等多件"; |
| 97 | } | 96 | } |
| 98 | createReqDTO.setSubject(subject); | 97 | createReqDTO.setSubject(subject); |
| 98 | + createReqDTO.setBody(subject); // TODO 芋艿:临时写死 | ||
| 99 | // 订单相关字段 | 99 | // 订单相关字段 |
| 100 | - createReqDTO.setAmount(tradeOrderDO.getPayPrice()).setExpireTime(addTime(tradeOrderProperties.getExpireTime())); | 100 | + createReqDTO.setAmount(order.getPayPrice()).setExpireTime(addTime(orderProperties.getExpireTime())); |
| 101 | return createReqDTO; | 101 | return createReqDTO; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| @@ -111,6 +111,7 @@ public interface TradeOrderConvert { | @@ -111,6 +111,7 @@ public interface TradeOrderConvert { | ||
| 111 | .collect(Collectors.toSet()); | 111 | .collect(Collectors.toSet()); |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | + // TODO 芋艿:可简化 | ||
| 114 | default PageResult<TradeOrderPageItemRespVO> convertPage(PageResult<TradeOrderDO> pageResult, List<TradeOrderItemDO> orderItems, | 115 | default PageResult<TradeOrderPageItemRespVO> convertPage(PageResult<TradeOrderDO> pageResult, List<TradeOrderItemDO> orderItems, |
| 115 | List<ProductPropertyValueDetailRespDTO> propertyValueDetails) { | 116 | List<ProductPropertyValueDetailRespDTO> propertyValueDetails) { |
| 116 | Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId); | 117 | Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId); |
| @@ -147,6 +148,7 @@ public interface TradeOrderConvert { | @@ -147,6 +148,7 @@ public interface TradeOrderConvert { | ||
| 147 | TradeOrderPageItemRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> items); | 148 | TradeOrderPageItemRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> items); |
| 148 | ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean); | 149 | ProductPropertyValueDetailRespVO convert(ProductPropertyValueDetailRespDTO bean); |
| 149 | 150 | ||
| 151 | + // TODO 芋艿:可简化 | ||
| 150 | default TradeOrderDetailRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems, | 152 | default TradeOrderDetailRespVO convert(TradeOrderDO order, List<TradeOrderItemDO> orderItems, |
| 151 | List<ProductPropertyValueDetailRespDTO> propertyValueDetails, MemberUserRespDTO user) { | 153 | List<ProductPropertyValueDetailRespDTO> propertyValueDetails, MemberUserRespDTO user) { |
| 152 | TradeOrderDetailRespVO orderVO = convert2(order, orderItems); | 154 | TradeOrderDetailRespVO orderVO = convert2(order, orderItems); |
| @@ -177,6 +179,7 @@ public interface TradeOrderConvert { | @@ -177,6 +179,7 @@ public interface TradeOrderConvert { | ||
| 177 | TradeOrderDetailRespVO convert2(TradeOrderDO order, List<TradeOrderItemDO> items); | 179 | TradeOrderDetailRespVO convert2(TradeOrderDO order, List<TradeOrderItemDO> items); |
| 178 | MemberUserRespVO convert(MemberUserRespDTO bean); | 180 | MemberUserRespVO convert(MemberUserRespDTO bean); |
| 179 | 181 | ||
| 182 | + // TODO 芋艿:可简化 | ||
| 180 | default PageResult<AppTradeOrderPageItemRespVO> convertPage02(PageResult<TradeOrderDO> pageResult, List<TradeOrderItemDO> orderItems, | 183 | default PageResult<AppTradeOrderPageItemRespVO> convertPage02(PageResult<TradeOrderDO> pageResult, List<TradeOrderItemDO> orderItems, |
| 181 | List<ProductPropertyValueDetailRespDTO> propertyValueDetails) { | 184 | List<ProductPropertyValueDetailRespDTO> propertyValueDetails) { |
| 182 | Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId); | 185 | Map<Long, List<TradeOrderItemDO>> orderItemMap = convertMultiMap(orderItems, TradeOrderItemDO::getOrderId); |
| @@ -241,4 +244,45 @@ public interface TradeOrderConvert { | @@ -241,4 +244,45 @@ public interface TradeOrderConvert { | ||
| 241 | 244 | ||
| 242 | AppTradeOrderItemRespVO convert03(TradeOrderItemDO bean); | 245 | AppTradeOrderItemRespVO convert03(TradeOrderItemDO bean); |
| 243 | 246 | ||
| 247 | + default TradePriceCalculateReqBO convert(Long userId, AppTradeOrderSettlementReqVO settlementReqVO, | ||
| 248 | + List<TradeCartDO> cartList) { | ||
| 249 | + TradePriceCalculateReqBO reqBO = new TradePriceCalculateReqBO(); | ||
| 250 | + reqBO.setUserId(userId).setType(settlementReqVO.getType()) | ||
| 251 | + .setCouponId(settlementReqVO.getCouponId()).setAddressId(settlementReqVO.getAddressId()) | ||
| 252 | + .setItems(new ArrayList<>(settlementReqVO.getItems().size())); | ||
| 253 | + // 商品项的构建 | ||
| 254 | + Map<Long, TradeCartDO> cartMap = convertMap(cartList, TradeCartDO::getId); | ||
| 255 | + for (AppTradeOrderSettlementReqVO.Item item : settlementReqVO.getItems()) { | ||
| 256 | + // 情况一:skuId + count | ||
| 257 | + if (item.getSkuId() != null) { | ||
| 258 | + reqBO.getItems().add(new TradePriceCalculateReqBO.Item().setSkuId(item.getSkuId()).setCount(item.getCount()) | ||
| 259 | + .setSelected(true)); // true 的原因,下单一定选中 | ||
| 260 | + continue; | ||
| 261 | + } | ||
| 262 | + // 情况二:cartId | ||
| 263 | + TradeCartDO cart = cartMap.get(item.getCartId()); | ||
| 264 | + if (cart == null) { | ||
| 265 | + continue; | ||
| 266 | + } | ||
| 267 | + reqBO.getItems().add(new TradePriceCalculateReqBO.Item().setSkuId(cart.getSkuId()).setCount(cart.getCount()) | ||
| 268 | + .setCartId(item.getCartId()).setSelected(true)); // true 的原因,下单一定选中 | ||
| 269 | + } | ||
| 270 | + return reqBO; | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + default AppTradeOrderSettlementRespVO convert(TradePriceCalculateRespBO calculate, AddressRespDTO address) { | ||
| 274 | + AppTradeOrderSettlementRespVO respVO = convert0(calculate, address); | ||
| 275 | + if (address != null) { | ||
| 276 | + Area area = AreaUtils.getArea(address.getAreaId()); | ||
| 277 | + respVO.getAddress().setDistrictId(area.getId()); | ||
| 278 | + respVO.getAddress().setDistrictName(area.getName()); | ||
| 279 | + respVO.getAddress().setCityId(area.getParent().getId()); | ||
| 280 | + respVO.getAddress().setCityName(area.getParent().getName()); | ||
| 281 | + respVO.getAddress().setProvinceId(area.getParent().getParent().getId()); | ||
| 282 | + respVO.getAddress().setProvinceName(area.getParent().getParent().getName()); | ||
| 283 | + } | ||
| 284 | + return respVO; | ||
| 285 | + } | ||
| 286 | + AppTradeOrderSettlementRespVO convert0(TradePriceCalculateRespBO calculate, AddressRespDTO address); | ||
| 287 | + | ||
| 244 | } | 288 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java
| @@ -167,11 +167,24 @@ public class TradeOrderItemDO extends BaseDO { | @@ -167,11 +167,24 @@ public class TradeOrderItemDO extends BaseDO { | ||
| 167 | */ | 167 | */ |
| 168 | private Long propertyId; | 168 | private Long propertyId; |
| 169 | /** | 169 | /** |
| 170 | + * 属性名字 | ||
| 171 | + * | ||
| 172 | + * 关联 ProductPropertyDO 的 name 字段 | ||
| 173 | + */ | ||
| 174 | + private String propertyName; | ||
| 175 | + | ||
| 176 | + /** | ||
| 170 | * 属性值编号 | 177 | * 属性值编号 |
| 171 | * | 178 | * |
| 172 | * 关联 ProductPropertyValueDO 的 id 编号 | 179 | * 关联 ProductPropertyValueDO 的 id 编号 |
| 173 | */ | 180 | */ |
| 174 | private Long valueId; | 181 | private Long valueId; |
| 182 | + /** | ||
| 183 | + * 属性值名字 | ||
| 184 | + * | ||
| 185 | + * 关联 ProductPropertyValueDO 的 name 字段 | ||
| 186 | + */ | ||
| 187 | + private String valueName; | ||
| 175 | 188 | ||
| 176 | } | 189 | } |
| 177 | 190 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/dal/mysql/cart/TradeCartMapper.java
| @@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper; | @@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper; | ||
| 12 | import java.util.Collection; | 12 | import java.util.Collection; |
| 13 | import java.util.List; | 13 | import java.util.List; |
| 14 | import java.util.Map; | 14 | import java.util.Map; |
| 15 | +import java.util.Set; | ||
| 15 | 16 | ||
| 16 | @Mapper | 17 | @Mapper |
| 17 | public interface TradeCartMapper extends BaseMapperX<TradeCartDO> { | 18 | public interface TradeCartMapper extends BaseMapperX<TradeCartDO> { |
| @@ -70,4 +71,10 @@ public interface TradeCartMapper extends BaseMapperX<TradeCartDO> { | @@ -70,4 +71,10 @@ public interface TradeCartMapper extends BaseMapperX<TradeCartDO> { | ||
| 70 | update(updateObject, new LambdaQueryWrapper<TradeCartDO>().in(TradeCartDO::getId, ids)); | 71 | update(updateObject, new LambdaQueryWrapper<TradeCartDO>().in(TradeCartDO::getId, ids)); |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 74 | + default List<TradeCartDO> selectListByUserId(Long userId, Set<Long> ids) { | ||
| 75 | + return selectList(new LambdaQueryWrapper<TradeCartDO>() | ||
| 76 | + .eq(TradeCartDO::getUserId, userId) | ||
| 77 | + .in(TradeCartDO::getId, ids)); | ||
| 78 | + } | ||
| 79 | + | ||
| 73 | } | 80 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartService.java
| @@ -4,10 +4,13 @@ import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO | @@ -4,10 +4,13 @@ import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartAddReqVO | ||
| 4 | import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; | 4 | import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartListRespVO; |
| 5 | import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartResetReqVO; | 5 | import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartResetReqVO; |
| 6 | import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; | 6 | import cn.iocoder.yudao.module.trade.controller.app.cart.vo.AppTradeCartUpdateReqVO; |
| 7 | +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; | ||
| 7 | 8 | ||
| 8 | import javax.validation.Valid; | 9 | import javax.validation.Valid; |
| 9 | import java.util.Collection; | 10 | import java.util.Collection; |
| 11 | +import java.util.List; | ||
| 10 | import java.util.Map; | 12 | import java.util.Map; |
| 13 | +import java.util.Set; | ||
| 11 | 14 | ||
| 12 | /** | 15 | /** |
| 13 | * 购物车 Service 接口 | 16 | * 购物车 Service 接口 |
| @@ -68,6 +71,15 @@ public interface TradeCartService { | @@ -68,6 +71,15 @@ public interface TradeCartService { | ||
| 68 | AppTradeCartListRespVO getCartList(Long userId); | 71 | AppTradeCartListRespVO getCartList(Long userId); |
| 69 | 72 | ||
| 70 | /** | 73 | /** |
| 74 | + * 查询用户的购物车列表 | ||
| 75 | + * | ||
| 76 | + * @param userId 用户编号 | ||
| 77 | + * @param ids 购物项的编号 | ||
| 78 | + * @return 购物车列表 | ||
| 79 | + */ | ||
| 80 | + List<TradeCartDO> getCartList(Long userId, Set<Long> ids); | ||
| 81 | + | ||
| 82 | + /** | ||
| 71 | * 获得用户的购物车商品 SPU 数量的 Map | 83 | * 获得用户的购物车商品 SPU 数量的 Map |
| 72 | * | 84 | * |
| 73 | * @param userId 用户编号 | 85 | * @param userId 用户编号 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/cart/TradeCartServiceImpl.java
| @@ -17,10 +17,7 @@ import org.springframework.transaction.annotation.Transactional; | @@ -17,10 +17,7 @@ import org.springframework.transaction.annotation.Transactional; | ||
| 17 | import org.springframework.validation.annotation.Validated; | 17 | import org.springframework.validation.annotation.Validated; |
| 18 | 18 | ||
| 19 | import javax.annotation.Resource; | 19 | import javax.annotation.Resource; |
| 20 | -import java.util.Collection; | ||
| 21 | -import java.util.Comparator; | ||
| 22 | -import java.util.List; | ||
| 23 | -import java.util.Map; | 20 | +import java.util.*; |
| 24 | 21 | ||
| 25 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 22 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 26 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 23 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| @@ -166,6 +163,14 @@ public class TradeCartServiceImpl implements TradeCartService { | @@ -166,6 +163,14 @@ public class TradeCartServiceImpl implements TradeCartService { | ||
| 166 | return TradeCartConvert.INSTANCE.convertList(carts, spus, skus); | 163 | return TradeCartConvert.INSTANCE.convertList(carts, spus, skus); |
| 167 | } | 164 | } |
| 168 | 165 | ||
| 166 | + @Override | ||
| 167 | + public List<TradeCartDO> getCartList(Long userId, Set<Long> ids) { | ||
| 168 | + if (CollUtil.isEmpty(ids)) { | ||
| 169 | + return Collections.emptyList(); | ||
| 170 | + } | ||
| 171 | + return cartMapper.selectListByUserId(userId, ids); | ||
| 172 | + } | ||
| 173 | + | ||
| 169 | private void deleteCartIfSpuDeleted(List<TradeCartDO> carts, List<ProductSpuRespDTO> spus) { | 174 | private void deleteCartIfSpuDeleted(List<TradeCartDO> carts, List<ProductSpuRespDTO> spus) { |
| 170 | // 如果 SPU 被删除,则删除购物车对应的商品。延迟删除 | 175 | // 如果 SPU 被删除,则删除购物车对应的商品。延迟删除 |
| 171 | carts.removeIf(cart -> { | 176 | carts.removeIf(cart -> { |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateService.java
| @@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.trade.service.delivery; | @@ -2,8 +2,8 @@ package cn.iocoder.yudao.module.trade.service.delivery; | ||
| 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.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateCreateReqVO; | 4 | import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateCreateReqVO; |
| 5 | +import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateDetailRespVO; | ||
| 5 | import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO; | 6 | import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplatePageReqVO; |
| 6 | -import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateRespVO; | ||
| 7 | import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO; | 7 | import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.DeliveryExpressTemplateUpdateReqVO; |
| 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; | 8 | import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; |
| 9 | 9 | ||
| @@ -46,7 +46,7 @@ public interface DeliveryExpressTemplateService { | @@ -46,7 +46,7 @@ public interface DeliveryExpressTemplateService { | ||
| 46 | * @param id 编号 | 46 | * @param id 编号 |
| 47 | * @return 快递运费模板详情 | 47 | * @return 快递运费模板详情 |
| 48 | */ | 48 | */ |
| 49 | - DeliveryExpressTemplateRespVO getDeliveryExpressTemplate(Long id); | 49 | + DeliveryExpressTemplateDetailRespVO getDeliveryExpressTemplate(Long id); |
| 50 | 50 | ||
| 51 | /** | 51 | /** |
| 52 | * 获得快递运费模板列表 | 52 | * 获得快递运费模板列表 |
| @@ -70,4 +70,14 @@ public interface DeliveryExpressTemplateService { | @@ -70,4 +70,14 @@ public interface DeliveryExpressTemplateService { | ||
| 70 | * @return 快递运费模板分页 | 70 | * @return 快递运费模板分页 |
| 71 | */ | 71 | */ |
| 72 | PageResult<DeliveryExpressTemplateDO> getDeliveryExpressTemplatePage(DeliveryExpressTemplatePageReqVO pageReqVO); | 72 | PageResult<DeliveryExpressTemplateDO> getDeliveryExpressTemplatePage(DeliveryExpressTemplatePageReqVO pageReqVO); |
| 73 | + | ||
| 74 | + /** | ||
| 75 | + * 校验快递运费模板 | ||
| 76 | + * | ||
| 77 | + * 如果校验不通过,抛出 {@link cn.iocoder.yudao.framework.common.exception.ServiceException} 异常 | ||
| 78 | + * | ||
| 79 | + * @param templateId 模板编号 | ||
| 80 | + * @return 快递运费模板 | ||
| 81 | + */ | ||
| 82 | + DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId); | ||
| 73 | } | 83 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/delivery/DeliveryExpressTemplateServiceImpl.java
| @@ -185,7 +185,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla | @@ -185,7 +185,7 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla | ||
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | @Override | 187 | @Override |
| 188 | - public DeliveryExpressTemplateRespVO getDeliveryExpressTemplate(Long id) { | 188 | + public DeliveryExpressTemplateDetailRespVO getDeliveryExpressTemplate(Long id) { |
| 189 | List<DeliveryExpressTemplateChargeDO> chargeList = expressTemplateChargeMapper.selectListByTemplateId(id); | 189 | List<DeliveryExpressTemplateChargeDO> chargeList = expressTemplateChargeMapper.selectListByTemplateId(id); |
| 190 | List<DeliveryExpressTemplateFreeDO> freeList = expressTemplateFreeMapper.selectListByTemplateId(id); | 190 | List<DeliveryExpressTemplateFreeDO> freeList = expressTemplateFreeMapper.selectListByTemplateId(id); |
| 191 | DeliveryExpressTemplateDO template = expressTemplateMapper.selectById(id); | 191 | DeliveryExpressTemplateDO template = expressTemplateMapper.selectById(id); |
| @@ -207,4 +207,13 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla | @@ -207,4 +207,13 @@ public class DeliveryExpressTemplateServiceImpl implements DeliveryExpressTempla | ||
| 207 | return expressTemplateMapper.selectPage(pageReqVO); | 207 | return expressTemplateMapper.selectPage(pageReqVO); |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | + @Override | ||
| 211 | + public DeliveryExpressTemplateDO validateDeliveryExpressTemplate(Long templateId) { | ||
| 212 | + DeliveryExpressTemplateDO template = expressTemplateMapper.selectById(templateId); | ||
| 213 | + if (template == null) { | ||
| 214 | + throw exception(EXPRESS_TEMPLATE_NOT_EXISTS); | ||
| 215 | + } | ||
| 216 | + return template; | ||
| 217 | + } | ||
| 218 | + | ||
| 210 | } | 219 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceImpl.java
| 1 | package cn.iocoder.yudao.module.trade.service.order; | 1 | package cn.iocoder.yudao.module.trade.service.order; |
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | +import cn.hutool.core.lang.Assert; | ||
| 4 | import cn.hutool.core.util.IdUtil; | 5 | import cn.hutool.core.util.IdUtil; |
| 5 | import cn.hutool.core.util.ObjectUtil; | 6 | import cn.hutool.core.util.ObjectUtil; |
| 6 | import cn.hutool.core.util.StrUtil; | 7 | import cn.hutool.core.util.StrUtil; |
| 7 | import cn.iocoder.yudao.framework.common.core.KeyValue; | 8 | import cn.iocoder.yudao.framework.common.core.KeyValue; |
| 8 | import cn.iocoder.yudao.framework.common.enums.TerminalEnum; | 9 | import cn.iocoder.yudao.framework.common.enums.TerminalEnum; |
| 9 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 10 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 10 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 11 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 11 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 12 | import cn.iocoder.yudao.module.member.api.address.AddressApi; | 12 | import cn.iocoder.yudao.module.member.api.address.AddressApi; |
| 13 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | 13 | import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; |
| @@ -18,15 +18,9 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; | @@ -18,15 +18,9 @@ import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; | ||
| 18 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; | 18 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; |
| 19 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | 19 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 20 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | 20 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |
| 21 | -import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 22 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; | 21 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO; |
| 23 | -import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | ||
| 24 | -import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | ||
| 25 | -import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | ||
| 26 | import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; | 22 | import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; |
| 27 | import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; | 23 | import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponUseReqDTO; |
| 28 | -import cn.iocoder.yudao.module.promotion.api.price.PriceApi; | ||
| 29 | -import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO; | ||
| 30 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; | 24 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderDeliveryReqVO; |
| 31 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; | 25 | import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderPageReqVO; |
| 32 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; | 26 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO; |
| @@ -34,13 +28,19 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageRe | @@ -34,13 +28,19 @@ import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderPageRe | ||
| 34 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO; | 28 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO; |
| 35 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; | 29 | import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementRespVO; |
| 36 | import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; | 30 | import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert; |
| 31 | +import cn.iocoder.yudao.module.trade.dal.dataobject.cart.TradeCartDO; | ||
| 37 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; | 32 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO; |
| 38 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; | 33 | import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO; |
| 39 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; | 34 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper; |
| 40 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; | 35 | import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper; |
| 41 | import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; | 36 | import cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants; |
| 37 | +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | ||
| 42 | import cn.iocoder.yudao.module.trade.enums.order.*; | 38 | import cn.iocoder.yudao.module.trade.enums.order.*; |
| 43 | import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; | 39 | import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties; |
| 40 | +import cn.iocoder.yudao.module.trade.service.cart.TradeCartService; | ||
| 41 | +import cn.iocoder.yudao.module.trade.service.price.TradePriceService; | ||
| 42 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||
| 43 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||
| 44 | import lombok.extern.slf4j.Slf4j; | 44 | import lombok.extern.slf4j.Slf4j; |
| 45 | import org.springframework.stereotype.Service; | 45 | import org.springframework.stereotype.Service; |
| 46 | import org.springframework.transaction.annotation.Transactional; | 46 | import org.springframework.transaction.annotation.Transactional; |
| @@ -71,11 +71,12 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -71,11 +71,12 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 71 | private TradeOrderItemMapper tradeOrderItemMapper; | 71 | private TradeOrderItemMapper tradeOrderItemMapper; |
| 72 | 72 | ||
| 73 | @Resource | 73 | @Resource |
| 74 | - private PriceApi priceApi; | 74 | + private TradeCartService tradeCartService; |
| 75 | @Resource | 75 | @Resource |
| 76 | - private ProductSkuApi productSkuApi; | 76 | + private TradePriceService tradePriceService; |
| 77 | + | ||
| 77 | @Resource | 78 | @Resource |
| 78 | - private ProductSpuApi productSpuApi; | 79 | + private ProductSkuApi productSkuApi; |
| 79 | @Resource | 80 | @Resource |
| 80 | private PayOrderApi payOrderApi; | 81 | private PayOrderApi payOrderApi; |
| 81 | @Resource | 82 | @Resource |
| @@ -92,76 +93,70 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -92,76 +93,70 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 92 | 93 | ||
| 93 | @Override | 94 | @Override |
| 94 | public AppTradeOrderSettlementRespVO settlementOrder(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) { | 95 | public AppTradeOrderSettlementRespVO settlementOrder(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) { |
| 95 | - return null; | 96 | + // 1. 获得收货地址 |
| 97 | + AddressRespDTO address = getAddress(userId, settlementReqVO.getAddressId()); | ||
| 98 | + if (address != null) { | ||
| 99 | + settlementReqVO.setAddressId(address.getId()); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + // 2. 计算价格 | ||
| 103 | + TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, settlementReqVO); | ||
| 104 | + | ||
| 105 | + // 3. 拼接返回 | ||
| 106 | + return TradeOrderConvert.INSTANCE.convert(calculateRespBO, address); | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + /** | ||
| 110 | + * 获得用户地址 | ||
| 111 | + * | ||
| 112 | + * @param userId 用户编号 | ||
| 113 | + * @param addressId 地址编号 | ||
| 114 | + * @return 地址 | ||
| 115 | + */ | ||
| 116 | + private AddressRespDTO getAddress(Long userId, Long addressId) { | ||
| 117 | + if (addressId != null) { | ||
| 118 | + return addressApi.getAddress(addressId, userId); | ||
| 119 | + } | ||
| 120 | + return addressApi.getDefaultAddress(userId); | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + /** | ||
| 124 | + * 计算订单价格 | ||
| 125 | + * | ||
| 126 | + * @param userId 用户编号 | ||
| 127 | + * @param settlementReqVO 结算信息 | ||
| 128 | + * @return 订单价格 | ||
| 129 | + */ | ||
| 130 | + private TradePriceCalculateRespBO calculatePrice(Long userId, AppTradeOrderSettlementReqVO settlementReqVO) { | ||
| 131 | + // 1. 如果来自购物车,则获得购物车的商品 | ||
| 132 | + List<TradeCartDO> cartList = tradeCartService.getCartList(userId, | ||
| 133 | + convertSet(settlementReqVO.getItems(), AppTradeOrderSettlementReqVO.Item::getCartId)); | ||
| 134 | + | ||
| 135 | + // 2. 计算价格 | ||
| 136 | + TradePriceCalculateReqBO calculateReqBO = TradeOrderConvert.INSTANCE.convert(userId, settlementReqVO, cartList); | ||
| 137 | + calculateReqBO.getItems().forEach(item -> Assert.isTrue(item.getSelected(), // 防御性编程,保证都是选中的 | ||
| 138 | + "商品({}) 未设置为选中", item.getSkuId())); | ||
| 139 | + return tradePriceService.calculatePrice(calculateReqBO); | ||
| 96 | } | 140 | } |
| 97 | 141 | ||
| 98 | @Override | 142 | @Override |
| 99 | @Transactional(rollbackFor = Exception.class) | 143 | @Transactional(rollbackFor = Exception.class) |
| 100 | public Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { | 144 | public Long createOrder(Long userId, String userIp, AppTradeOrderCreateReqVO createReqVO) { |
| 101 | - // 商品 SKU 检查:可售状态、库存 | ||
| 102 | -// List<ProductSkuRespDTO> skus = validateSkuSaleable(createReqVO.getItems()); // TODO 芋艿,临时关闭。 | ||
| 103 | - List<ProductSkuRespDTO> skus = null; | ||
| 104 | - // 商品 SPU 检查:可售状态 | ||
| 105 | - List<ProductSpuRespDTO> spus = validateSpuSaleable(convertSet(skus, ProductSkuRespDTO::getSpuId)); | ||
| 106 | - // 用户收件地址的校验 | 145 | + // 1. 用户收件地址的校验 |
| 107 | AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId()); | 146 | AddressRespDTO address = validateAddress(userId, createReqVO.getAddressId()); |
| 108 | 147 | ||
| 109 | - // 价格计算 | ||
| 110 | - PriceCalculateRespDTO priceResp = priceApi.calculatePrice(TradeOrderConvert.INSTANCE.convert(createReqVO, userId)); | 148 | + // 2. 价格计算 |
| 149 | + TradePriceCalculateRespBO calculateRespBO = calculatePrice(userId, createReqVO); | ||
| 111 | 150 | ||
| 112 | - // 插入 TradeOrderDO 订单 | ||
| 113 | - TradeOrderDO tradeOrderDO = createTradeOrder(userId, userIp, createReqVO, priceResp.getOrder(), address); | ||
| 114 | - // 插入 TradeOrderItemDO 订单项 | ||
| 115 | - List<TradeOrderItemDO> tradeOrderItems = createTradeOrderItems(tradeOrderDO, priceResp.getOrder().getItems(), skus); | 151 | + // 3.1 插入 TradeOrderDO 订单 |
| 152 | + TradeOrderDO order = createTradeOrder(userId, userIp, createReqVO, calculateRespBO, address); | ||
| 153 | + // 3.2 插入 TradeOrderItemDO 订单项 | ||
| 154 | + List<TradeOrderItemDO> orderItems = createTradeOrderItems(order, calculateRespBO); | ||
| 116 | 155 | ||
| 117 | // 订单创建完后的逻辑 | 156 | // 订单创建完后的逻辑 |
| 118 | - afterCreateTradeOrder(userId, createReqVO, tradeOrderDO, tradeOrderItems, spus); | 157 | + afterCreateTradeOrder(userId, createReqVO, order, orderItems, calculateRespBO); |
| 119 | // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来! | 158 | // TODO @LeeYan9: 是可以思考下, 订单的营销优惠记录, 应该记录在哪里, 微信讨论起来! |
| 120 | - return tradeOrderDO.getId(); | ||
| 121 | - } | ||
| 122 | - | ||
| 123 | -// /** | ||
| 124 | -// * 校验商品 SKU 是否可出售 | ||
| 125 | -// * | ||
| 126 | -// * @param items 商品 SKU | ||
| 127 | -// * @return 商品 SKU 数组 | ||
| 128 | -// */ | ||
| 129 | -// private List<ProductSkuRespDTO> validateSkuSaleable(List<Item> items) { | ||
| 130 | -// List<ProductSkuRespDTO> skus = productSkuApi.getSkuList(convertSet(items, Item::getSkuId)); | ||
| 131 | -// // SKU 不存在 | ||
| 132 | -// if (items.size() != skus.size()) { | ||
| 133 | -// throw exception(ORDER_CREATE_SKU_NOT_FOUND); | ||
| 134 | -// } | ||
| 135 | -// // 校验库存不足 | ||
| 136 | -// Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId); | ||
| 137 | -// items.forEach(item -> { | ||
| 138 | -// ProductSkuRespDTO sku = skuMap.get(item.getSkuId()); | ||
| 139 | -// if (item.getCount() > sku.getStock()) { | ||
| 140 | -// throw exception(ErrorCodeConstants.ORDER_CREATE_SKU_STOCK_NOT_ENOUGH); | ||
| 141 | -// } | ||
| 142 | -// }); | ||
| 143 | -// return skus; | ||
| 144 | -// } | ||
| 145 | - | ||
| 146 | - /** | ||
| 147 | - * 校验商品 SPU 是否可出售 | ||
| 148 | - * | ||
| 149 | - * @param spuIds 商品 SPU 编号数组 | ||
| 150 | - * @return 商品 SPU 数组 | ||
| 151 | - */ | ||
| 152 | - private List<ProductSpuRespDTO> validateSpuSaleable(Set<Long> spuIds) { | ||
| 153 | - List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(spuIds); | ||
| 154 | - // SPU 不存在 | ||
| 155 | - if (spus.size() != spuIds.size()) { | ||
| 156 | - throw exception(ORDER_CREATE_SPU_NOT_FOUND); | ||
| 157 | - } | ||
| 158 | - // 校验是否存在禁用的 SPU | ||
| 159 | - ProductSpuRespDTO spu = CollectionUtils.findFirst(spus, | ||
| 160 | - spuDTO -> ObjectUtil.notEqual(ProductSpuStatusEnum.ENABLE.getStatus(), spuDTO.getStatus())); | ||
| 161 | - if (spu != null) { | ||
| 162 | - throw exception(ErrorCodeConstants.ORDER_CREATE_SPU_NOT_SALE); | ||
| 163 | - } | ||
| 164 | - return spus; | 159 | + return order.getId(); |
| 165 | } | 160 | } |
| 166 | 161 | ||
| 167 | /** | 162 | /** |
| @@ -173,33 +168,35 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -173,33 +168,35 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 173 | */ | 168 | */ |
| 174 | private AddressRespDTO validateAddress(Long userId, Long addressId) { | 169 | private AddressRespDTO validateAddress(Long userId, Long addressId) { |
| 175 | AddressRespDTO address = addressApi.getAddress(addressId, userId); | 170 | AddressRespDTO address = addressApi.getAddress(addressId, userId); |
| 176 | - if (Objects.isNull(address)) { | 171 | + if (address == null) { |
| 177 | throw exception(ErrorCodeConstants.ORDER_CREATE_ADDRESS_NOT_FOUND); | 172 | throw exception(ErrorCodeConstants.ORDER_CREATE_ADDRESS_NOT_FOUND); |
| 178 | } | 173 | } |
| 179 | return address; | 174 | return address; |
| 180 | } | 175 | } |
| 181 | 176 | ||
| 182 | private TradeOrderDO createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO, | 177 | private TradeOrderDO createTradeOrder(Long userId, String clientIp, AppTradeOrderCreateReqVO createReqVO, |
| 183 | - PriceCalculateRespDTO.Order order, AddressRespDTO address) { | ||
| 184 | - TradeOrderDO tradeOrderDO = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, order, address); | ||
| 185 | - tradeOrderDO.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的; | ||
| 186 | - tradeOrderDO.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); | ||
| 187 | - tradeOrderDO.setType(TradeOrderTypeEnum.NORMAL.getType()); | ||
| 188 | - tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); | ||
| 189 | - tradeOrderDO.setProductCount(getSumValue(order.getItems(), PriceCalculateRespDTO.OrderItem::getCount, Integer::sum)); | ||
| 190 | - tradeOrderDO.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? | ||
| 191 | - tradeOrderDO.setAdjustPrice(0).setPayed(false); // 支付信息 | ||
| 192 | - tradeOrderDO.setDeliveryStatus(TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus()); // 物流信息 | ||
| 193 | - tradeOrderDO.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); // 退款信息 | ||
| 194 | - tradeOrderMapper.insert(tradeOrderDO); | ||
| 195 | - return tradeOrderDO; | 178 | + TradePriceCalculateRespBO calculateRespBO, AddressRespDTO address) { |
| 179 | + TradeOrderDO order = TradeOrderConvert.INSTANCE.convert(userId, clientIp, createReqVO, calculateRespBO, address); | ||
| 180 | + order.setNo(IdUtil.getSnowflakeNextId() + ""); // TODO @LeeYan9: 思考下, 怎么生成好点哈; 这个是会展示给用户的; | ||
| 181 | + order.setStatus(TradeOrderStatusEnum.UNPAID.getStatus()); | ||
| 182 | + order.setType(TradeOrderTypeEnum.NORMAL.getType()); | ||
| 183 | + order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()); | ||
| 184 | + order.setProductCount(getSumValue(calculateRespBO.getItems(), TradePriceCalculateRespBO.OrderItem::getCount, Integer::sum)); | ||
| 185 | + order.setTerminal(TerminalEnum.H5.getTerminal()); // todo 数据来源? | ||
| 186 | + // 支付信息 | ||
| 187 | + order.setAdjustPrice(0).setPayed(false); | ||
| 188 | + // 物流信息 TODO 芋艿:暂时写死物流方式;应该是前端选择的 | ||
| 189 | + order.setDeliveryType(DeliveryTypeEnum.EXPRESS.getMode()).setDeliveryStatus(TradeOrderDeliveryStatusEnum.UNDELIVERED.getStatus()); | ||
| 190 | + // 退款信息 | ||
| 191 | + order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0); | ||
| 192 | + tradeOrderMapper.insert(order); | ||
| 193 | + return order; | ||
| 196 | } | 194 | } |
| 197 | 195 | ||
| 198 | - private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO, | ||
| 199 | - List<PriceCalculateRespDTO.OrderItem> orderItems, List<ProductSkuRespDTO> skus) { | ||
| 200 | - List<TradeOrderItemDO> tradeOrderItemDOs = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, orderItems, skus); | ||
| 201 | - tradeOrderItemMapper.insertBatch(tradeOrderItemDOs); | ||
| 202 | - return tradeOrderItemDOs; | 196 | + private List<TradeOrderItemDO> createTradeOrderItems(TradeOrderDO tradeOrderDO, TradePriceCalculateRespBO calculateRespBO) { |
| 197 | + List<TradeOrderItemDO> orderItems = TradeOrderConvert.INSTANCE.convertList(tradeOrderDO, calculateRespBO); | ||
| 198 | + tradeOrderItemMapper.insertBatch(orderItems); | ||
| 199 | + return orderItems; | ||
| 203 | } | 200 | } |
| 204 | 201 | ||
| 205 | /** | 202 | /** |
| @@ -210,12 +207,13 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -210,12 +207,13 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 210 | * @param userId 用户编号 | 207 | * @param userId 用户编号 |
| 211 | * @param createReqVO 创建订单请求 | 208 | * @param createReqVO 创建订单请求 |
| 212 | * @param tradeOrderDO 交易订单 | 209 | * @param tradeOrderDO 交易订单 |
| 210 | + * @param calculateRespBO 订单价格计算结果 | ||
| 213 | */ | 211 | */ |
| 214 | private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, | 212 | private void afterCreateTradeOrder(Long userId, AppTradeOrderCreateReqVO createReqVO, |
| 215 | - TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs, | ||
| 216 | - List<ProductSpuRespDTO> spus) { | 213 | + TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> orderItems, |
| 214 | + TradePriceCalculateRespBO calculateRespBO) { | ||
| 217 | // 下单时扣减商品库存 | 215 | // 下单时扣减商品库存 |
| 218 | - productSkuApi.updateSkuStock(new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(tradeOrderItemDOs))); | 216 | + productSkuApi.updateSkuStock(new ProductSkuUpdateStockReqDTO(TradeOrderConvert.INSTANCE.convertList(orderItems))); |
| 219 | 217 | ||
| 220 | // 删除购物车商品 TODO 芋艿:待实现 | 218 | // 删除购物车商品 TODO 芋艿:待实现 |
| 221 | 219 | ||
| @@ -228,20 +226,19 @@ public class TradeOrderServiceImpl implements TradeOrderService { | @@ -228,20 +226,19 @@ public class TradeOrderServiceImpl implements TradeOrderService { | ||
| 228 | } | 226 | } |
| 229 | 227 | ||
| 230 | // 生成预支付 | 228 | // 生成预支付 |
| 231 | - createPayOrder(tradeOrderDO, tradeOrderItemDOs, spus); | 229 | + createPayOrder(tradeOrderDO, orderItems, calculateRespBO); |
| 232 | 230 | ||
| 233 | // 增加订单日志 TODO 芋艿:待实现 | 231 | // 增加订单日志 TODO 芋艿:待实现 |
| 234 | } | 232 | } |
| 235 | 233 | ||
| 236 | - private void createPayOrder(TradeOrderDO tradeOrderDO, List<TradeOrderItemDO> tradeOrderItemDOs, | ||
| 237 | - List<ProductSpuRespDTO> spus) { | 234 | + private void createPayOrder(TradeOrderDO order, List<TradeOrderItemDO> orderItems, TradePriceCalculateRespBO calculateRespBO) { |
| 238 | // 创建支付单,用于后续的支付 | 235 | // 创建支付单,用于后续的支付 |
| 239 | PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( | 236 | PayOrderCreateReqDTO payOrderCreateReqDTO = TradeOrderConvert.INSTANCE.convert( |
| 240 | - tradeOrderDO, tradeOrderItemDOs, spus, tradeOrderProperties); | 237 | + order, orderItems, calculateRespBO, tradeOrderProperties); |
| 241 | Long payOrderId = payOrderApi.createOrder(payOrderCreateReqDTO); | 238 | Long payOrderId = payOrderApi.createOrder(payOrderCreateReqDTO); |
| 242 | 239 | ||
| 243 | // 更新到交易单上 | 240 | // 更新到交易单上 |
| 244 | - tradeOrderMapper.updateById(new TradeOrderDO().setId(tradeOrderDO.getId()).setPayOrderId(payOrderId)); | 241 | + tradeOrderMapper.updateById(new TradeOrderDO().setId(order.getId()).setPayOrderId(payOrderId)); |
| 245 | } | 242 | } |
| 246 | 243 | ||
| 247 | @Override | 244 | @Override |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceService.java
| @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.trade.service.price; | @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.trade.service.price; | ||
| 3 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | 3 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; |
| 4 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | 4 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; |
| 5 | 5 | ||
| 6 | +import javax.validation.Valid; | ||
| 7 | + | ||
| 6 | /** | 8 | /** |
| 7 | * 价格计算 Service 接口 | 9 | * 价格计算 Service 接口 |
| 8 | * | 10 | * |
| @@ -16,6 +18,6 @@ public interface TradePriceService { | @@ -16,6 +18,6 @@ public interface TradePriceService { | ||
| 16 | * @param calculateReqDTO 计算信息 | 18 | * @param calculateReqDTO 计算信息 |
| 17 | * @return 计算结果 | 19 | * @return 计算结果 |
| 18 | */ | 20 | */ |
| 19 | - TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqDTO); | 21 | + TradePriceCalculateRespBO calculatePrice(@Valid TradePriceCalculateReqBO calculateReqDTO); |
| 20 | 22 | ||
| 21 | } | 23 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImpl.java
| @@ -2,12 +2,16 @@ package cn.iocoder.yudao.module.trade.service.price; | @@ -2,12 +2,16 @@ package cn.iocoder.yudao.module.trade.service.price; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | 3 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |
| 4 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | 4 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 5 | +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | ||
| 6 | +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | ||
| 7 | +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | ||
| 5 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | 8 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; |
| 6 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | 9 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; |
| 7 | import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator; | 10 | import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator; |
| 8 | import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper; | 11 | import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculatorHelper; |
| 9 | import lombok.extern.slf4j.Slf4j; | 12 | import lombok.extern.slf4j.Slf4j; |
| 10 | import org.springframework.stereotype.Service; | 13 | import org.springframework.stereotype.Service; |
| 14 | +import org.springframework.validation.annotation.Validated; | ||
| 11 | 15 | ||
| 12 | import javax.annotation.Resource; | 16 | import javax.annotation.Resource; |
| 13 | import java.util.List; | 17 | import java.util.List; |
| @@ -15,8 +19,8 @@ import java.util.Map; | @@ -15,8 +19,8 @@ import java.util.Map; | ||
| 15 | 19 | ||
| 16 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 20 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 17 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | 21 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; |
| 18 | -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_NOT_EXISTS; | ||
| 19 | -import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SKU_STOCK_NOT_ENOUGH; | 22 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 23 | +import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.*; | ||
| 20 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL; | 24 | import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.PRICE_CALCULATE_PAY_PRICE_ILLEGAL; |
| 21 | 25 | ||
| 22 | /** | 26 | /** |
| @@ -25,22 +29,28 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.PRICE_C | @@ -25,22 +29,28 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.PRICE_C | ||
| 25 | * @author 芋道源码 | 29 | * @author 芋道源码 |
| 26 | */ | 30 | */ |
| 27 | @Service | 31 | @Service |
| 32 | +@Validated | ||
| 28 | @Slf4j | 33 | @Slf4j |
| 29 | public class TradePriceServiceImpl implements TradePriceService { | 34 | public class TradePriceServiceImpl implements TradePriceService { |
| 30 | 35 | ||
| 31 | @Resource | 36 | @Resource |
| 32 | private ProductSkuApi productSkuApi; | 37 | private ProductSkuApi productSkuApi; |
| 33 | @Resource | 38 | @Resource |
| 39 | + private ProductSpuApi productSpuApi; | ||
| 40 | + | ||
| 41 | + @Resource | ||
| 34 | private List<TradePriceCalculator> priceCalculators; | 42 | private List<TradePriceCalculator> priceCalculators; |
| 35 | 43 | ||
| 36 | @Override | 44 | @Override |
| 37 | public TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqBO) { | 45 | public TradePriceCalculateRespBO calculatePrice(TradePriceCalculateReqBO calculateReqBO) { |
| 38 | - // 1. 获得商品 SKU 数组 | ||
| 39 | - List<ProductSkuRespDTO> skuList = checkSkus(calculateReqBO); | 46 | + // 1.1 获得商品 SKU 数组 |
| 47 | + List<ProductSkuRespDTO> skuList = checkSkuList(calculateReqBO); | ||
| 48 | + // 1.2 获得商品 SPU 数组 | ||
| 49 | + List<ProductSpuRespDTO> spuList = checkSpuList(skuList); | ||
| 40 | 50 | ||
| 41 | // 2.1 计算价格 | 51 | // 2.1 计算价格 |
| 42 | TradePriceCalculateRespBO calculateRespBO = TradePriceCalculatorHelper | 52 | TradePriceCalculateRespBO calculateRespBO = TradePriceCalculatorHelper |
| 43 | - .buildCalculateResp(calculateReqBO, skuList); | 53 | + .buildCalculateResp(calculateReqBO, spuList, skuList); |
| 44 | priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO)); | 54 | priceCalculators.forEach(calculator -> calculator.calculate(calculateReqBO, calculateRespBO)); |
| 45 | // 2.2 如果最终支付金额小于等于 0,则抛出业务异常 | 55 | // 2.2 如果最终支付金额小于等于 0,则抛出业务异常 |
| 46 | if (calculateRespBO.getPrice().getPayPrice() <= 0) { | 56 | if (calculateRespBO.getPrice().getPayPrice() <= 0) { |
| @@ -51,7 +61,7 @@ public class TradePriceServiceImpl implements TradePriceService { | @@ -51,7 +61,7 @@ public class TradePriceServiceImpl implements TradePriceService { | ||
| 51 | return calculateRespBO; | 61 | return calculateRespBO; |
| 52 | } | 62 | } |
| 53 | 63 | ||
| 54 | - private List<ProductSkuRespDTO> checkSkus(TradePriceCalculateReqBO reqBO) { | 64 | + private List<ProductSkuRespDTO> checkSkuList(TradePriceCalculateReqBO reqBO) { |
| 55 | // 获得商品 SKU 数组 | 65 | // 获得商品 SKU 数组 |
| 56 | Map<Long, Integer> skuIdCountMap = convertMap(reqBO.getItems(), | 66 | Map<Long, Integer> skuIdCountMap = convertMap(reqBO.getItems(), |
| 57 | TradePriceCalculateReqBO.Item::getSkuId, TradePriceCalculateReqBO.Item::getCount); | 67 | TradePriceCalculateReqBO.Item::getSkuId, TradePriceCalculateReqBO.Item::getCount); |
| @@ -70,4 +80,20 @@ public class TradePriceServiceImpl implements TradePriceService { | @@ -70,4 +80,20 @@ public class TradePriceServiceImpl implements TradePriceService { | ||
| 70 | return skus; | 80 | return skus; |
| 71 | } | 81 | } |
| 72 | 82 | ||
| 83 | + private List<ProductSpuRespDTO> checkSpuList(List<ProductSkuRespDTO> skuList) { | ||
| 84 | + // 获得商品 SPU 数组 | ||
| 85 | + List<ProductSpuRespDTO> spus = productSpuApi.getSpuList(convertSet(skuList, ProductSkuRespDTO::getSpuId)); | ||
| 86 | + | ||
| 87 | + // 校验商品 SPU | ||
| 88 | + spus.forEach(spu -> { | ||
| 89 | + if (spu == null) { | ||
| 90 | + throw exception(SPU_NOT_EXISTS); | ||
| 91 | + } | ||
| 92 | + if (!ProductSpuStatusEnum.isEnable(spu.getStatus())) { | ||
| 93 | + throw exception(SPU_NOT_ENABLE); | ||
| 94 | + } | ||
| 95 | + }); | ||
| 96 | + return spus; | ||
| 97 | + } | ||
| 98 | + | ||
| 73 | } | 99 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateReqBO.java
| 1 | package cn.iocoder.yudao.module.trade.service.price.bo; | 1 | package cn.iocoder.yudao.module.trade.service.price.bo; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; | ||
| 4 | +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | ||
| 3 | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | 5 | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; |
| 4 | import lombok.Data; | 6 | import lombok.Data; |
| 5 | 7 | ||
| @@ -21,7 +23,7 @@ public class TradePriceCalculateReqBO { | @@ -21,7 +23,7 @@ public class TradePriceCalculateReqBO { | ||
| 21 | * | 23 | * |
| 22 | * 枚举 {@link TradeOrderTypeEnum} | 24 | * 枚举 {@link TradeOrderTypeEnum} |
| 23 | */ | 25 | */ |
| 24 | - private Integer orderType; | 26 | + private Integer type; |
| 25 | 27 | ||
| 26 | /** | 28 | /** |
| 27 | * 用户编号 | 29 | * 用户编号 |
| @@ -45,6 +47,21 @@ public class TradePriceCalculateReqBO { | @@ -45,6 +47,21 @@ public class TradePriceCalculateReqBO { | ||
| 45 | private Long addressId; | 47 | private Long addressId; |
| 46 | 48 | ||
| 47 | /** | 49 | /** |
| 50 | + * 配送方式 | ||
| 51 | + * | ||
| 52 | + * 枚举 {@link DeliveryTypeEnum} | ||
| 53 | + */ | ||
| 54 | + private Integer deliveryType; | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * 配送模板编号 | ||
| 58 | + * | ||
| 59 | + * 关联 {@link DeliveryExpressTemplateDO#getId()} | ||
| 60 | + */ | ||
| 61 | + // TODO @jason:运费模版,是不是每个 SKU 传入哈 | ||
| 62 | + private Long templateId; | ||
| 63 | + | ||
| 64 | + /** | ||
| 48 | * 商品 SKU 数组 | 65 | * 商品 SKU 数组 |
| 49 | */ | 66 | */ |
| 50 | @NotNull(message = "商品数组不能为空") | 67 | @NotNull(message = "商品数组不能为空") |
| @@ -82,5 +99,4 @@ public class TradePriceCalculateReqBO { | @@ -82,5 +99,4 @@ public class TradePriceCalculateReqBO { | ||
| 82 | private Boolean selected; | 99 | private Boolean selected; |
| 83 | 100 | ||
| 84 | } | 101 | } |
| 85 | - | ||
| 86 | } | 102 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/bo/TradePriceCalculateRespBO.java
| 1 | package cn.iocoder.yudao.module.trade.service.price.bo; | 1 | package cn.iocoder.yudao.module.trade.service.price.bo; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; | ||
| 3 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | 4 | import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; |
| 4 | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | 5 | import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; |
| 5 | import lombok.Data; | 6 | import lombok.Data; |
| @@ -23,7 +24,7 @@ public class TradePriceCalculateRespBO { | @@ -23,7 +24,7 @@ public class TradePriceCalculateRespBO { | ||
| 23 | * | 24 | * |
| 24 | * 枚举 {@link TradeOrderTypeEnum} | 25 | * 枚举 {@link TradeOrderTypeEnum} |
| 25 | */ | 26 | */ |
| 26 | - private Integer orderType; | 27 | + private Integer type; |
| 27 | 28 | ||
| 28 | /** | 29 | /** |
| 29 | * 订单价格 | 30 | * 订单价格 |
| @@ -163,7 +164,26 @@ public class TradePriceCalculateRespBO { | @@ -163,7 +164,26 @@ public class TradePriceCalculateRespBO { | ||
| 163 | */ | 164 | */ |
| 164 | private Integer payPrice; | 165 | private Integer payPrice; |
| 165 | 166 | ||
| 166 | - // TODO 芋艿:这里补充下基本信息,简单一点。 | 167 | + // ========== 商品信息 ========== |
| 168 | + /** | ||
| 169 | + * 商品名 | ||
| 170 | + */ | ||
| 171 | + private String spuName; | ||
| 172 | + /** | ||
| 173 | + * 商品图片 | ||
| 174 | + * | ||
| 175 | + * 优先级:SKU.picUrl > SPU.picUrl | ||
| 176 | + */ | ||
| 177 | + private String picUrl; | ||
| 178 | + /** | ||
| 179 | + * 分类编号 | ||
| 180 | + */ | ||
| 181 | + private Long categoryId; | ||
| 182 | + | ||
| 183 | + /** | ||
| 184 | + * 商品属性数组 | ||
| 185 | + */ | ||
| 186 | + private List<ProductPropertyValueDetailRespDTO> properties; | ||
| 167 | 187 | ||
| 168 | } | 188 | } |
| 169 | 189 | ||
| @@ -190,12 +210,6 @@ public class TradePriceCalculateRespBO { | @@ -190,12 +210,6 @@ public class TradePriceCalculateRespBO { | ||
| 190 | */ | 210 | */ |
| 191 | private Integer type; | 211 | private Integer type; |
| 192 | /** | 212 | /** |
| 193 | - * 营销级别 | ||
| 194 | - * | ||
| 195 | - * 枚举 @link PromotionLevelEnum} TODO PromotionLevelEnum 没有这个枚举类 | ||
| 196 | - */ | ||
| 197 | - private Integer level; | ||
| 198 | - /** | ||
| 199 | * 计算时的原价(总),单位:分 | 213 | * 计算时的原价(总),单位:分 |
| 200 | */ | 214 | */ |
| 201 | private Integer totalPrice; | 215 | private Integer totalPrice; |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculator.java
| @@ -101,7 +101,8 @@ public class TradeCouponPriceCalculator implements TradePriceCalculator { | @@ -101,7 +101,8 @@ public class TradeCouponPriceCalculator implements TradePriceCalculator { | ||
| 101 | CouponRespDTO coupon) { | 101 | CouponRespDTO coupon) { |
| 102 | Predicate<TradePriceCalculateRespBO.OrderItem> matchPredicate = TradePriceCalculateRespBO.OrderItem::getSelected; | 102 | Predicate<TradePriceCalculateRespBO.OrderItem> matchPredicate = TradePriceCalculateRespBO.OrderItem::getSelected; |
| 103 | if (PromotionProductScopeEnum.SPU.getScope().equals(coupon.getProductScope())) { | 103 | if (PromotionProductScopeEnum.SPU.getScope().equals(coupon.getProductScope())) { |
| 104 | - matchPredicate = orderItem -> coupon.getProductSpuIds().contains(orderItem.getSpuId()); | 104 | + matchPredicate = matchPredicate // 额外加如下条件 |
| 105 | + .and(orderItem -> coupon.getProductSpuIds().contains(orderItem.getSpuId())); | ||
| 105 | } | 106 | } |
| 106 | return filterList(result.getItems(), matchPredicate); | 107 | return filterList(result.getItems(), matchPredicate); |
| 107 | } | 108 | } |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDeliveryPriceCalculator.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.member.api.address.AddressApi; | ||
| 4 | +import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO; | ||
| 5 | +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | ||
| 6 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 7 | +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateChargeDO; | ||
| 8 | +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO; | ||
| 9 | +import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateFreeDO; | ||
| 10 | +import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateChargeMapper; | ||
| 11 | +import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressTemplateFreeMapper; | ||
| 12 | +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryExpressChargeModeEnum; | ||
| 13 | +import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum; | ||
| 14 | +import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService; | ||
| 15 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||
| 16 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||
| 17 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO.OrderItem; | ||
| 18 | +import org.springframework.core.annotation.Order; | ||
| 19 | +import org.springframework.stereotype.Component; | ||
| 20 | + | ||
| 21 | +import javax.annotation.Resource; | ||
| 22 | +import java.util.HashMap; | ||
| 23 | +import java.util.List; | ||
| 24 | +import java.util.Map; | ||
| 25 | +import java.util.Set; | ||
| 26 | + | ||
| 27 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | ||
| 28 | + | ||
| 29 | +/** | ||
| 30 | + * 运费的 {@link TradePriceCalculator} 实现类 | ||
| 31 | + * | ||
| 32 | + * @author jason | ||
| 33 | + */ | ||
| 34 | +@Component | ||
| 35 | +@Order(TradePriceCalculator.ORDER_DELIVERY) | ||
| 36 | +public class TradeDeliveryPriceCalculator implements TradePriceCalculator { | ||
| 37 | + | ||
| 38 | + @Resource | ||
| 39 | + private AddressApi addressApi; | ||
| 40 | + @Resource | ||
| 41 | + private ProductSkuApi productSkuApi; | ||
| 42 | + | ||
| 43 | + @Resource | ||
| 44 | + private DeliveryExpressTemplateService deliveryExpressTemplateService; | ||
| 45 | + // TODO @jason:走 Service 哈。Mapper 只允许自己的 Service 调用,保护好数据结构; | ||
| 46 | + @Resource | ||
| 47 | + private DeliveryExpressTemplateChargeMapper templateChargeMapper; | ||
| 48 | + @Resource | ||
| 49 | + private DeliveryExpressTemplateFreeMapper templateFreeMapper; | ||
| 50 | + | ||
| 51 | + @Override | ||
| 52 | + public void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result) { | ||
| 53 | + // 1.1 判断配送方式 | ||
| 54 | + if (param.getDeliveryType() == null || DeliveryTypeEnum.PICK_UP.getMode().equals(param.getDeliveryType())) { | ||
| 55 | + return; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + if (param.getTemplateId() == null || param.getAddressId() == null) { | ||
| 59 | + return; | ||
| 60 | + } | ||
| 61 | + // 1.2 校验运费模板是否存在 | ||
| 62 | + DeliveryExpressTemplateDO template = deliveryExpressTemplateService.validateDeliveryExpressTemplate(param.getTemplateId()); | ||
| 63 | + | ||
| 64 | + // 得到包邮配置 | ||
| 65 | + List<DeliveryExpressTemplateFreeDO> expressTemplateFreeList = templateFreeMapper.selectListByTemplateId(template.getId()); | ||
| 66 | + Map<Integer, DeliveryExpressTemplateFreeDO> areaTemplateFreeMap = new HashMap<>(); | ||
| 67 | + expressTemplateFreeList.forEach(item -> { | ||
| 68 | + for (Integer areaId : item.getAreaIds()) { | ||
| 69 | + // TODO 需要保证 areaId 不能重复 | ||
| 70 | + if (!areaTemplateFreeMap.containsKey(areaId)) { | ||
| 71 | + areaTemplateFreeMap.put(areaId, item); | ||
| 72 | + } | ||
| 73 | + } | ||
| 74 | + }); | ||
| 75 | + // 得到快递运费配置 | ||
| 76 | + List<DeliveryExpressTemplateChargeDO> expressTemplateChargeList = templateChargeMapper.selectListByTemplateId(template.getId()); | ||
| 77 | + Map<Integer, DeliveryExpressTemplateChargeDO> areaTemplateChargeMap = new HashMap<>(); | ||
| 78 | + expressTemplateChargeList.forEach(item -> { | ||
| 79 | + for (Integer areaId : item.getAreaIds()) { | ||
| 80 | + // areaId 不能重复 | ||
| 81 | + if (!areaTemplateChargeMap.containsKey(areaId)) { | ||
| 82 | + areaTemplateChargeMap.put(areaId, item); | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | + }); | ||
| 86 | + // 得到收件地址区域 | ||
| 87 | + AddressRespDTO address = addressApi.getAddress(param.getAddressId(), param.getUserId()); | ||
| 88 | + // 1.3 计算快递费用 | ||
| 89 | + calculateDeliveryPrice(address.getAreaId(), template.getChargeMode(), | ||
| 90 | + areaTemplateFreeMap, areaTemplateChargeMap, result); | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + /** | ||
| 94 | + * 校验订单是否满足包邮条件 | ||
| 95 | + * | ||
| 96 | + * @param receiverAreaId 收件人地区的区域编号 | ||
| 97 | + * @param chargeMode 配送计费方式 | ||
| 98 | + * @param areaTemplateFreeMap 运费模板包邮区域设置 Map | ||
| 99 | + * @param areaTemplateChargeMap 运费模板快递费用设置 Map | ||
| 100 | + */ | ||
| 101 | + private void calculateDeliveryPrice(Integer receiverAreaId, | ||
| 102 | + Integer chargeMode, | ||
| 103 | + Map<Integer, DeliveryExpressTemplateFreeDO> areaTemplateFreeMap, | ||
| 104 | + Map<Integer, DeliveryExpressTemplateChargeDO> areaTemplateChargeMap, | ||
| 105 | + TradePriceCalculateRespBO result) { | ||
| 106 | + // 过滤出已选中的商品SKU | ||
| 107 | + List<OrderItem> selectedItem = filterList(result.getItems(), OrderItem::getSelected); | ||
| 108 | + Set<Long> skuIds = convertSet(selectedItem, OrderItem::getSkuId); | ||
| 109 | + // 得到SKU 详情。得到 重量体积 | ||
| 110 | + Map<Long, ProductSkuRespDTO> skuRespMap = convertMap(productSkuApi.getSkuList(skuIds), ProductSkuRespDTO::getId); | ||
| 111 | + // 一个 spuId 可能对应多条订单商品 SKU | ||
| 112 | + // TODO @jason:得确认下,按照 sku 算,还是 spu 算; | ||
| 113 | + Map<Long, List<OrderItem>> spuIdItemMap = convertMultiMap(selectedItem, OrderItem::getSpuId); | ||
| 114 | + // 依次计算每个 SPU 的快递运费 | ||
| 115 | + for (Map.Entry<Long, List<OrderItem>> entry : spuIdItemMap.entrySet()) { | ||
| 116 | + List<OrderItem> orderItems = entry.getValue(); | ||
| 117 | + // 总件数, 总金额, 总重量, 总体积 | ||
| 118 | + int totalCount = 0; | ||
| 119 | + int totalPrice = 0; | ||
| 120 | + double totalWeight = 0; | ||
| 121 | + double totalVolume = 0; | ||
| 122 | + for (OrderItem orderItem : orderItems) { | ||
| 123 | + totalCount += orderItem.getCount(); | ||
| 124 | + totalPrice += orderItem.getPrice(); // TODO jason:应该按照 payPrice? | ||
| 125 | + ProductSkuRespDTO skuResp = skuRespMap.get(orderItem.getSkuId()); | ||
| 126 | + if (skuResp != null) { | ||
| 127 | + totalWeight = totalWeight + skuResp.getWeight(); // TODO @jason:* 数量 | ||
| 128 | + totalVolume = totalVolume + skuResp.getVolume(); | ||
| 129 | + } | ||
| 130 | + } | ||
| 131 | + // 优先判断是否包邮. 如果包邮不计算快递运费 | ||
| 132 | + if (areaTemplateFreeMap.containsKey(receiverAreaId) && | ||
| 133 | + checkExpressFree(chargeMode, totalCount, totalWeight, | ||
| 134 | + totalVolume, totalPrice, areaTemplateFreeMap.get(receiverAreaId))) { | ||
| 135 | + continue; | ||
| 136 | + } | ||
| 137 | + // 计算快递运费 | ||
| 138 | + // TODO @jason:貌似也可以抽成 checkExpressFree 类似方法 | ||
| 139 | + if (areaTemplateChargeMap.containsKey(receiverAreaId)) { | ||
| 140 | + DeliveryExpressTemplateChargeDO templateCharge = areaTemplateChargeMap.get(receiverAreaId); | ||
| 141 | + DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); | ||
| 142 | + switch (chargeModeEnum) { | ||
| 143 | + case PIECE: { | ||
| 144 | + calculateExpressFeeBySpu(totalCount, templateCharge, orderItems); | ||
| 145 | + break; | ||
| 146 | + } | ||
| 147 | + case WEIGHT: { | ||
| 148 | + calculateExpressFeeBySpu(totalWeight, templateCharge, orderItems); | ||
| 149 | + break; | ||
| 150 | + } | ||
| 151 | + case VOLUME: { | ||
| 152 | + calculateExpressFeeBySpu(totalVolume, templateCharge, orderItems); | ||
| 153 | + break; | ||
| 154 | + } | ||
| 155 | + } | ||
| 156 | + } | ||
| 157 | + } | ||
| 158 | + TradePriceCalculatorHelper.recountAllPrice(result); | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + /** | ||
| 162 | + * 按 spu 来计算快递费用 | ||
| 163 | + * | ||
| 164 | + * @param total 总件数/总重量/总体积 | ||
| 165 | + * @param templateCharge 快递运费配置 | ||
| 166 | + * @param orderItems SKU 商品项目 | ||
| 167 | + */ | ||
| 168 | + private void calculateExpressFeeBySpu(double total, DeliveryExpressTemplateChargeDO templateCharge, List<OrderItem> orderItems) { | ||
| 169 | + int deliveryPrice; | ||
| 170 | + if (total <= templateCharge.getStartCount()) { | ||
| 171 | + deliveryPrice = templateCharge.getStartPrice(); | ||
| 172 | + } else { | ||
| 173 | + double remainWeight = total - templateCharge.getStartCount(); | ||
| 174 | + // 剩余重量/ 续件 = 续件的次数. 向上取整 | ||
| 175 | + int extraNum = (int) Math.ceil(remainWeight / templateCharge.getExtraCount()); | ||
| 176 | + int extraPrice = templateCharge.getExtraPrice() * extraNum; | ||
| 177 | + deliveryPrice = templateCharge.getStartPrice() + extraPrice; | ||
| 178 | + } | ||
| 179 | + // TODO @芋艿 分摊快递费用到 SKU. 是不是搞复杂了; | ||
| 180 | + // TODO @jason:因为退费的时候,可能按照 SKU 考虑退费金额 | ||
| 181 | + divideDeliveryPrice(deliveryPrice, orderItems); | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + /** | ||
| 185 | + * 快递运费分摊到每个 SKU 商品上 | ||
| 186 | + * | ||
| 187 | + * @param deliveryPrice 快递运费 | ||
| 188 | + * @param orderItems SKU 商品 | ||
| 189 | + */ | ||
| 190 | + private void divideDeliveryPrice(int deliveryPrice, List<OrderItem> orderItems) { | ||
| 191 | + int dividePrice = deliveryPrice / orderItems.size(); | ||
| 192 | + for (OrderItem item : orderItems) { | ||
| 193 | + // 更新快递运费 | ||
| 194 | + item.setDeliveryPrice(dividePrice); | ||
| 195 | + } | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + /** | ||
| 199 | + * 检查是否包邮 | ||
| 200 | + * | ||
| 201 | + * @param chargeMode 配送计费方式 | ||
| 202 | + * @param totalCount 总件数 | ||
| 203 | + * @param totalWeight 总重量 | ||
| 204 | + * @param totalVolume 总体积 | ||
| 205 | + * @param totalPrice 总金额 | ||
| 206 | + * @param templateFree 包邮配置 | ||
| 207 | + */ | ||
| 208 | + private boolean checkExpressFree(Integer chargeMode, int totalCount, double totalWeight, | ||
| 209 | + double totalVolume, int totalPrice, DeliveryExpressTemplateFreeDO templateFree) { | ||
| 210 | + DeliveryExpressChargeModeEnum chargeModeEnum = DeliveryExpressChargeModeEnum.valueOf(chargeMode); | ||
| 211 | + switch (chargeModeEnum) { | ||
| 212 | + case PIECE: | ||
| 213 | + // 两个条件都满足才包邮 | ||
| 214 | + if (totalCount >= templateFree.getFreeCount() && totalPrice >= templateFree.getFreePrice()) { | ||
| 215 | + return true; | ||
| 216 | + } | ||
| 217 | + break; | ||
| 218 | + case WEIGHT: | ||
| 219 | + // freeCount 是不是应该是 double ?? | ||
| 220 | + if (totalWeight >= templateFree.getFreeCount() | ||
| 221 | + && totalPrice >= templateFree.getFreePrice()) { | ||
| 222 | + return true; | ||
| 223 | + } | ||
| 224 | + break; | ||
| 225 | + case VOLUME: | ||
| 226 | + if (totalVolume >= templateFree.getFreeCount() | ||
| 227 | + && totalPrice >= templateFree.getFreePrice()) { | ||
| 228 | + return true; | ||
| 229 | + } | ||
| 230 | + break; | ||
| 231 | + } | ||
| 232 | + return false; | ||
| 233 | + } | ||
| 234 | +} |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculator.java
| @@ -53,10 +53,13 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato | @@ -53,10 +53,13 @@ public class TradeDiscountActivityPriceCalculator implements TradePriceCalculato | ||
| 53 | Integer newDiscountPrice = orderItem.getPayPrice() - newPayPrice; | 53 | Integer newDiscountPrice = orderItem.getPayPrice() - newPayPrice; |
| 54 | 54 | ||
| 55 | // 3.1 记录优惠明细 | 55 | // 3.1 记录优惠明细 |
| 56 | - TradePriceCalculatorHelper.addPromotion(result, orderItem, | ||
| 57 | - discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), | ||
| 58 | - StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)), | ||
| 59 | - newDiscountPrice); | 56 | + if (orderItem.getSelected()) { |
| 57 | + // 注意,只有在选中的情况下,才会记录到优惠明细。否则仅仅是更新 SKU 优惠金额,用于展示 | ||
| 58 | + TradePriceCalculatorHelper.addPromotion(result, orderItem, | ||
| 59 | + discountProduct.getActivityId(), discountProduct.getActivityName(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType(), | ||
| 60 | + StrUtil.format("限时折扣:省 {} 元", formatPrice(newDiscountPrice)), | ||
| 61 | + newDiscountPrice); | ||
| 62 | + } | ||
| 60 | // 3.2 更新 SKU 优惠金额 | 63 | // 3.2 更新 SKU 优惠金额 |
| 61 | orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice); | 64 | orderItem.setDiscountPrice(orderItem.getDiscountPrice() + newDiscountPrice); |
| 62 | TradePriceCalculatorHelper.recountPayPrice(orderItem); | 65 | TradePriceCalculatorHelper.recountPayPrice(orderItem); |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculator.java
| @@ -13,6 +13,12 @@ public interface TradePriceCalculator { | @@ -13,6 +13,12 @@ public interface TradePriceCalculator { | ||
| 13 | int ORDER_DISCOUNT_ACTIVITY = 10; | 13 | int ORDER_DISCOUNT_ACTIVITY = 10; |
| 14 | int ORDER_REWARD_ACTIVITY = 20; | 14 | int ORDER_REWARD_ACTIVITY = 20; |
| 15 | int ORDER_COUPON = 30; | 15 | int ORDER_COUPON = 30; |
| 16 | + /** | ||
| 17 | + * 快递运费的计算 | ||
| 18 | + * | ||
| 19 | + * 放在各种营销活动、优惠劵后面 TODO | ||
| 20 | + */ | ||
| 21 | + int ORDER_DELIVERY = 40; | ||
| 16 | 22 | ||
| 17 | void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result); | 23 | void calculate(TradePriceCalculateReqBO param, TradePriceCalculateRespBO result); |
| 18 | 24 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradePriceCalculatorHelper.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.trade.service.price.calculator; | ||
| 3 | import cn.hutool.core.lang.Assert; | 3 | import cn.hutool.core.lang.Assert; |
| 4 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 4 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 5 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | 5 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 6 | +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | ||
| 6 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | 7 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; |
| 7 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | 8 | import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; |
| 8 | 9 | ||
| @@ -24,25 +25,42 @@ import static java.util.Collections.singletonList; | @@ -24,25 +25,42 @@ import static java.util.Collections.singletonList; | ||
| 24 | public class TradePriceCalculatorHelper { | 25 | public class TradePriceCalculatorHelper { |
| 25 | 26 | ||
| 26 | public static TradePriceCalculateRespBO buildCalculateResp(TradePriceCalculateReqBO param, | 27 | public static TradePriceCalculateRespBO buildCalculateResp(TradePriceCalculateReqBO param, |
| 27 | - List<ProductSkuRespDTO> skuList) { | 28 | + List<ProductSpuRespDTO> spuList, List<ProductSkuRespDTO> skuList) { |
| 28 | // 创建 PriceCalculateRespDTO 对象 | 29 | // 创建 PriceCalculateRespDTO 对象 |
| 29 | TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); | 30 | TradePriceCalculateRespBO result = new TradePriceCalculateRespBO(); |
| 30 | - result.setOrderType(param.getOrderType()); | 31 | + result.setType(param.getType()); |
| 32 | + result.setPromotions(new ArrayList<>()); | ||
| 33 | + | ||
| 31 | // 创建它的 OrderItem 属性 | 34 | // 创建它的 OrderItem 属性 |
| 32 | - Map<Long, TradePriceCalculateReqBO.Item> skuItemMap = convertMap(param.getItems(), | ||
| 33 | - TradePriceCalculateReqBO.Item::getSkuId); | ||
| 34 | - result.setItems(new ArrayList<>(skuItemMap.size())); | ||
| 35 | - skuList.forEach(sku -> { | ||
| 36 | - TradePriceCalculateReqBO.Item skuItem = skuItemMap.get(sku.getId()); | ||
| 37 | - TradePriceCalculateRespBO.OrderItem orderItem = new TradePriceCalculateRespBO.OrderItem() | ||
| 38 | - // SKU 字段 | ||
| 39 | - .setSpuId(sku.getSpuId()).setSkuId(sku.getId()) | ||
| 40 | - .setCount(skuItem.getCount()).setCartId(skuItem.getCartId()).setSelected(skuItem.getSelected()) | ||
| 41 | - // 价格字段 | ||
| 42 | - .setPrice(sku.getPrice()).setPayPrice(sku.getPrice() * skuItem.getCount()) | ||
| 43 | - .setDiscountPrice(0).setDeliveryPrice(0).setCouponPrice(0).setPointPrice(0); | 35 | + result.setItems(new ArrayList<>(param.getItems().size())); |
| 36 | + Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId); | ||
| 37 | + Map<Long, ProductSkuRespDTO> skuMap = convertMap(skuList, ProductSkuRespDTO::getId); | ||
| 38 | + param.getItems().forEach(item -> { | ||
| 39 | + ProductSkuRespDTO sku = skuMap.get(item.getSkuId()); | ||
| 40 | + if (sku == null) { | ||
| 41 | + return; | ||
| 42 | + } | ||
| 43 | + ProductSpuRespDTO spu = spuMap.get(sku.getSpuId()); | ||
| 44 | + if (spu == null) { | ||
| 45 | + return; | ||
| 46 | + } | ||
| 47 | + // 商品项 | ||
| 48 | + TradePriceCalculateRespBO.OrderItem orderItem = new TradePriceCalculateRespBO.OrderItem(); | ||
| 44 | result.getItems().add(orderItem); | 49 | result.getItems().add(orderItem); |
| 50 | + orderItem.setSpuId(sku.getSpuId()).setSkuId(sku.getId()) | ||
| 51 | + .setCount(item.getCount()).setCartId(item.getCartId()).setSelected(item.getSelected()); | ||
| 52 | + // sku 价格 | ||
| 53 | + orderItem.setPrice(sku.getPrice()).setPayPrice(sku.getPrice() * item.getCount()) | ||
| 54 | + .setDiscountPrice(0).setDeliveryPrice(0).setCouponPrice(0).setPointPrice(0); | ||
| 55 | + // sku 信息 | ||
| 56 | + orderItem.setPicUrl(sku.getPicUrl()).setProperties(sku.getProperties()); | ||
| 57 | + // spu 信息 | ||
| 58 | + orderItem.setSpuName(spu.getName()).setCategoryId(spu.getCategoryId()); | ||
| 59 | + if (orderItem.getPicUrl() == null) { | ||
| 60 | + orderItem.setPicUrl(spu.getPicUrl()); | ||
| 61 | + } | ||
| 45 | }); | 62 | }); |
| 63 | + | ||
| 46 | // 创建它的 Price 属性 | 64 | // 创建它的 Price 属性 |
| 47 | result.setPrice(new TradePriceCalculateRespBO.Price()); | 65 | result.setPrice(new TradePriceCalculateRespBO.Price()); |
| 48 | recountAllPrice(result); | 66 | recountAllPrice(result); |
| @@ -87,6 +105,31 @@ public class TradePriceCalculatorHelper { | @@ -87,6 +105,31 @@ public class TradePriceCalculatorHelper { | ||
| 87 | } | 105 | } |
| 88 | 106 | ||
| 89 | /** | 107 | /** |
| 108 | + * 重新计算每个订单项的支付金额 | ||
| 109 | + * | ||
| 110 | + * 【目前主要是单测使用】 | ||
| 111 | + * | ||
| 112 | + * @param orderItems 订单项数组 | ||
| 113 | + */ | ||
| 114 | + public static void recountPayPrice(List<TradePriceCalculateRespBO.OrderItem> orderItems) { | ||
| 115 | + orderItems.forEach(orderItem -> { | ||
| 116 | + if (orderItem.getDiscountPrice() == null) { | ||
| 117 | + orderItem.setDiscountPrice(0); | ||
| 118 | + } | ||
| 119 | + if (orderItem.getDeliveryPrice() == null) { | ||
| 120 | + orderItem.setDeliveryPrice(0); | ||
| 121 | + } | ||
| 122 | + if (orderItem.getCouponPrice() == null) { | ||
| 123 | + orderItem.setCouponPrice(0); | ||
| 124 | + } | ||
| 125 | + if (orderItem.getPointPrice() == null) { | ||
| 126 | + orderItem.setPointPrice(0); | ||
| 127 | + } | ||
| 128 | + recountPayPrice(orderItem); | ||
| 129 | + }); | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + /** | ||
| 90 | * 计算已选中的订单项,总支付金额 | 133 | * 计算已选中的订单项,总支付金额 |
| 91 | * | 134 | * |
| 92 | * @param orderItems 订单项数组 | 135 | * @param orderItems 订单项数组 |
| @@ -94,7 +137,7 @@ public class TradePriceCalculatorHelper { | @@ -94,7 +137,7 @@ public class TradePriceCalculatorHelper { | ||
| 94 | */ | 137 | */ |
| 95 | public static Integer calculateTotalPayPrice(List<TradePriceCalculateRespBO.OrderItem> orderItems) { | 138 | public static Integer calculateTotalPayPrice(List<TradePriceCalculateRespBO.OrderItem> orderItems) { |
| 96 | return getSumValue(orderItems, | 139 | return getSumValue(orderItems, |
| 97 | - orderItem -> orderItem.getSelected() ? orderItem.getPayPrice() : 0, // 未选中的情况下,不计算支付金额 | 140 | + orderItem -> orderItem.getSelected() ? orderItem.getPayPrice() : 0, // 未选中的情况下,不计算支付金额 |
| 98 | Integer::sum); | 141 | Integer::sum); |
| 99 | } | 142 | } |
| 100 | 143 |
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculator.java
| @@ -53,6 +53,9 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator | @@ -53,6 +53,9 @@ public class TradeRewardActivityPriceCalculator implements TradePriceCalculator | ||
| 53 | // 1.2 获得最大匹配的满减送活动的规则 | 53 | // 1.2 获得最大匹配的满减送活动的规则 |
| 54 | RewardActivityMatchRespDTO.Rule rule = getMaxMatchRewardActivityRule(rewardActivity, orderItems); | 54 | RewardActivityMatchRespDTO.Rule rule = getMaxMatchRewardActivityRule(rewardActivity, orderItems); |
| 55 | if (rule == null) { | 55 | if (rule == null) { |
| 56 | + TradePriceCalculatorHelper.addNotMatchPromotion(result, orderItems, | ||
| 57 | + rewardActivity.getId(), rewardActivity.getName(), PromotionTypeEnum.REWARD_ACTIVITY.getType(), | ||
| 58 | + getRewardActivityNotMeetTip(rewardActivity)); | ||
| 56 | return; | 59 | return; |
| 57 | } | 60 | } |
| 58 | 61 |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/aftersale/TradeAfterSaleServiceTest.java
| @@ -69,8 +69,7 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest { | @@ -69,8 +69,7 @@ public class TradeAfterSaleServiceTest extends BaseDbUnitTest { | ||
| 69 | .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png")); | 69 | .setApplyPicUrls(asList("https://www.baidu.com/1.png", "https://www.baidu.com/2.png")); |
| 70 | // mock 方法(交易订单项) | 70 | // mock 方法(交易订单项) |
| 71 | TradeOrderItemDO orderItem = randomPojo(TradeOrderItemDO.class, o -> { | 71 | TradeOrderItemDO orderItem = randomPojo(TradeOrderItemDO.class, o -> { |
| 72 | - //o.setOrderId(111L).setUserId(userId).setOrderDividePrice(200); TODO DO 中没有 orderDividePrice 属性 | ||
| 73 | - o.setOrderId(111L).setUserId(userId); | 72 | + o.setOrderId(111L).setUserId(userId).setPayPrice(200); |
| 74 | o.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); | 73 | o.setAfterSaleStatus(TradeOrderItemAfterSaleStatusEnum.NONE.getStatus()); |
| 75 | }); | 74 | }); |
| 76 | when(tradeOrderService.getOrderItem(eq(1024L), eq(1L))) | 75 | when(tradeOrderService.getOrderItem(eq(1024L), eq(1L))) |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/order/TradeOrderServiceTest.java
| @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.member.api.user.MemberUserApi; | ||
| 8 | import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; | 8 | import cn.iocoder.yudao.module.pay.api.order.PayOrderApi; |
| 9 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; | 9 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; |
| 10 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | 10 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 11 | +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; | ||
| 11 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | 12 | import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; |
| 12 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | 13 | import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; |
| 13 | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | 14 | import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; |
| @@ -101,10 +102,10 @@ public class TradeOrderServiceTest extends BaseDbUnitTest { | @@ -101,10 +102,10 @@ public class TradeOrderServiceTest extends BaseDbUnitTest { | ||
| 101 | // mock 方法(商品 SKU 检查) | 102 | // mock 方法(商品 SKU 检查) |
| 102 | ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L) | 103 | ProductSkuRespDTO sku01 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(1L).setSpuId(11L) |
| 103 | .setPrice(50).setStock(100) | 104 | .setPrice(50).setStock(100) |
| 104 | - .setProperties(singletonList(new ProductSkuRespDTO.Property().setPropertyId(111L).setValueId(222L)))); | 105 | + .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(111L).setValueId(222L)))); |
| 105 | ProductSkuRespDTO sku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(2L).setSpuId(21L) | 106 | ProductSkuRespDTO sku02 = randomPojo(ProductSkuRespDTO.class, o -> o.setId(2L).setSpuId(21L) |
| 106 | .setPrice(20).setStock(50)) | 107 | .setPrice(20).setStock(50)) |
| 107 | - .setProperties(singletonList(new ProductSkuRespDTO.Property().setPropertyId(333L).setValueId(444L))); | 108 | + .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(333L).setValueId(444L))); |
| 108 | when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02)); | 109 | when(productSkuApi.getSkuList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(sku01, sku02)); |
| 109 | // mock 方法(商品 SPU 检查) | 110 | // mock 方法(商品 SPU 检查) |
| 110 | ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L) | 111 | ProductSpuRespDTO spu01 = randomPojo(ProductSpuRespDTO.class, o -> o.setId(11L) |
| @@ -114,7 +115,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest { | @@ -114,7 +115,7 @@ public class TradeOrderServiceTest extends BaseDbUnitTest { | ||
| 114 | when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02)); | 115 | when(productSpuApi.getSpuList(eq(asSet(11L, 21L)))).thenReturn(Arrays.asList(spu01, spu02)); |
| 115 | // mock 方法(用户收件地址的校验) | 116 | // mock 方法(用户收件地址的校验) |
| 116 | AddressRespDTO addressRespDTO = new AddressRespDTO().setId(10L).setUserId(userId).setName("芋艿") | 117 | AddressRespDTO addressRespDTO = new AddressRespDTO().setId(10L).setUserId(userId).setName("芋艿") |
| 117 | - .setMobile("15601691300").setAreaId(3306L).setPostCode("85757").setDetailAddress("土豆村"); | 118 | + .setMobile("15601691300").setAreaId(3306).setPostCode("85757").setDetailAddress("土豆村"); |
| 118 | when(addressApi.getAddress(eq(10L), eq(userId))).thenReturn(addressRespDTO); | 119 | when(addressApi.getAddress(eq(10L), eq(userId))).thenReturn(addressRespDTO); |
| 119 | // mock 方法(价格计算) | 120 | // mock 方法(价格计算) |
| 120 | PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem() | 121 | PriceCalculateRespDTO.OrderItem priceOrderItem01 = new PriceCalculateRespDTO.OrderItem() |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/TradePriceServiceImplTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | ||
| 4 | +import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO; | ||
| 5 | +import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi; | ||
| 6 | +import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO; | ||
| 7 | +import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; | ||
| 8 | +import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; | ||
| 9 | +import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; | ||
| 10 | +import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum; | ||
| 11 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||
| 12 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||
| 13 | +import cn.iocoder.yudao.module.trade.service.price.calculator.TradePriceCalculator; | ||
| 14 | +import org.junit.jupiter.api.Test; | ||
| 15 | +import org.mockito.InjectMocks; | ||
| 16 | +import org.mockito.Mock; | ||
| 17 | +import org.mockito.Mockito; | ||
| 18 | + | ||
| 19 | +import java.util.Arrays; | ||
| 20 | +import java.util.List; | ||
| 21 | + | ||
| 22 | +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; | ||
| 23 | +import static java.util.Collections.singletonList; | ||
| 24 | +import static org.junit.jupiter.api.Assertions.*; | ||
| 25 | +import static org.mockito.Mockito.when; | ||
| 26 | + | ||
| 27 | +/** | ||
| 28 | + * {@link TradePriceServiceImpl} 的单元测试 | ||
| 29 | + * | ||
| 30 | + * @author 芋道源码 | ||
| 31 | + */ | ||
| 32 | +public class TradePriceServiceImplTest extends BaseMockitoUnitTest { | ||
| 33 | + | ||
| 34 | + @InjectMocks | ||
| 35 | + private TradePriceServiceImpl tradePriceService; | ||
| 36 | + | ||
| 37 | + @Mock | ||
| 38 | + private ProductSkuApi productSkuApi; | ||
| 39 | + @Mock | ||
| 40 | + private ProductSpuApi productSpuApi; | ||
| 41 | + @Mock | ||
| 42 | + private List<TradePriceCalculator> priceCalculators; | ||
| 43 | + | ||
| 44 | + @Test | ||
| 45 | + public void testCalculatePrice() { | ||
| 46 | + // 准备参数 | ||
| 47 | + TradePriceCalculateReqBO calculateReqBO = new TradePriceCalculateReqBO() | ||
| 48 | + .setType(TradeOrderTypeEnum.NORMAL.getType()).setUserId(10L) | ||
| 49 | + .setCouponId(20L).setAddressId(30L) | ||
| 50 | + .setItems(Arrays.asList( | ||
| 51 | + new TradePriceCalculateReqBO.Item().setSkuId(100L).setCount(1).setSelected(true), | ||
| 52 | + new TradePriceCalculateReqBO.Item().setSkuId(200L).setCount(3).setSelected(true), | ||
| 53 | + new TradePriceCalculateReqBO.Item().setSkuId(300L).setCount(6).setCartId(233L).setSelected(false) | ||
| 54 | + )); | ||
| 55 | + // mock 方法 | ||
| 56 | + List<ProductSkuRespDTO> skuList = Arrays.asList( | ||
| 57 | + new ProductSkuRespDTO().setId(100L).setStock(500).setPrice(1000).setPicUrl("https://t.cn/1.png").setSpuId(1001L) | ||
| 58 | + .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(1L).setPropertyName("颜色") | ||
| 59 | + .setValueId(2L).setValueName("红色"))), | ||
| 60 | + new ProductSkuRespDTO().setId(200L).setStock(400).setPrice(2000).setPicUrl("https://t.cn/2.png").setSpuId(1001L) | ||
| 61 | + .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(1L).setPropertyName("颜色") | ||
| 62 | + .setValueId(3L).setValueName("黄色"))), | ||
| 63 | + new ProductSkuRespDTO().setId(300L).setStock(600).setPrice(3000).setPicUrl("https://t.cn/3.png").setSpuId(1001L) | ||
| 64 | + .setProperties(singletonList(new ProductPropertyValueDetailRespDTO().setPropertyId(1L).setPropertyName("颜色") | ||
| 65 | + .setValueId(4L).setValueName("黑色"))) | ||
| 66 | + ); | ||
| 67 | + when(productSkuApi.getSkuList(Mockito.eq(asSet(100L, 200L, 300L)))).thenReturn(skuList); | ||
| 68 | + when(productSpuApi.getSpuList(Mockito.eq(asSet(1001L)))) | ||
| 69 | + .thenReturn(singletonList(new ProductSpuRespDTO().setId(1001L).setName("小菜").setCategoryId(666L) | ||
| 70 | + .setStatus(ProductSpuStatusEnum.ENABLE.getStatus()))); | ||
| 71 | + | ||
| 72 | + // 调用 | ||
| 73 | + TradePriceCalculateRespBO calculateRespBO = tradePriceService.calculatePrice(calculateReqBO); | ||
| 74 | + // 断言 | ||
| 75 | + assertEquals(TradeOrderTypeEnum.NORMAL.getType(), calculateRespBO.getType()); | ||
| 76 | + assertEquals(0, calculateRespBO.getPromotions().size()); | ||
| 77 | + assertNull(calculateRespBO.getCouponId()); | ||
| 78 | + // 断言:订单价格 | ||
| 79 | + assertEquals(7000, calculateRespBO.getPrice().getTotalPrice()); | ||
| 80 | + assertEquals(0, calculateRespBO.getPrice().getDiscountPrice()); | ||
| 81 | + assertEquals(0, calculateRespBO.getPrice().getDeliveryPrice()); | ||
| 82 | + assertEquals(0, calculateRespBO.getPrice().getCouponPrice()); | ||
| 83 | + assertEquals(0, calculateRespBO.getPrice().getPointPrice()); | ||
| 84 | + assertEquals(7000, calculateRespBO.getPrice().getPayPrice()); | ||
| 85 | + // 断言:SKU 1 | ||
| 86 | + assertEquals(1001L, calculateRespBO.getItems().get(0).getSpuId()); | ||
| 87 | + assertEquals(100L, calculateRespBO.getItems().get(0).getSkuId()); | ||
| 88 | + assertEquals(1, calculateRespBO.getItems().get(0).getCount()); | ||
| 89 | + assertNull(calculateRespBO.getItems().get(0).getCartId()); | ||
| 90 | + assertTrue(calculateRespBO.getItems().get(0).getSelected()); | ||
| 91 | + assertEquals(1000, calculateRespBO.getItems().get(0).getPrice()); | ||
| 92 | + assertEquals(0, calculateRespBO.getItems().get(0).getDiscountPrice()); | ||
| 93 | + assertEquals(0, calculateRespBO.getItems().get(0).getDeliveryPrice()); | ||
| 94 | + assertEquals(0, calculateRespBO.getItems().get(0).getCouponPrice()); | ||
| 95 | + assertEquals(0, calculateRespBO.getItems().get(0).getPointPrice()); | ||
| 96 | + assertEquals(1000, calculateRespBO.getItems().get(0).getPayPrice()); | ||
| 97 | + assertEquals("小菜", calculateRespBO.getItems().get(0).getSpuName()); | ||
| 98 | + assertEquals("https://t.cn/1.png", calculateRespBO.getItems().get(0).getPicUrl()); | ||
| 99 | + assertEquals(666L, calculateRespBO.getItems().get(0).getCategoryId()); | ||
| 100 | + assertEquals(skuList.get(0).getProperties(), calculateRespBO.getItems().get(0).getProperties()); | ||
| 101 | + // 断言:SKU 2 | ||
| 102 | + assertEquals(1001L, calculateRespBO.getItems().get(1).getSpuId()); | ||
| 103 | + assertEquals(200L, calculateRespBO.getItems().get(1).getSkuId()); | ||
| 104 | + assertEquals(3, calculateRespBO.getItems().get(1).getCount()); | ||
| 105 | + assertNull(calculateRespBO.getItems().get(1).getCartId()); | ||
| 106 | + assertTrue(calculateRespBO.getItems().get(1).getSelected()); | ||
| 107 | + assertEquals(2000, calculateRespBO.getItems().get(1).getPrice()); | ||
| 108 | + assertEquals(0, calculateRespBO.getItems().get(1).getDiscountPrice()); | ||
| 109 | + assertEquals(0, calculateRespBO.getItems().get(1).getDeliveryPrice()); | ||
| 110 | + assertEquals(0, calculateRespBO.getItems().get(1).getCouponPrice()); | ||
| 111 | + assertEquals(0, calculateRespBO.getItems().get(1).getPointPrice()); | ||
| 112 | + assertEquals(6000, calculateRespBO.getItems().get(1).getPayPrice()); | ||
| 113 | + assertEquals("小菜", calculateRespBO.getItems().get(1).getSpuName()); | ||
| 114 | + assertEquals("https://t.cn/2.png", calculateRespBO.getItems().get(1).getPicUrl()); | ||
| 115 | + assertEquals(666L, calculateRespBO.getItems().get(1).getCategoryId()); | ||
| 116 | + assertEquals(skuList.get(1).getProperties(), calculateRespBO.getItems().get(1).getProperties()); | ||
| 117 | + // 断言:SKU 3 | ||
| 118 | + assertEquals(1001L, calculateRespBO.getItems().get(2).getSpuId()); | ||
| 119 | + assertEquals(300L, calculateRespBO.getItems().get(2).getSkuId()); | ||
| 120 | + assertEquals(6, calculateRespBO.getItems().get(2).getCount()); | ||
| 121 | + assertEquals(233L, calculateRespBO.getItems().get(2).getCartId()); | ||
| 122 | + assertFalse(calculateRespBO.getItems().get(2).getSelected()); | ||
| 123 | + assertEquals(3000, calculateRespBO.getItems().get(2).getPrice()); | ||
| 124 | + assertEquals(0, calculateRespBO.getItems().get(2).getDiscountPrice()); | ||
| 125 | + assertEquals(0, calculateRespBO.getItems().get(2).getDeliveryPrice()); | ||
| 126 | + assertEquals(0, calculateRespBO.getItems().get(2).getCouponPrice()); | ||
| 127 | + assertEquals(0, calculateRespBO.getItems().get(2).getPointPrice()); | ||
| 128 | + assertEquals(18000, calculateRespBO.getItems().get(2).getPayPrice()); | ||
| 129 | + assertEquals("小菜", calculateRespBO.getItems().get(2).getSpuName()); | ||
| 130 | + assertEquals("https://t.cn/3.png", calculateRespBO.getItems().get(2).getPicUrl()); | ||
| 131 | + assertEquals(666L, calculateRespBO.getItems().get(2).getCategoryId()); | ||
| 132 | + assertEquals(skuList.get(2).getProperties(), calculateRespBO.getItems().get(2).getProperties()); | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | +} |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeCouponPriceCalculatorTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | ||
| 4 | +import cn.iocoder.yudao.module.promotion.api.coupon.CouponApi; | ||
| 5 | +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponRespDTO; | ||
| 6 | +import cn.iocoder.yudao.module.promotion.api.coupon.dto.CouponValidReqDTO; | ||
| 7 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; | ||
| 8 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum; | ||
| 9 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | ||
| 10 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||
| 11 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||
| 12 | +import org.junit.jupiter.api.Test; | ||
| 13 | +import org.mockito.InjectMocks; | ||
| 14 | +import org.mockito.Mock; | ||
| 15 | + | ||
| 16 | +import java.util.ArrayList; | ||
| 17 | + | ||
| 18 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | ||
| 19 | +import static java.util.Arrays.asList; | ||
| 20 | +import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| 21 | +import static org.junit.jupiter.api.Assertions.assertTrue; | ||
| 22 | +import static org.mockito.ArgumentMatchers.eq; | ||
| 23 | +import static org.mockito.Mockito.when; | ||
| 24 | + | ||
| 25 | +/** | ||
| 26 | + * {@link TradeCouponPriceCalculator} 的单元测试类 | ||
| 27 | + * | ||
| 28 | + * @author 芋道源码 | ||
| 29 | + */ | ||
| 30 | +public class TradeCouponPriceCalculatorTest extends BaseMockitoUnitTest { | ||
| 31 | + | ||
| 32 | + @InjectMocks | ||
| 33 | + private TradeCouponPriceCalculator tradeCouponPriceCalculator; | ||
| 34 | + | ||
| 35 | + @Mock | ||
| 36 | + private CouponApi couponApi; | ||
| 37 | + | ||
| 38 | + @Test | ||
| 39 | + public void testCalculate() { | ||
| 40 | + // 准备参数 | ||
| 41 | + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() | ||
| 42 | + .setUserId(233L).setCouponId(1024L) | ||
| 43 | + .setItems(asList( | ||
| 44 | + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 匹配优惠劵 | ||
| 45 | + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 匹配优惠劵 | ||
| 46 | + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(true), // 不匹配优惠劵 | ||
| 47 | + new TradePriceCalculateReqBO.Item().setSkuId(40L).setCount(5).setSelected(false) // 匹配优惠劵,但是未选中 | ||
| 48 | + )); | ||
| 49 | + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() | ||
| 50 | + .setPrice(new TradePriceCalculateRespBO.Price()) | ||
| 51 | + .setPromotions(new ArrayList<>()) | ||
| 52 | + .setItems(asList( | ||
| 53 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) | ||
| 54 | + .setPrice(100).setSpuId(1L), | ||
| 55 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) | ||
| 56 | + .setPrice(50).setSpuId(2L), | ||
| 57 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(4).setSelected(true) | ||
| 58 | + .setPrice(30).setSpuId(3L), | ||
| 59 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(40L).setCount(5).setSelected(false) | ||
| 60 | + .setPrice(60).setSpuId(1L) | ||
| 61 | + )); | ||
| 62 | + // 保证价格被初始化上 | ||
| 63 | + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); | ||
| 64 | + TradePriceCalculatorHelper.recountAllPrice(result); | ||
| 65 | + | ||
| 66 | + // mock 方法(优惠劵 Coupon 信息) | ||
| 67 | + CouponRespDTO coupon = randomPojo(CouponRespDTO.class, o -> o.setId(1024L).setName("程序员节") | ||
| 68 | + .setProductScope(PromotionProductScopeEnum.SPU.getScope()).setProductSpuIds(asList(1L, 2L)) | ||
| 69 | + .setUsePrice(350).setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()) | ||
| 70 | + .setDiscountPercent(50).setDiscountLimitPrice(70)); | ||
| 71 | + when(couponApi.validateCoupon(eq(new CouponValidReqDTO().setId(1024L).setUserId(233L)))).thenReturn(coupon); | ||
| 72 | + | ||
| 73 | + // 调用 | ||
| 74 | + tradeCouponPriceCalculator.calculate(param, result); | ||
| 75 | + // 断言 | ||
| 76 | + assertEquals(result.getCouponId(), 1024L); | ||
| 77 | + // 断言:Price 部分 | ||
| 78 | + TradePriceCalculateRespBO.Price price = result.getPrice(); | ||
| 79 | + assertEquals(price.getTotalPrice(), 470); | ||
| 80 | + assertEquals(price.getDiscountPrice(), 0); | ||
| 81 | + assertEquals(price.getPointPrice(), 0); | ||
| 82 | + assertEquals(price.getDeliveryPrice(), 0); | ||
| 83 | + assertEquals(price.getCouponPrice(), 70); | ||
| 84 | + assertEquals(price.getPayPrice(), 400); | ||
| 85 | + // 断言:SKU 1 | ||
| 86 | + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); | ||
| 87 | + assertEquals(orderItem01.getSkuId(), 10L); | ||
| 88 | + assertEquals(orderItem01.getCount(), 2); | ||
| 89 | + assertEquals(orderItem01.getPrice(), 100); | ||
| 90 | + assertEquals(orderItem01.getDiscountPrice(), 0); | ||
| 91 | + assertEquals(orderItem01.getDeliveryPrice(), 0); | ||
| 92 | + assertEquals(orderItem01.getCouponPrice(), 40); | ||
| 93 | + assertEquals(orderItem01.getPointPrice(), 0); | ||
| 94 | + assertEquals(orderItem01.getPayPrice(), 160); | ||
| 95 | + // 断言:SKU 2 | ||
| 96 | + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); | ||
| 97 | + assertEquals(orderItem02.getSkuId(), 20L); | ||
| 98 | + assertEquals(orderItem02.getCount(), 3); | ||
| 99 | + assertEquals(orderItem02.getPrice(), 50); | ||
| 100 | + assertEquals(orderItem02.getDiscountPrice(), 0); | ||
| 101 | + assertEquals(orderItem02.getDeliveryPrice(), 0); | ||
| 102 | + assertEquals(orderItem02.getCouponPrice(), 30); | ||
| 103 | + assertEquals(orderItem02.getPointPrice(), 0); | ||
| 104 | + assertEquals(orderItem02.getPayPrice(), 120); | ||
| 105 | + // 断言:SKU 3 | ||
| 106 | + TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2); | ||
| 107 | + assertEquals(orderItem03.getSkuId(), 30L); | ||
| 108 | + assertEquals(orderItem03.getCount(), 4); | ||
| 109 | + assertEquals(orderItem03.getPrice(), 30); | ||
| 110 | + assertEquals(orderItem03.getDiscountPrice(), 0); | ||
| 111 | + assertEquals(orderItem03.getCouponPrice(), 0); | ||
| 112 | + assertEquals(orderItem03.getPointPrice(), 0); | ||
| 113 | + assertEquals(orderItem03.getPayPrice(), 120); | ||
| 114 | + // 断言:SKU 4 | ||
| 115 | + TradePriceCalculateRespBO.OrderItem orderItem04 = result.getItems().get(3); | ||
| 116 | + assertEquals(orderItem04.getSkuId(), 40L); | ||
| 117 | + assertEquals(orderItem04.getCount(), 5); | ||
| 118 | + assertEquals(orderItem04.getPrice(), 60); | ||
| 119 | + assertEquals(orderItem04.getDiscountPrice(), 0); | ||
| 120 | + assertEquals(orderItem04.getCouponPrice(), 0); | ||
| 121 | + assertEquals(orderItem04.getPointPrice(), 0); | ||
| 122 | + assertEquals(orderItem04.getPayPrice(), 300); | ||
| 123 | + // 断言:Promotion 部分 | ||
| 124 | + assertEquals(result.getPromotions().size(), 1); | ||
| 125 | + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); | ||
| 126 | + assertEquals(promotion01.getId(), 1024L); | ||
| 127 | + assertEquals(promotion01.getName(), "程序员节"); | ||
| 128 | + assertEquals(promotion01.getType(), PromotionTypeEnum.COUPON.getType()); | ||
| 129 | + assertEquals(promotion01.getTotalPrice(), 350); | ||
| 130 | + assertEquals(promotion01.getDiscountPrice(), 70); | ||
| 131 | + assertTrue(promotion01.getMatch()); | ||
| 132 | + assertEquals(promotion01.getDescription(), "优惠劵:省 0.70 元"); | ||
| 133 | + assertEquals(promotion01.getItems().size(), 2); | ||
| 134 | + TradePriceCalculateRespBO.PromotionItem promotionItem011 = promotion01.getItems().get(0); | ||
| 135 | + assertEquals(promotionItem011.getSkuId(), 10L); | ||
| 136 | + assertEquals(promotionItem011.getTotalPrice(), 200); | ||
| 137 | + assertEquals(promotionItem011.getDiscountPrice(), 40); | ||
| 138 | + TradePriceCalculateRespBO.PromotionItem promotionItem012 = promotion01.getItems().get(1); | ||
| 139 | + assertEquals(promotionItem012.getSkuId(), 20L); | ||
| 140 | + assertEquals(promotionItem012.getTotalPrice(), 150); | ||
| 141 | + assertEquals(promotionItem012.getDiscountPrice(), 30); | ||
| 142 | + } | ||
| 143 | + | ||
| 144 | +} |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeDiscountActivityPriceCalculatorTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | ||
| 4 | +import cn.iocoder.yudao.module.promotion.api.discount.DiscountActivityApi; | ||
| 5 | +import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO; | ||
| 6 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionDiscountTypeEnum; | ||
| 7 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | ||
| 8 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||
| 9 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||
| 10 | +import org.junit.jupiter.api.Test; | ||
| 11 | +import org.mockito.InjectMocks; | ||
| 12 | +import org.mockito.Mock; | ||
| 13 | + | ||
| 14 | +import java.util.ArrayList; | ||
| 15 | + | ||
| 16 | +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; | ||
| 17 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | ||
| 18 | +import static java.util.Arrays.asList; | ||
| 19 | +import static org.junit.jupiter.api.Assertions.*; | ||
| 20 | +import static org.mockito.ArgumentMatchers.eq; | ||
| 21 | +import static org.mockito.Mockito.when; | ||
| 22 | + | ||
| 23 | +/** | ||
| 24 | + * {@link TradeDiscountActivityPriceCalculator} 的单元测试类 | ||
| 25 | + * | ||
| 26 | + * @author 芋道源码 | ||
| 27 | + */ | ||
| 28 | +public class TradeDiscountActivityPriceCalculatorTest extends BaseMockitoUnitTest { | ||
| 29 | + | ||
| 30 | + @InjectMocks | ||
| 31 | + private TradeDiscountActivityPriceCalculator tradeDiscountActivityPriceCalculator; | ||
| 32 | + | ||
| 33 | + @Mock | ||
| 34 | + private DiscountActivityApi discountActivityApi; | ||
| 35 | + | ||
| 36 | + @Test | ||
| 37 | + public void testCalculate() { | ||
| 38 | + // 准备参数 | ||
| 39 | + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() | ||
| 40 | + .setItems(asList( | ||
| 41 | + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 匹配活动,且已选中 | ||
| 42 | + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(false) // 匹配活动,但未选中 | ||
| 43 | + )); | ||
| 44 | + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() | ||
| 45 | + .setPrice(new TradePriceCalculateRespBO.Price()) | ||
| 46 | + .setPromotions(new ArrayList<>()) | ||
| 47 | + .setItems(asList( | ||
| 48 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) | ||
| 49 | + .setPrice(100), | ||
| 50 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(false) | ||
| 51 | + .setPrice(50) | ||
| 52 | + )); | ||
| 53 | + // 保证价格被初始化上 | ||
| 54 | + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); | ||
| 55 | + TradePriceCalculatorHelper.recountAllPrice(result); | ||
| 56 | + | ||
| 57 | + // mock 方法(限时折扣活动) | ||
| 58 | + when(discountActivityApi.getMatchDiscountProductList(eq(asSet(10L, 20L)))).thenReturn(asList( | ||
| 59 | + randomPojo(DiscountProductRespDTO.class, o -> o.setActivityId(1000L) | ||
| 60 | + .setActivityName("活动 1000 号").setSkuId(10L) | ||
| 61 | + .setDiscountType(PromotionDiscountTypeEnum.PRICE.getType()).setDiscountPrice(40)), | ||
| 62 | + randomPojo(DiscountProductRespDTO.class, o -> o.setActivityId(2000L) | ||
| 63 | + .setActivityName("活动 2000 号").setSkuId(20L) | ||
| 64 | + .setDiscountType(PromotionDiscountTypeEnum.PERCENT.getType()).setDiscountPercent(60)) | ||
| 65 | + )); | ||
| 66 | + // 10L: 100 * 2 - 40 * 2 = 120 | ||
| 67 | + // 20L:50 * 3 - 50 * 3 * 0.4 = 90 | ||
| 68 | + | ||
| 69 | + // 调用 | ||
| 70 | + tradeDiscountActivityPriceCalculator.calculate(param, result); | ||
| 71 | + // 断言:Price 部分 | ||
| 72 | + TradePriceCalculateRespBO.Price price = result.getPrice(); | ||
| 73 | + assertEquals(price.getTotalPrice(), 200); | ||
| 74 | + assertEquals(price.getDiscountPrice(), 80); | ||
| 75 | + assertEquals(price.getPointPrice(), 0); | ||
| 76 | + assertEquals(price.getDeliveryPrice(), 0); | ||
| 77 | + assertEquals(price.getCouponPrice(), 0); | ||
| 78 | + assertEquals(price.getPayPrice(), 120); | ||
| 79 | + assertNull(result.getCouponId()); | ||
| 80 | + // 断言:SKU 1 | ||
| 81 | + assertEquals(result.getItems().size(), 2); | ||
| 82 | + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); | ||
| 83 | + assertEquals(orderItem01.getSkuId(), 10L); | ||
| 84 | + assertEquals(orderItem01.getCount(), 2); | ||
| 85 | + assertEquals(orderItem01.getPrice(), 100); | ||
| 86 | + assertEquals(orderItem01.getDiscountPrice(), 80); | ||
| 87 | + assertEquals(orderItem01.getDeliveryPrice(), 0); | ||
| 88 | + assertEquals(orderItem01.getCouponPrice(), 0); | ||
| 89 | + assertEquals(orderItem01.getPointPrice(), 0); | ||
| 90 | + assertEquals(orderItem01.getPayPrice(), 120); | ||
| 91 | + // 断言:SKU 2 | ||
| 92 | + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); | ||
| 93 | + assertEquals(orderItem02.getSkuId(), 20L); | ||
| 94 | + assertEquals(orderItem02.getCount(), 3); | ||
| 95 | + assertEquals(orderItem02.getPrice(), 50); | ||
| 96 | + assertEquals(orderItem02.getDiscountPrice(), 60); | ||
| 97 | + assertEquals(orderItem02.getDeliveryPrice(), 0); | ||
| 98 | + assertEquals(orderItem02.getCouponPrice(), 0); | ||
| 99 | + assertEquals(orderItem02.getPointPrice(), 0); | ||
| 100 | + assertEquals(orderItem02.getPayPrice(), 90); | ||
| 101 | + // 断言:Promotion 部分 | ||
| 102 | + assertEquals(result.getPromotions().size(), 1); | ||
| 103 | + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); | ||
| 104 | + assertEquals(promotion01.getId(), 1000L); | ||
| 105 | + assertEquals(promotion01.getName(), "活动 1000 号"); | ||
| 106 | + assertEquals(promotion01.getType(), PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()); | ||
| 107 | + assertEquals(promotion01.getTotalPrice(), 200); | ||
| 108 | + assertEquals(promotion01.getDiscountPrice(), 80); | ||
| 109 | + assertTrue(promotion01.getMatch()); | ||
| 110 | + assertEquals(promotion01.getDescription(), "限时折扣:省 0.80 元"); | ||
| 111 | + TradePriceCalculateRespBO.PromotionItem promotionItem01 = promotion01.getItems().get(0); | ||
| 112 | + assertEquals(promotion01.getItems().size(), 1); | ||
| 113 | + assertEquals(promotionItem01.getSkuId(), 10L); | ||
| 114 | + assertEquals(promotionItem01.getTotalPrice(), 200); | ||
| 115 | + assertEquals(promotionItem01.getDiscountPrice(), 80); | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | +} |
yudao-module-mall/yudao-module-trade-biz/src/test/java/cn/iocoder/yudao/module/trade/service/price/calculator/TradeRewardActivityPriceCalculatorTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.trade.service.price.calculator; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; | ||
| 4 | +import cn.iocoder.yudao.module.promotion.api.reward.RewardActivityApi; | ||
| 5 | +import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO; | ||
| 6 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionConditionTypeEnum; | ||
| 7 | +import cn.iocoder.yudao.module.promotion.enums.common.PromotionTypeEnum; | ||
| 8 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO; | ||
| 9 | +import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO; | ||
| 10 | +import org.junit.jupiter.api.Test; | ||
| 11 | +import org.mockito.InjectMocks; | ||
| 12 | +import org.mockito.Mock; | ||
| 13 | + | ||
| 14 | +import java.util.ArrayList; | ||
| 15 | + | ||
| 16 | +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; | ||
| 17 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | ||
| 18 | +import static java.util.Arrays.asList; | ||
| 19 | +import static java.util.Collections.singletonList; | ||
| 20 | +import static org.junit.jupiter.api.Assertions.*; | ||
| 21 | +import static org.mockito.ArgumentMatchers.eq; | ||
| 22 | +import static org.mockito.Mockito.when; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * {@link TradeRewardActivityPriceCalculator} 的单元测试类 | ||
| 26 | + * | ||
| 27 | + * @author 芋道源码 | ||
| 28 | + */ | ||
| 29 | +public class TradeRewardActivityPriceCalculatorTest extends BaseMockitoUnitTest { | ||
| 30 | + | ||
| 31 | + @InjectMocks | ||
| 32 | + private TradeRewardActivityPriceCalculator tradeRewardActivityPriceCalculator; | ||
| 33 | + | ||
| 34 | + @Mock | ||
| 35 | + private RewardActivityApi rewardActivityApi; | ||
| 36 | + | ||
| 37 | + @Test | ||
| 38 | + public void testCalculate_match() { | ||
| 39 | + // 准备参数 | ||
| 40 | + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() | ||
| 41 | + .setItems(asList( | ||
| 42 | + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), // 匹配活动 1 | ||
| 43 | + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), // 匹配活动 1 | ||
| 44 | + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(true) // 匹配活动 2 | ||
| 45 | + )); | ||
| 46 | + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() | ||
| 47 | + .setPrice(new TradePriceCalculateRespBO.Price()) | ||
| 48 | + .setPromotions(new ArrayList<>()) | ||
| 49 | + .setItems(asList( | ||
| 50 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) | ||
| 51 | + .setPrice(100).setSpuId(1L), | ||
| 52 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) | ||
| 53 | + .setPrice(50).setSpuId(2L), | ||
| 54 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(30L).setCount(4).setSelected(true) | ||
| 55 | + .setPrice(30).setSpuId(3L) | ||
| 56 | + )); | ||
| 57 | + // 保证价格被初始化上 | ||
| 58 | + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); | ||
| 59 | + TradePriceCalculatorHelper.recountAllPrice(result); | ||
| 60 | + | ||
| 61 | + // mock 方法(限时折扣 DiscountActivity 信息) | ||
| 62 | + when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L, 3L)))).thenReturn(asList( | ||
| 63 | + randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号") | ||
| 64 | + .setSpuIds(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) | ||
| 65 | + .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(200).setDiscountPrice(70)))), | ||
| 66 | + randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(2000L).setName("活动 2000 号") | ||
| 67 | + .setSpuIds(singletonList(3L)).setConditionType(PromotionConditionTypeEnum.COUNT.getType()) | ||
| 68 | + .setRules(asList(new RewardActivityMatchRespDTO.Rule().setLimit(1).setDiscountPrice(10), | ||
| 69 | + new RewardActivityMatchRespDTO.Rule().setLimit(2).setDiscountPrice(60), // 最大可满足,因为是 4 个 | ||
| 70 | + new RewardActivityMatchRespDTO.Rule().setLimit(10).setDiscountPrice(100)))) | ||
| 71 | + )); | ||
| 72 | + | ||
| 73 | + // 调用 | ||
| 74 | + tradeRewardActivityPriceCalculator.calculate(param, result); | ||
| 75 | + // 断言 Order 部分 | ||
| 76 | + TradePriceCalculateRespBO.Price price = result.getPrice(); | ||
| 77 | + assertEquals(price.getTotalPrice(), 470); | ||
| 78 | + assertEquals(price.getDiscountPrice(), 130); | ||
| 79 | + assertEquals(price.getPointPrice(), 0); | ||
| 80 | + assertEquals(price.getDeliveryPrice(), 0); | ||
| 81 | + assertEquals(price.getCouponPrice(), 0); | ||
| 82 | + assertEquals(price.getPayPrice(), 340); | ||
| 83 | + assertNull(result.getCouponId()); | ||
| 84 | + // 断言:SKU 1 | ||
| 85 | + assertEquals(result.getItems().size(), 3); | ||
| 86 | + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); | ||
| 87 | + assertEquals(orderItem01.getSkuId(), 10L); | ||
| 88 | + assertEquals(orderItem01.getCount(), 2); | ||
| 89 | + assertEquals(orderItem01.getPrice(), 100); | ||
| 90 | + assertEquals(orderItem01.getDiscountPrice(), 40); | ||
| 91 | + assertEquals(orderItem01.getDeliveryPrice(), 0); | ||
| 92 | + assertEquals(orderItem01.getCouponPrice(), 0); | ||
| 93 | + assertEquals(orderItem01.getPointPrice(), 0); | ||
| 94 | + assertEquals(orderItem01.getPayPrice(), 160); | ||
| 95 | + // 断言:SKU 2 | ||
| 96 | + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); | ||
| 97 | + assertEquals(orderItem02.getSkuId(), 20L); | ||
| 98 | + assertEquals(orderItem02.getCount(), 3); | ||
| 99 | + assertEquals(orderItem02.getPrice(), 50); | ||
| 100 | + assertEquals(orderItem02.getDiscountPrice(), 30); | ||
| 101 | + assertEquals(orderItem02.getDeliveryPrice(), 0); | ||
| 102 | + assertEquals(orderItem02.getCouponPrice(), 0); | ||
| 103 | + assertEquals(orderItem02.getPointPrice(), 0); | ||
| 104 | + assertEquals(orderItem02.getPayPrice(), 120); | ||
| 105 | + // 断言:SKU 3 | ||
| 106 | + TradePriceCalculateRespBO.OrderItem orderItem03 = result.getItems().get(2); | ||
| 107 | + assertEquals(orderItem03.getSkuId(), 30L); | ||
| 108 | + assertEquals(orderItem03.getCount(), 4); | ||
| 109 | + assertEquals(orderItem03.getPrice(), 30); | ||
| 110 | + assertEquals(orderItem03.getDiscountPrice(), 60); | ||
| 111 | + assertEquals(orderItem03.getDeliveryPrice(), 0); | ||
| 112 | + assertEquals(orderItem03.getCouponPrice(), 0); | ||
| 113 | + assertEquals(orderItem03.getPointPrice(), 0); | ||
| 114 | + assertEquals(orderItem03.getPayPrice(), 60); | ||
| 115 | + // 断言:Promotion 部分(第一个) | ||
| 116 | + assertEquals(result.getPromotions().size(), 2); | ||
| 117 | + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); | ||
| 118 | + assertEquals(promotion01.getId(), 1000L); | ||
| 119 | + assertEquals(promotion01.getName(), "活动 1000 号"); | ||
| 120 | + assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); | ||
| 121 | + assertEquals(promotion01.getTotalPrice(), 350); | ||
| 122 | + assertEquals(promotion01.getDiscountPrice(), 70); | ||
| 123 | + assertTrue(promotion01.getMatch()); | ||
| 124 | + assertEquals(promotion01.getDescription(), "满减送:省 0.70 元"); | ||
| 125 | + assertEquals(promotion01.getItems().size(), 2); | ||
| 126 | + TradePriceCalculateRespBO.PromotionItem promotionItem011 = promotion01.getItems().get(0); | ||
| 127 | + assertEquals(promotionItem011.getSkuId(), 10L); | ||
| 128 | + assertEquals(promotionItem011.getTotalPrice(), 200); | ||
| 129 | + assertEquals(promotionItem011.getDiscountPrice(), 40); | ||
| 130 | + TradePriceCalculateRespBO.PromotionItem promotionItem012 = promotion01.getItems().get(1); | ||
| 131 | + assertEquals(promotionItem012.getSkuId(), 20L); | ||
| 132 | + assertEquals(promotionItem012.getTotalPrice(), 150); | ||
| 133 | + assertEquals(promotionItem012.getDiscountPrice(), 30); | ||
| 134 | + // 断言:Promotion 部分(第二个) | ||
| 135 | + TradePriceCalculateRespBO.Promotion promotion02 = result.getPromotions().get(1); | ||
| 136 | + assertEquals(promotion02.getId(), 2000L); | ||
| 137 | + assertEquals(promotion02.getName(), "活动 2000 号"); | ||
| 138 | + assertEquals(promotion02.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); | ||
| 139 | + assertEquals(promotion02.getTotalPrice(), 120); | ||
| 140 | + assertEquals(promotion02.getDiscountPrice(), 60); | ||
| 141 | + assertTrue(promotion02.getMatch()); | ||
| 142 | + assertEquals(promotion02.getDescription(), "满减送:省 0.60 元"); | ||
| 143 | + TradePriceCalculateRespBO.PromotionItem promotionItem02 = promotion02.getItems().get(0); | ||
| 144 | + assertEquals(promotion02.getItems().size(), 1); | ||
| 145 | + assertEquals(promotionItem02.getSkuId(), 30L); | ||
| 146 | + assertEquals(promotionItem02.getTotalPrice(), 120); | ||
| 147 | + assertEquals(promotionItem02.getDiscountPrice(), 60); | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + @Test | ||
| 151 | + public void testCalculate_notMatch() { | ||
| 152 | + // 准备参数 | ||
| 153 | + TradePriceCalculateReqBO param = new TradePriceCalculateReqBO() | ||
| 154 | + .setItems(asList( | ||
| 155 | + new TradePriceCalculateReqBO.Item().setSkuId(10L).setCount(2).setSelected(true), | ||
| 156 | + new TradePriceCalculateReqBO.Item().setSkuId(20L).setCount(3).setSelected(true), | ||
| 157 | + new TradePriceCalculateReqBO.Item().setSkuId(30L).setCount(4).setSelected(true) | ||
| 158 | + )); | ||
| 159 | + TradePriceCalculateRespBO result = new TradePriceCalculateRespBO() | ||
| 160 | + .setPrice(new TradePriceCalculateRespBO.Price()) | ||
| 161 | + .setPromotions(new ArrayList<>()) | ||
| 162 | + .setItems(asList( | ||
| 163 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(10L).setCount(2).setSelected(true) | ||
| 164 | + .setPrice(100).setSpuId(1L), | ||
| 165 | + new TradePriceCalculateRespBO.OrderItem().setSkuId(20L).setCount(3).setSelected(true) | ||
| 166 | + .setPrice(50).setSpuId(2L) | ||
| 167 | + )); | ||
| 168 | + // 保证价格被初始化上 | ||
| 169 | + TradePriceCalculatorHelper.recountPayPrice(result.getItems()); | ||
| 170 | + TradePriceCalculatorHelper.recountAllPrice(result); | ||
| 171 | + | ||
| 172 | + // mock 方法(限时折扣 DiscountActivity 信息) | ||
| 173 | + when(rewardActivityApi.getMatchRewardActivityList(eq(asSet(1L, 2L)))).thenReturn(singletonList( | ||
| 174 | + randomPojo(RewardActivityMatchRespDTO.class, o -> o.setId(1000L).setName("活动 1000 号") | ||
| 175 | + .setSpuIds(asList(1L, 2L)).setConditionType(PromotionConditionTypeEnum.PRICE.getType()) | ||
| 176 | + .setRules(singletonList(new RewardActivityMatchRespDTO.Rule().setLimit(351).setDiscountPrice(70)))) | ||
| 177 | + )); | ||
| 178 | + | ||
| 179 | + // 调用 | ||
| 180 | + tradeRewardActivityPriceCalculator.calculate(param, result); | ||
| 181 | + // 断言 Order 部分 | ||
| 182 | + TradePriceCalculateRespBO.Price price = result.getPrice(); | ||
| 183 | + assertEquals(price.getTotalPrice(), 350); | ||
| 184 | + assertEquals(price.getDiscountPrice(), 0); | ||
| 185 | + assertEquals(price.getPointPrice(), 0); | ||
| 186 | + assertEquals(price.getDeliveryPrice(), 0); | ||
| 187 | + assertEquals(price.getCouponPrice(), 0); | ||
| 188 | + assertEquals(price.getPayPrice(), 350); | ||
| 189 | + assertNull(result.getCouponId()); | ||
| 190 | + // 断言:SKU 1 | ||
| 191 | + assertEquals(result.getItems().size(), 2); | ||
| 192 | + TradePriceCalculateRespBO.OrderItem orderItem01 = result.getItems().get(0); | ||
| 193 | + assertEquals(orderItem01.getSkuId(), 10L); | ||
| 194 | + assertEquals(orderItem01.getCount(), 2); | ||
| 195 | + assertEquals(orderItem01.getPrice(), 100); | ||
| 196 | + assertEquals(orderItem01.getDiscountPrice(), 0); | ||
| 197 | + assertEquals(orderItem01.getDeliveryPrice(), 0); | ||
| 198 | + assertEquals(orderItem01.getCouponPrice(), 0); | ||
| 199 | + assertEquals(orderItem01.getPointPrice(), 0); | ||
| 200 | + assertEquals(orderItem01.getPayPrice(), 200); | ||
| 201 | + // 断言:SKU 2 | ||
| 202 | + TradePriceCalculateRespBO.OrderItem orderItem02 = result.getItems().get(1); | ||
| 203 | + assertEquals(orderItem02.getSkuId(), 20L); | ||
| 204 | + assertEquals(orderItem02.getCount(), 3); | ||
| 205 | + assertEquals(orderItem02.getPrice(), 50); | ||
| 206 | + assertEquals(orderItem02.getDiscountPrice(), 0); | ||
| 207 | + assertEquals(orderItem02.getDeliveryPrice(), 0); | ||
| 208 | + assertEquals(orderItem02.getCouponPrice(), 0); | ||
| 209 | + assertEquals(orderItem02.getPointPrice(), 0); | ||
| 210 | + assertEquals(orderItem02.getPayPrice(), 150); | ||
| 211 | + // 断言 Promotion 部分 | ||
| 212 | + assertEquals(result.getPromotions().size(), 1); | ||
| 213 | + TradePriceCalculateRespBO.Promotion promotion01 = result.getPromotions().get(0); | ||
| 214 | + assertEquals(promotion01.getId(), 1000L); | ||
| 215 | + assertEquals(promotion01.getName(), "活动 1000 号"); | ||
| 216 | + assertEquals(promotion01.getType(), PromotionTypeEnum.REWARD_ACTIVITY.getType()); | ||
| 217 | + assertEquals(promotion01.getTotalPrice(), 350); | ||
| 218 | + assertEquals(promotion01.getDiscountPrice(), 0); | ||
| 219 | + assertFalse(promotion01.getMatch()); | ||
| 220 | + assertEquals(promotion01.getDescription(), "TODO"); // TODO 芋艿:后面再想想 | ||
| 221 | + assertEquals(promotion01.getItems().size(), 2); | ||
| 222 | + TradePriceCalculateRespBO.PromotionItem promotionItem011 = promotion01.getItems().get(0); | ||
| 223 | + assertEquals(promotionItem011.getSkuId(), 10L); | ||
| 224 | + assertEquals(promotionItem011.getTotalPrice(), 200); | ||
| 225 | + assertEquals(promotionItem011.getDiscountPrice(), 0); | ||
| 226 | + TradePriceCalculateRespBO.PromotionItem promotionItem012 = promotion01.getItems().get(1); | ||
| 227 | + assertEquals(promotionItem012.getSkuId(), 20L); | ||
| 228 | + assertEquals(promotionItem012.getTotalPrice(), 150); | ||
| 229 | + assertEquals(promotionItem012.getDiscountPrice(), 0); | ||
| 230 | + } | ||
| 231 | + | ||
| 232 | +} |
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/AddressApi.java
| @@ -18,4 +18,12 @@ public interface AddressApi { | @@ -18,4 +18,12 @@ public interface AddressApi { | ||
| 18 | */ | 18 | */ |
| 19 | AddressRespDTO getAddress(Long id, Long userId); | 19 | AddressRespDTO getAddress(Long id, Long userId); |
| 20 | 20 | ||
| 21 | + /** | ||
| 22 | + * 获得用户默认收件地址 | ||
| 23 | + * | ||
| 24 | + * @param userId 用户编号 | ||
| 25 | + * @return 用户收件地址 | ||
| 26 | + */ | ||
| 27 | + AddressRespDTO getDefaultAddress(Long userId); | ||
| 28 | + | ||
| 21 | } | 29 | } |
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/api/address/dto/AddressRespDTO.java
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/api/address/AddressApiImpl.java
| @@ -25,4 +25,9 @@ public class AddressApiImpl implements AddressApi { | @@ -25,4 +25,9 @@ public class AddressApiImpl implements AddressApi { | ||
| 25 | return AddressConvert.INSTANCE.convert02(addressService.getAddress(userId, id)); | 25 | return AddressConvert.INSTANCE.convert02(addressService.getAddress(userId, id)); |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | + @Override | ||
| 29 | + public AddressRespDTO getDefaultAddress(Long userId) { | ||
| 30 | + return AddressConvert.INSTANCE.convert02(addressService.getDefaultUserAddress(userId)); | ||
| 31 | + } | ||
| 32 | + | ||
| 28 | } | 33 | } |
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java