前端:订单确认页,接入优惠劵列表(不包括计算)

后端:增加优惠劵的计算逻辑
This commit is contained in:
YunaiV
2019-04-19 22:51:19 +08:00
parent ea4593adbc
commit cb07eb3f71
12 changed files with 339 additions and 33 deletions

View File

@@ -96,7 +96,7 @@ public class UsersCartController {
return CommonResult.success(result);
}
// 计算商品价格
CommonResult<CalcOrderPriceBO> calcOrderPriceResult = list0(cartItems);
CommonResult<CalcOrderPriceBO> calcOrderPriceResult = list0(cartItems, null);
if (calcOrderPriceResult.isError()) {
return CommonResult.error(calcOrderPriceResult);
}
@@ -105,7 +105,7 @@ public class UsersCartController {
}
@GetMapping("/confirm_create_order")
public CommonResult<UsersOrderConfirmCreateVO> getConfirmCreateOrder() {
public CommonResult<UsersOrderConfirmCreateVO> getConfirmCreateOrder(@RequestParam("couponCardId") Integer couponCardId) {
Integer userId = UserSecurityContextHolder.getContext().getUserId();
// 获得购物车中选中的
List<CartItemBO> cartItems = cartService.list(userId, true).getData();
@@ -117,7 +117,7 @@ public class UsersCartController {
return CommonResult.success(result);
}
// 计算商品价格
CommonResult<CalcOrderPriceBO> calcOrderPriceResult = list0(cartItems);
CommonResult<CalcOrderPriceBO> calcOrderPriceResult = list0(cartItems, couponCardId);
if (calcOrderPriceResult.isError()) {
return CommonResult.error(calcOrderPriceResult);
}
@@ -130,10 +130,12 @@ public class UsersCartController {
.setCouponCards(couponCards));
}
private CommonResult<CalcOrderPriceBO> list0(List<CartItemBO> cartItems) {
private CommonResult<CalcOrderPriceBO> list0(List<CartItemBO> cartItems, Integer couponCardId) {
// 创建计算的 DTO
CalcOrderPriceDTO calcOrderPriceDTO = new CalcOrderPriceDTO()
.setItems(new ArrayList<>(cartItems.size()));
.setUserId(UserSecurityContextHolder.getContext().getUserId())
.setItems(new ArrayList<>(cartItems.size()))
.setCouponCardId(couponCardId);
for (CartItemBO item : cartItems) {
calcOrderPriceDTO.getItems().add(new CalcOrderPriceDTO.Item(item.getSkuId(), item.getQuantity(), item.getSelected()));
}

View File

@@ -93,10 +93,13 @@ public class UsersOrderController {
@GetMapping("confirm_create_order")
@ApiOperation("确认创建订单")
public CommonResult<UsersOrderConfirmCreateVO> getConfirmCreateOrder(@RequestParam("skuId") Integer skuId,
@RequestParam("quantity") Integer quantity) {
@RequestParam("quantity") Integer quantity,
@RequestParam("couponCardId") Integer couponCardId) {
// 创建 CalcOrderPriceDTO 对象,并执行价格计算
CalcOrderPriceDTO calcOrderPriceDTO = new CalcOrderPriceDTO()
.setItems(Collections.singletonList(new CalcOrderPriceDTO.Item(skuId, quantity, true)));
.setUserId(UserSecurityContextHolder.getContext().getUserId())
.setItems(Collections.singletonList(new CalcOrderPriceDTO.Item(skuId, quantity, true)))
.setCouponCardId(couponCardId);
CommonResult<CalcOrderPriceBO> calcOrderPriceResult = cartService.calcOrderPrice(calcOrderPriceDTO);
if (calcOrderPriceResult.isError()) {
return CommonResult.error(calcOrderPriceResult);

View File

@@ -24,7 +24,6 @@ public class UsersOrderConfirmCreateVO {
* 优惠劵列表 TODO 芋艿,后续改改
*/
private List<CouponCardAvailableBO> couponCards;
/**
* 商品分组
*

View File

@@ -18,6 +18,17 @@ public class CalcOrderPriceBO {
* 商品分组数组
*/
private List<ItemGroup> itemGroups;
/**
* 优惠劵编号
*/
private Integer couponCardId;
/**
* 优惠劵减少的金额
*
* 1. 若未使用优惠劵,返回 null
* 2. 该金额,已经分摊到每个 Item 的 discountTotal ,需要注意。
*/
private Integer couponCardDiscountTotal;
/**
* 邮费信息
*

View File

@@ -3,6 +3,7 @@ package cn.iocoder.mall.order.api.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
@@ -12,9 +13,13 @@ import java.util.List;
@Accessors(chain = true)
public class CalcOrderPriceDTO {
@NotNull(message = "用户编号不能为空")
private Integer userId;
/**
* 商品数组
* 优惠劵编号
*/
private Integer couponCardId;
@NotNull(message = "商品数组不能为空")
private List<Item> items;
@Data

View File

@@ -16,7 +16,9 @@ import cn.iocoder.mall.order.biz.dataobject.CartItemDO;
import cn.iocoder.mall.product.api.ProductSpuService;
import cn.iocoder.mall.product.api.bo.ProductSkuBO;
import cn.iocoder.mall.product.api.bo.ProductSkuDetailBO;
import cn.iocoder.mall.promotion.api.CouponService;
import cn.iocoder.mall.promotion.api.PromotionActivityService;
import cn.iocoder.mall.promotion.api.bo.CouponCardDetailBO;
import cn.iocoder.mall.promotion.api.bo.PromotionActivityBO;
import cn.iocoder.mall.promotion.api.constant.*;
import com.alibaba.dubbo.config.annotation.Reference;
@@ -38,6 +40,8 @@ public class CartServiceImpl implements CartService {
private ProductSpuService productSpuService;
@Reference(validation = "true")
private PromotionActivityService promotionActivityService;
@Reference(validation = "true")
private CouponService couponService;
@Autowired
private CartMapper cartMapper;
@@ -152,6 +156,7 @@ public class CartServiceImpl implements CartService {
@Override
public CommonResult<CalcOrderPriceBO> calcOrderPrice(CalcOrderPriceDTO calcOrderPriceDTO) {
// TODO 芋艿,补充一些表单校验。例如说,需要传入用户编号。
// 校验商品都存在
Map<Integer, CalcOrderPriceDTO.Item> calcOrderItemMap = calcOrderPriceDTO.getItems().stream()
.collect(Collectors.toMap(CalcOrderPriceDTO.Item::getSkuId, item -> item)); // KEYskuId
@@ -177,7 +182,15 @@ public class CartServiceImpl implements CartService {
// 3. 计算【满减送】促销
List<CalcOrderPriceBO.ItemGroup> itemGroups = groupByFullPrivilege(items, activityList);
calcOrderPriceBO.setItemGroups(itemGroups);
// 4. 计算最终的价格
// 4. 计算优惠劵
if (calcOrderPriceDTO.getCouponCardId() != null) {
CommonResult<Integer> result = modifyPriceByCouponCard(calcOrderPriceDTO.getUserId(), calcOrderPriceDTO.getCouponCardId(), itemGroups);
if (result.isError()) {
return CommonResult.error(result);
}
calcOrderPriceBO.setCouponCardDiscountTotal(result.getData());
}
// 5. 计算最终的价格
int buyTotal = 0;
int discountTotal = 0;
int presentTotal = 0;
@@ -314,6 +327,72 @@ public class CartServiceImpl implements CartService {
return itemGroups;
}
private CommonResult<Integer> modifyPriceByCouponCard(Integer userId, Integer couponCardId, List<CalcOrderPriceBO.ItemGroup> itemGroups) {
Assert.isTrue(couponCardId != null, "优惠劵编号不能为空");
// 查询优惠劵
CommonResult<CouponCardDetailBO> couponCardResult = couponService.getCouponCardDetail(userId, couponCardId);
if (couponCardResult.isError()) {
return CommonResult.error(couponCardResult);
}
CouponCardDetailBO couponCard = couponCardResult.getData();
// 获得匹配的商品
List<CalcOrderPriceBO.Item> items = new ArrayList<>();
if (RangeTypeEnum.ALL.getValue().equals(couponCard.getRangeType())) {
// totalPrice = spus.stream().mapToInt(spu -> spu.getPrice() * spu.getQuantity()).sum();
itemGroups.forEach(itemGroup -> items.addAll(itemGroup.getItems()));
} else if (RangeTypeEnum.PRODUCT_INCLUDE_PART.getValue().equals(couponCard.getRangeType())) {
itemGroups.forEach(itemGroup -> items.forEach(item -> {
if (couponCard.getRangeValues().contains(item.getSpu().getId())) {
items.add(item);
}
}));
} else if (RangeTypeEnum.PRODUCT_EXCLUDE_PART.getValue().equals(couponCard.getRangeType())) {
itemGroups.forEach(itemGroup -> items.forEach(item -> {
if (!couponCard.getRangeValues().contains(item.getSpu().getId())) {
items.add(item);
}
}));
} else if (RangeTypeEnum.CATEGORY_INCLUDE_PART.getValue().equals(couponCard.getRangeType())) {
itemGroups.forEach(itemGroup -> items.forEach(item -> {
if (couponCard.getRangeValues().contains(item.getSpu().getCid())) {
items.add(item);
}
}));
} else if (RangeTypeEnum.CATEGORY_EXCLUDE_PART.getValue().equals(couponCard.getRangeType())) {
itemGroups.forEach(itemGroup -> items.forEach(item -> {
if (!couponCard.getRangeValues().contains(item.getSpu().getCid())) {
items.add(item);
}
}));
}
// 判断是否符合条件
int originalTotal = items.stream().mapToInt(CalcOrderPriceBO.Item::getPresentTotal).sum(); // 此处,指的是以优惠劵视角的原价
if (originalTotal == 0 || originalTotal < couponCard.getPriceAvailable()) {
return ServiceExceptionUtil.error(PromotionErrorCodeEnum.COUPON_CARD_NOT_MATCH.getCode()); // TODO 芋艿,这种情况,会出现错误码的提示,无法格式化出来。另外,这块的最佳实践,找人讨论下。
}
// 计算价格
// 获得到优惠信息,进行价格计算
int presentTotal;
if (PreferentialTypeEnum.PRICE.getValue().equals(couponCard.getPreferentialType())) { // 减价
// 计算循环次数。这样,后续优惠的金额就是相乘了
presentTotal = originalTotal - couponCard.getPriceOff();
Assert.isTrue(presentTotal > 0, "计算后,价格为负数:" + presentTotal);
} else if (PreferentialTypeEnum.DISCOUNT.getValue().equals(couponCard.getPreferentialType())) { // 打折
presentTotal = originalTotal * couponCard.getPercentOff() / 100;
if (originalTotal - presentTotal > couponCard.getDiscountPriceLimit()) {
presentTotal = originalTotal - couponCard.getDiscountPriceLimit();
}
} else {
throw new IllegalArgumentException(String.format("优惠劵(%s) 的优惠类型不正确", couponCard.toString()));
}
int discountTotal = originalTotal - presentTotal;
Assert.isTrue(discountTotal > 0, "计算后,不产生优惠:" + discountTotal);
// 按比例,拆分 presentTotal
splitDiscountPriceToItems(items, discountTotal, presentTotal);
// 返回优惠金额
return CommonResult.success(originalTotal - presentTotal);
}
/**
* 计算指定 SKU 在限时折扣下的价格
*
@@ -393,11 +472,31 @@ public class CartServiceImpl implements CartService {
} else {
throw new IllegalArgumentException(String.format("满减送促销(%s) 的优惠类型不正确", activity.toString()));
}
Integer discountTotal = originalTotal - presentTotal;
int discountTotal = originalTotal - presentTotal;
if (discountTotal == 0) {
return null;
}
// 按比例,拆分 presentTotal
// for (int i = 0; i < items.size(); i++) {
// CalcOrderPriceBO.Item item = items.get(i);
// Integer discountPart;
// if (i < items.size() - 1) { // 减一的原因,是因为拆分时,如果按照比例,可能会出现.所以最后一个,使用反减
// discountPart = (int) (discountTotal * (1.0D * item.getPresentTotal() / presentTotal));
// discountTotal -= discountPart;
// } else {
// discountPart = discountTotal;
// }
// Assert.isTrue(discountPart > 0, "优惠金额必须大于 0");
// item.setDiscountTotal(item.getDiscountTotal() + discountPart);
// item.setPresentTotal(item.getBuyTotal() - item.getDiscountTotal());
// item.setPresentPrice(item.getPresentTotal() / item.getBuyQuantity());
// }
splitDiscountPriceToItems(items, discountTotal, presentTotal);
// 返回优惠金额
return originalTotal - presentTotal;
}
private void splitDiscountPriceToItems(List<CalcOrderPriceBO.Item> items, Integer discountTotal, Integer presentTotal) {
for (int i = 0; i < items.size(); i++) {
CalcOrderPriceBO.Item item = items.get(i);
Integer discountPart;
@@ -412,7 +511,6 @@ public class CartServiceImpl implements CartService {
item.setPresentTotal(item.getBuyTotal() - item.getDiscountTotal());
item.setPresentPrice(item.getPresentTotal() / item.getBuyQuantity());
}
return originalTotal - presentTotal;
}
private PromotionActivityBO findPromotionActivityByType(List<PromotionActivityBO> activityList, PromotionActivityTypeEnum type) {