Price 价格服务的编写
parent
84cc2728bd
commit
ed71f5e9c8
|
@ -36,6 +36,6 @@ public interface AdminConvert {
|
||||||
|
|
||||||
AdminPageItemVO convert02(AdminVO adminVO);
|
AdminPageItemVO convert02(AdminVO adminVO);
|
||||||
AdminPageItemVO.Department convert(DepartmentVO bean);
|
AdminPageItemVO.Department convert(DepartmentVO bean);
|
||||||
List<AdminPageItemVO.Role> convert(List<RoleVO> list);
|
List<AdminPageItemVO.Role> convertList(List<RoleVO> list);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ public class AdminManager {
|
||||||
// 拼接部门
|
// 拼接部门
|
||||||
adminPageItemVO.setDepartment(AdminConvert.INSTANCE.convert(departmentMap.get(adminVO.getDepartmentId())));
|
adminPageItemVO.setDepartment(AdminConvert.INSTANCE.convert(departmentMap.get(adminVO.getDepartmentId())));
|
||||||
// 拼接角色
|
// 拼接角色
|
||||||
adminPageItemVO.setRoles( AdminConvert.INSTANCE.convert(adminRoleMap.get(adminVO.getId())));
|
adminPageItemVO.setRoles( AdminConvert.INSTANCE.convertList(adminRoleMap.get(adminVO.getId())));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
adminPageVO.setList(Collections.emptyList());
|
adminPageVO.setList(Collections.emptyList());
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
|
@Deprecated
|
||||||
public class CalcOrderPriceBO {
|
public class CalcOrderPriceBO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,7 +30,6 @@ public enum OrderErrorCodeEnum {
|
||||||
|
|
||||||
// order item
|
// order item
|
||||||
ORDER_ITEM_ONLY_ONE(1008000200, "订单Item只有一个!"),
|
ORDER_ITEM_ONLY_ONE(1008000200, "订单Item只有一个!"),
|
||||||
ORDER_ITEM_SOME_NOT_EXISTS(1008000201, "有不存在的商品!"),
|
|
||||||
|
|
||||||
// 订单退货
|
// 订单退货
|
||||||
ORDER_RETURN_NO_RETURN_APPLY(1008000400, "未退货申请"),
|
ORDER_RETURN_NO_RETURN_APPLY(1008000400, "未退货申请"),
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
|
@Deprecated
|
||||||
public class CalcOrderPriceDTO {
|
public class CalcOrderPriceDTO {
|
||||||
|
|
||||||
@NotNull(message = "用户编号不能为空")
|
@NotNull(message = "用户编号不能为空")
|
||||||
|
|
|
@ -47,25 +47,8 @@ public class CartServiceImpl implements CartService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CalcOrderPriceBO calcOrderPrice(CalcOrderPriceDTO calcOrderPriceDTO) {
|
public CalcOrderPriceBO calcOrderPrice(CalcOrderPriceDTO calcOrderPriceDTO) {
|
||||||
// TODO 芋艿,补充一些表单校验。例如说,需要传入用户编号。
|
|
||||||
// 校验商品都存在
|
|
||||||
Map<Integer, CalcOrderPriceDTO.Item> calcOrderItemMap = calcOrderPriceDTO.getItems().stream()
|
|
||||||
.collect(Collectors.toMap(CalcOrderPriceDTO.Item::getSkuId, item -> item)); // KEY:skuId
|
|
||||||
List<ProductSkuDetailBO> skus = productSpuService.getProductSkuDetailList(calcOrderItemMap.keySet());
|
|
||||||
if (skus.size() != calcOrderPriceDTO.getItems().size()) {
|
|
||||||
throw ServiceExceptionUtil.exception(OrderErrorCodeEnum.ORDER_ITEM_SOME_NOT_EXISTS.getCode());
|
|
||||||
}
|
|
||||||
// TODO 库存相关
|
|
||||||
// 查询促销活动
|
|
||||||
List<PromotionActivityBO> activityList = promotionActivityService.getPromotionActivityListBySpuIds(
|
|
||||||
skus.stream().map(sku -> sku.getSpu().getId()).collect(Collectors.toSet()),
|
|
||||||
Collections.singletonList(PromotionActivityStatusEnum.RUN.getValue()));
|
|
||||||
// 拼装结果(主要是计算价格)
|
|
||||||
CalcOrderPriceBO calcOrderPriceBO = new CalcOrderPriceBO();
|
|
||||||
// 1. 创建初始的每一项的数组
|
|
||||||
List<CalcOrderPriceBO.Item> items = initCalcOrderPriceItems(skus, calcOrderItemMap);
|
|
||||||
// 2. 计算【限时折扣】促销
|
// 2. 计算【限时折扣】促销
|
||||||
modifyPriceByTimeLimitDiscount(items, activityList);
|
|
||||||
// 3. 计算【满减送】促销
|
// 3. 计算【满减送】促销
|
||||||
List<CalcOrderPriceBO.ItemGroup> itemGroups = groupByFullPrivilege(items, activityList);
|
List<CalcOrderPriceBO.ItemGroup> itemGroups = groupByFullPrivilege(items, activityList);
|
||||||
calcOrderPriceBO.setItemGroups(itemGroups);
|
calcOrderPriceBO.setItemGroups(itemGroups);
|
||||||
|
@ -114,52 +97,7 @@ public class CartServiceImpl implements CartService {
|
||||||
.setOriginalPrice(sku.getPrice()).setBuyPrice(presentPrice);
|
.setOriginalPrice(sku.getPrice()).setBuyPrice(presentPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<CalcOrderPriceBO.Item> initCalcOrderPriceItems(List<ProductSkuDetailBO> skus,
|
|
||||||
Map<Integer, CalcOrderPriceDTO.Item> calcOrderItemMap) {
|
|
||||||
List<CalcOrderPriceBO.Item> items = new ArrayList<>();
|
|
||||||
for (ProductSkuDetailBO sku : skus) {
|
|
||||||
CalcOrderPriceBO.Item item = CartConvert.INSTANCE.convert(sku);
|
|
||||||
items.add(item);
|
|
||||||
// 将是否选中,购物数量,复制到 item 中
|
|
||||||
CalcOrderPriceDTO.Item calcOrderItem = calcOrderItemMap.get(sku.getId());
|
|
||||||
item.setSelected(calcOrderItem.getSelected());
|
|
||||||
item.setBuyQuantity(calcOrderItem.getQuantity());
|
|
||||||
// 计算初始价格
|
|
||||||
item.setOriginPrice(sku.getPrice());
|
|
||||||
item.setBuyPrice(sku.getPrice());
|
|
||||||
item.setPresentPrice(sku.getPrice());
|
|
||||||
item.setBuyTotal(sku.getPrice() * calcOrderItem.getQuantity());
|
|
||||||
item.setDiscountTotal(0);
|
|
||||||
item.setPresentTotal(item.getBuyTotal());
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void modifyPriceByTimeLimitDiscount(List<CalcOrderPriceBO.Item> items, List<PromotionActivityBO> activityList) {
|
|
||||||
for (CalcOrderPriceBO.Item item : items) {
|
|
||||||
// 获得符合条件的限时折扣
|
|
||||||
PromotionActivityBO timeLimitedDiscount = activityList.stream()
|
|
||||||
.filter(activity -> PromotionActivityTypeEnum.TIME_LIMITED_DISCOUNT.getValue().equals(activity.getActivityType())
|
|
||||||
&& activity.getTimeLimitedDiscount().getItems().stream().anyMatch(item0 -> item0.getSpuId().equals(item.getSpu().getId())))
|
|
||||||
.findFirst().orElse(null);
|
|
||||||
if (timeLimitedDiscount == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 计算价格
|
|
||||||
ProductSkuBO sku = new ProductSkuBO().setId(item.getId()).setSpuId(item.getSpu().getId()).setPrice(item.getPrice());
|
|
||||||
Integer newPrice = calcSkuPriceByTimeLimitDiscount(sku, timeLimitedDiscount);
|
|
||||||
if (newPrice.equals(item.getPrice())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 设置优惠
|
|
||||||
item.setActivity(timeLimitedDiscount);
|
|
||||||
// 设置价格
|
|
||||||
item.setBuyPrice(newPrice);
|
|
||||||
item.setBuyTotal(newPrice * item.getBuyQuantity());
|
|
||||||
item.setPresentTotal(item.getBuyTotal() - item.getDiscountTotal());
|
|
||||||
item.setPresentPrice(item.getPresentTotal() / item.getBuyQuantity());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<CalcOrderPriceBO.ItemGroup> groupByFullPrivilege(List<CalcOrderPriceBO.Item> items, List<PromotionActivityBO> activityList) {
|
private List<CalcOrderPriceBO.ItemGroup> groupByFullPrivilege(List<CalcOrderPriceBO.Item> items, List<PromotionActivityBO> activityList) {
|
||||||
List<CalcOrderPriceBO.ItemGroup> itemGroups = new ArrayList<>();
|
List<CalcOrderPriceBO.ItemGroup> itemGroups = new ArrayList<>();
|
||||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商品 SKU 列表查询 DTO
|
* 商品 SKU 列表查询 DTO
|
||||||
|
@ -16,9 +17,14 @@ public class ProductSkuListQueryReqDTO implements Serializable {
|
||||||
* 商品 SKU 编号
|
* 商品 SKU 编号
|
||||||
*/
|
*/
|
||||||
private Integer productSkuId;
|
private Integer productSkuId;
|
||||||
|
/**
|
||||||
|
* 商品 SKU 编号数组
|
||||||
|
*/
|
||||||
|
private Collection<Integer> productSkuIds;
|
||||||
/**
|
/**
|
||||||
* 商品 SPU 编号
|
* 商品 SPU 编号
|
||||||
*/
|
*/
|
||||||
private Integer productSpuId;
|
private Integer productSpuId;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ public interface ProductSkuMapper extends BaseMapper<ProductSkuDO> {
|
||||||
|
|
||||||
default List<ProductSkuDO> selectList(ProductSkuListQueryBO queryBO) {
|
default List<ProductSkuDO> selectList(ProductSkuListQueryBO queryBO) {
|
||||||
return selectList(new QueryWrapperX<ProductSkuDO>().eqIfPresent("id", queryBO.getProductSkuId())
|
return selectList(new QueryWrapperX<ProductSkuDO>().eqIfPresent("id", queryBO.getProductSkuId())
|
||||||
|
.inIfPresent("id", queryBO.getProductSkuIds())
|
||||||
.eqIfPresent("spu_id", queryBO.getProductSpuId())
|
.eqIfPresent("spu_id", queryBO.getProductSpuId())
|
||||||
.eqIfPresent("status", queryBO.getProductSkuStatus()));
|
.eqIfPresent("status", queryBO.getProductSkuStatus()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package cn.iocoder.mall.productservice.service.sku.bo;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商品 SKU 列表查询 BO
|
* 商品 SKU 列表查询 BO
|
||||||
*/
|
*/
|
||||||
|
@ -14,6 +16,10 @@ public class ProductSkuListQueryBO {
|
||||||
* 商品 SKU 编号
|
* 商品 SKU 编号
|
||||||
*/
|
*/
|
||||||
private Integer productSkuId;
|
private Integer productSkuId;
|
||||||
|
/**
|
||||||
|
* 商品 SKU 编号数组
|
||||||
|
*/
|
||||||
|
private Collection<Integer> productSkuIds;
|
||||||
/**
|
/**
|
||||||
* 商品 SPU 编号
|
* 商品 SPU 编号
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,7 +3,7 @@ package cn.iocoder.mall.promotion.api.enums;
|
||||||
/**
|
/**
|
||||||
* 促销活动状态枚举
|
* 促销活动状态枚举
|
||||||
*/
|
*/
|
||||||
public enum PromotionActivityStatusEnum {
|
public enum PromotionActivityStatusEnum {
|
||||||
|
|
||||||
WAIT(10, "未开始"),
|
WAIT(10, "未开始"),
|
||||||
RUN(20, "进行中"),
|
RUN(20, "进行中"),
|
||||||
|
|
|
@ -34,4 +34,7 @@ public interface PromotionErrorCodeConstants {
|
||||||
ErrorCode COUPON_CARD_STATUS_NOT_UNUSED = new ErrorCode(1006003003, "优惠劵不处于待使用状态");
|
ErrorCode COUPON_CARD_STATUS_NOT_UNUSED = new ErrorCode(1006003003, "优惠劵不处于待使用状态");
|
||||||
ErrorCode COUPON_CARD_STATUS_NOT_USED = new ErrorCode( 1006003004, "优惠劵不处于已使用状态");
|
ErrorCode COUPON_CARD_STATUS_NOT_USED = new ErrorCode( 1006003004, "优惠劵不处于已使用状态");
|
||||||
|
|
||||||
|
// ========== PRICE 模块 ==========
|
||||||
|
ErrorCode PRICE_PRODUCT_SKU_NOT_EXISTS = new ErrorCode(1006004000, "有不存在的商品!");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,9 @@ import java.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 促销伙伴 Response DTO
|
||||||
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class PromotionActivityRespDTO implements Serializable {
|
public class PromotionActivityRespDTO implements Serializable {
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package cn.iocoder.mall.promotion.api.rpc.price;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 价格 Rpc 接口,提供价格计算的功能
|
||||||
|
*/
|
||||||
|
public class PriceRpc {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package cn.iocoder.mall.promotion.api.rpc.price.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品价格计算 Request DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors
|
||||||
|
public class PriceProductCalcReqDTO implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户编号
|
||||||
|
*/
|
||||||
|
@NotNull(message = "用户编号不能为空")
|
||||||
|
private Integer userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优惠劵编号
|
||||||
|
*/
|
||||||
|
private Integer couponCardId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品 SKU 数组
|
||||||
|
*/
|
||||||
|
@NotNull(message = "商品数组不能为空")
|
||||||
|
private List<Item> items;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品 SKU
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public static class Item {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SKU 编号
|
||||||
|
*/
|
||||||
|
private Integer skuId;
|
||||||
|
/**
|
||||||
|
* 数量
|
||||||
|
*/
|
||||||
|
private Integer quantity;
|
||||||
|
|
||||||
|
public Item() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Item(Integer skuId, Integer quantity) {
|
||||||
|
this.skuId = skuId;
|
||||||
|
this.quantity = quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
package cn.iocoder.mall.promotion.api.rpc.price.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品价格计算 Request DTO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class PriceProductCalcRespDTO implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品分组数组
|
||||||
|
*/
|
||||||
|
private List<ItemGroup> itemGroups;
|
||||||
|
/**
|
||||||
|
* 优惠劵编号
|
||||||
|
*/
|
||||||
|
private Integer couponCardId;
|
||||||
|
/**
|
||||||
|
* 优惠劵减少的金额
|
||||||
|
*
|
||||||
|
* 1. 若未使用优惠劵,返回 null
|
||||||
|
* 2. 该金额,已经分摊到每个 Item 的 discountTotal ,需要注意。
|
||||||
|
*/
|
||||||
|
private Integer couponCardDiscountTotal;
|
||||||
|
/**
|
||||||
|
* 邮费信息
|
||||||
|
*
|
||||||
|
* TODO 芋艿,暂时未弄
|
||||||
|
*/
|
||||||
|
private Postage postage;
|
||||||
|
/**
|
||||||
|
* 费用
|
||||||
|
*/
|
||||||
|
private Fee fee;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商品分组
|
||||||
|
*
|
||||||
|
* 多个商品,参加同一个活动,从而形成分组。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public static class ItemGroup {
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 优惠活动
|
||||||
|
// */
|
||||||
|
// // TODO 芋艿,目前只会有【满减送】的情况,未来有新的促销方式,可能需要改成数组
|
||||||
|
// private PromotionActivityBO activity;
|
||||||
|
/**
|
||||||
|
* 促销减少的金额
|
||||||
|
*
|
||||||
|
* 1. 若未参与促销活动,或不满足促销条件,返回 null
|
||||||
|
* 2. 该金额,已经分摊到每个 Item 的 discountTotal ,需要注意。
|
||||||
|
*/
|
||||||
|
private Integer activityDiscountTotal;
|
||||||
|
/**
|
||||||
|
* 商品数组
|
||||||
|
*/
|
||||||
|
private List<Item> items;
|
||||||
|
// /**
|
||||||
|
// * 费用
|
||||||
|
// *
|
||||||
|
// * TODO 芋艿,这里先偷懒,postageTotal 字段用不到。
|
||||||
|
// */
|
||||||
|
// private Fee fee; // 注释原因,不用这里了
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public static class Item {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买数量
|
||||||
|
*/
|
||||||
|
private Integer buyQuantity;
|
||||||
|
// /**
|
||||||
|
// * 优惠活动
|
||||||
|
// */
|
||||||
|
// private PromotionActivityBO activity;
|
||||||
|
/**
|
||||||
|
* 原始单价,单位:分。
|
||||||
|
*/
|
||||||
|
private Integer originPrice;
|
||||||
|
/**
|
||||||
|
* 购买单价,单位:分
|
||||||
|
*/
|
||||||
|
private Integer buyPrice;
|
||||||
|
/**
|
||||||
|
* 最终价格,单位:分。
|
||||||
|
*/
|
||||||
|
private Integer presentPrice;
|
||||||
|
/**
|
||||||
|
* 购买总金额,单位:分
|
||||||
|
*
|
||||||
|
* 用途类似 {@link #presentTotal}
|
||||||
|
*/
|
||||||
|
private Integer buyTotal;
|
||||||
|
/**
|
||||||
|
* 优惠总金额,单位:分。
|
||||||
|
*/
|
||||||
|
private Integer discountTotal;
|
||||||
|
/**
|
||||||
|
* 最终总金额,单位:分。
|
||||||
|
*
|
||||||
|
* 注意,presentPrice * quantity 不一定等于 presentTotal 。
|
||||||
|
* 因为,存在无法整除的情况。
|
||||||
|
* 举个例子,presentPrice = 8.33 ,quantity = 3 的情况,presentTotal 有可能是 24.99 ,也可能是 25 。
|
||||||
|
* 所以,需要存储一个该字段。
|
||||||
|
*/
|
||||||
|
private Integer presentTotal;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 费用(合计)
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public static class Fee {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 购买总价
|
||||||
|
*/
|
||||||
|
private Integer buyTotal;
|
||||||
|
/**
|
||||||
|
* 优惠总价
|
||||||
|
*
|
||||||
|
* 注意,满多少元包邮,不算在优惠中。
|
||||||
|
*/
|
||||||
|
private Integer discountTotal;
|
||||||
|
/**
|
||||||
|
* 邮费 TODO 芋艿,将 postage 改成 logistics
|
||||||
|
*/
|
||||||
|
private Integer postageTotal;
|
||||||
|
/**
|
||||||
|
* 最终价格
|
||||||
|
*
|
||||||
|
* 计算公式 = 总价 - 优惠总价 + 邮费
|
||||||
|
*/
|
||||||
|
private Integer presentTotal;
|
||||||
|
|
||||||
|
public Fee() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Fee(Integer buyTotal, Integer discountTotal, Integer postageTotal, Integer presentTotal) {
|
||||||
|
this.buyTotal = buyTotal;
|
||||||
|
this.discountTotal = discountTotal;
|
||||||
|
this.postageTotal = postageTotal;
|
||||||
|
this.presentTotal = presentTotal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邮费信息
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public static class Postage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要满足多少钱,可以包邮。单位:分
|
||||||
|
*/
|
||||||
|
private Integer threshold;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -66,6 +66,13 @@
|
||||||
<artifactId>mall-spring-boot-starter-mybatis</artifactId>
|
<artifactId>mall-spring-boot-starter-mybatis</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Test 相关 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 工具类相关 -->
|
<!-- 工具类相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
|
|
@ -26,6 +26,8 @@ public interface PromotionActivityConvert {
|
||||||
@Mappings({})
|
@Mappings({})
|
||||||
List<PromotionActivityRespDTO> convertToRespDTO(List<PromotionActivityDO> activityList);
|
List<PromotionActivityRespDTO> convertToRespDTO(List<PromotionActivityDO> activityList);
|
||||||
|
|
||||||
|
List<PromotionActivityRespDTO> convertList(List<PromotionActivityDO> list);
|
||||||
|
|
||||||
// @Mappings({})
|
// @Mappings({})
|
||||||
// PromotionActivityDO convert(PromotionActivityAddDTO activityAddDTO);
|
// PromotionActivityDO convert(PromotionActivityAddDTO activityAddDTO);
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity;
|
package cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity;
|
||||||
|
|
||||||
import cn.iocoder.mall.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.mall.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.mall.mybatis.core.dataobject.DeletableDO;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -11,9 +14,11 @@ import java.util.List;
|
||||||
/**
|
/**
|
||||||
* 促销活动 DO
|
* 促销活动 DO
|
||||||
*/
|
*/
|
||||||
|
@TableName(value = "promotion_activity", autoResultMap = true)
|
||||||
@Data
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class PromotionActivityDO extends DeletableDO {
|
public class PromotionActivityDO extends BaseDO {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 活动编号
|
* 活动编号
|
||||||
|
@ -59,10 +64,12 @@ public class PromotionActivityDO extends DeletableDO {
|
||||||
/**
|
/**
|
||||||
* 限制折扣字符串,使用 JSON 序列化成字符串存储
|
* 限制折扣字符串,使用 JSON 序列化成字符串存储
|
||||||
*/
|
*/
|
||||||
|
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||||
private TimeLimitedDiscount timeLimitedDiscount;
|
private TimeLimitedDiscount timeLimitedDiscount;
|
||||||
/**
|
/**
|
||||||
* 满减送字符串,使用 JSON 序列化成字符串存储
|
* 满减送字符串,使用 JSON 序列化成字符串存储
|
||||||
*/
|
*/
|
||||||
|
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||||
private FullPrivilege fullPrivilege;
|
private FullPrivilege fullPrivilege;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cn.iocoder.mall.promotionservice.dal.mysql.mapper.activity;
|
package cn.iocoder.mall.promotionservice.dal.mysql.mapper.activity;
|
||||||
|
|
||||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity.PromotionActivityDO;
|
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity.PromotionActivityDO;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@ -8,13 +10,11 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface PromotionActivityMapper {
|
public interface PromotionActivityMapper extends BaseMapper<PromotionActivityDO> {
|
||||||
|
|
||||||
PromotionActivityDO selectById(@Param("id") Integer id);
|
default List<PromotionActivityDO> selectListByStatus(@Param("statuses") Collection<Integer> statuses) {
|
||||||
|
return selectList(new QueryWrapper<PromotionActivityDO>().in("status", statuses));
|
||||||
List<PromotionActivityDO> selectListByStatus(@Param("statuses") Collection<Integer> statuses);
|
}
|
||||||
|
|
||||||
void insert(PromotionActivityDO activity);
|
|
||||||
|
|
||||||
List<PromotionActivityDO> selectListByPage(@Param("title") String title,
|
List<PromotionActivityDO> selectListByPage(@Param("title") String title,
|
||||||
@Param("activityType") Integer activityType,
|
@Param("activityType") Integer activityType,
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
package cn.iocoder.mall.promotionservice.manager;
|
|
@ -0,0 +1,110 @@
|
||||||
|
package cn.iocoder.mall.promotionservice.manager.price;
|
||||||
|
|
||||||
|
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
||||||
|
import cn.iocoder.common.framework.util.CollectionUtils;
|
||||||
|
import cn.iocoder.common.framework.vo.CommonResult;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.sku.ProductSkuRpc;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuListQueryReqDTO;
|
||||||
|
import cn.iocoder.mall.productservice.rpc.sku.dto.ProductSkuRespDTO;
|
||||||
|
import cn.iocoder.mall.promotion.api.enums.PromotionActivityStatusEnum;
|
||||||
|
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityRespDTO;
|
||||||
|
import cn.iocoder.mall.promotion.api.rpc.price.dto.PriceProductCalcReqDTO;
|
||||||
|
import cn.iocoder.mall.promotion.api.rpc.price.dto.PriceProductCalcRespDTO;
|
||||||
|
import cn.iocoder.mall.promotionservice.service.activity.PromotionActivityService;
|
||||||
|
import org.apache.dubbo.config.annotation.DubboReference;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static cn.iocoder.mall.promotion.api.enums.PromotionErrorCodeConstants.PRICE_PRODUCT_SKU_NOT_EXISTS;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class PriceManager {
|
||||||
|
|
||||||
|
@DubboReference(version = "${dubbo.consumer.ProductSkuRpc.version}")
|
||||||
|
private ProductSkuRpc productSkuRpc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PromotionActivityService promotionActivityService;
|
||||||
|
|
||||||
|
public PriceProductCalcRespDTO calcProductPrice(PriceProductCalcReqDTO calcReqDTO) {
|
||||||
|
// TODO 芋艿,补充一些表单校验。例如说,需要传入用户编号。
|
||||||
|
// 校验商品都存在
|
||||||
|
Map<Integer, PriceProductCalcReqDTO.Item> calcProductItemDTOMap = CollectionUtils.convertMap(
|
||||||
|
calcReqDTO.getItems(), PriceProductCalcReqDTO.Item::getSkuId);
|
||||||
|
CommonResult<List<ProductSkuRespDTO>> listProductSkusResult = productSkuRpc.listProductSkus(
|
||||||
|
new ProductSkuListQueryReqDTO().setProductSkuIds(calcProductItemDTOMap.keySet()));
|
||||||
|
listProductSkusResult.checkError();
|
||||||
|
if (calcReqDTO.getItems().size() != listProductSkusResult.getData().size()) {
|
||||||
|
throw ServiceExceptionUtil.exception(PRICE_PRODUCT_SKU_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
// TODO 库存相关
|
||||||
|
// 查询促销活动
|
||||||
|
List<PromotionActivityRespDTO> activityRespDTOs = promotionActivityService.listPromotionActivitiesBySpuIds(
|
||||||
|
calcProductItemDTOMap.keySet(), Collections.singleton(PromotionActivityStatusEnum.RUN.getValue()));
|
||||||
|
// 拼装结果(主要是计算价格)
|
||||||
|
PriceProductCalcRespDTO calcRespDTO = new PriceProductCalcRespDTO();
|
||||||
|
// 1. 创建初始的每一项的数组
|
||||||
|
List<PriceProductCalcRespDTO.Item> calcItemRespDTOs = initCalcOrderPriceItems(
|
||||||
|
listProductSkusResult.getData(), calcProductItemDTOMap);
|
||||||
|
// 2. 计算【限时折扣】促销
|
||||||
|
// modifyPriceByTimeLimitDiscount(items, activityList);
|
||||||
|
// 3. 计算【满减送】促销
|
||||||
|
// 4. 计算优惠劵
|
||||||
|
// 5. 计算最终的价格
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PriceProductCalcRespDTO.Item> initCalcOrderPriceItems(List<ProductSkuRespDTO> skus,
|
||||||
|
Map<Integer, PriceProductCalcReqDTO.Item> calcProductItemDTOMap) {
|
||||||
|
List<PriceProductCalcRespDTO.Item> items = new ArrayList<>();
|
||||||
|
for (ProductSkuRespDTO sku : skus) {
|
||||||
|
PriceProductCalcRespDTO.Item item = new PriceProductCalcRespDTO.Item();
|
||||||
|
items.add(item);
|
||||||
|
// 将是否选中,购物数量,复制到 item 中
|
||||||
|
PriceProductCalcReqDTO.Item calcOrderItem = calcProductItemDTOMap.get(sku.getId());
|
||||||
|
item.setBuyQuantity(calcOrderItem.getQuantity());
|
||||||
|
// 计算初始价格
|
||||||
|
item.setOriginPrice(sku.getPrice());
|
||||||
|
item.setBuyPrice(sku.getPrice());
|
||||||
|
item.setPresentPrice(sku.getPrice());
|
||||||
|
item.setBuyTotal(sku.getPrice() * calcOrderItem.getQuantity());
|
||||||
|
item.setDiscountTotal(0);
|
||||||
|
item.setPresentTotal(item.getBuyTotal());
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private void modifyPriceByTimeLimitDiscount(List<CalcOrderPriceBO.Item> items, List<PromotionActivityBO> activityList) {
|
||||||
|
// for (CalcOrderPriceBO.Item item : items) {
|
||||||
|
// // 获得符合条件的限时折扣
|
||||||
|
// PromotionActivityBO timeLimitedDiscount = activityList.stream()
|
||||||
|
// .filter(activity -> PromotionActivityTypeEnum.TIME_LIMITED_DISCOUNT.getValue().equals(activity.getActivityType())
|
||||||
|
// && activity.getTimeLimitedDiscount().getItems().stream().anyMatch(item0 -> item0.getSpuId().equals(item.getSpu().getId())))
|
||||||
|
// .findFirst().orElse(null);
|
||||||
|
// if (timeLimitedDiscount == null) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// // 计算价格
|
||||||
|
// ProductSkuBO sku = new ProductSkuBO().setId(item.getId()).setSpuId(item.getSpu().getId()).setPrice(item.getPrice());
|
||||||
|
// Integer newPrice = calcSkuPriceByTimeLimitDiscount(sku, timeLimitedDiscount);
|
||||||
|
// if (newPrice.equals(item.getPrice())) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// // 设置优惠
|
||||||
|
// item.setActivity(timeLimitedDiscount);
|
||||||
|
// // 设置价格
|
||||||
|
// item.setBuyPrice(newPrice);
|
||||||
|
// item.setBuyTotal(newPrice * item.getBuyQuantity());
|
||||||
|
// item.setPresentTotal(item.getBuyTotal() - item.getDiscountTotal());
|
||||||
|
// item.setPresentPrice(item.getPresentTotal() / item.getBuyQuantity());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package cn.iocoder.mall.promotionservice.service.activity;
|
package cn.iocoder.mall.promotionservice.service.activity;
|
||||||
|
|
||||||
import cn.iocoder.common.framework.exception.util.ServiceExceptionUtil;
|
|
||||||
import cn.iocoder.mall.promotion.api.enums.PromotionActivityTypeEnum;
|
import cn.iocoder.mall.promotion.api.enums.PromotionActivityTypeEnum;
|
||||||
import cn.iocoder.mall.promotion.api.enums.RangeTypeEnum;
|
import cn.iocoder.mall.promotion.api.enums.RangeTypeEnum;
|
||||||
|
import cn.iocoder.mall.promotion.api.rpc.activity.dto.PromotionActivityRespDTO;
|
||||||
import cn.iocoder.mall.promotionservice.convert.activity.PromotionActivityConvert;
|
import cn.iocoder.mall.promotionservice.convert.activity.PromotionActivityConvert;
|
||||||
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity.PromotionActivityDO;
|
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity.PromotionActivityDO;
|
||||||
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.activity.PromotionActivityMapper;
|
import cn.iocoder.mall.promotionservice.dal.mysql.mapper.activity.PromotionActivityMapper;
|
||||||
|
@ -12,7 +12,6 @@ import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -26,11 +25,25 @@ public class PromotionActivityService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private PromotionActivityMapper promotionActivityMapper;
|
private PromotionActivityMapper promotionActivityMapper;
|
||||||
|
|
||||||
public List<PromotionActivityDO> getPromotionActivityListBySpuId(Integer spuId, Collection<Integer> activityStatuses) {
|
/**
|
||||||
return this.getPromotionActivityListBySpuIds(Collections.singleton(spuId), activityStatuses);
|
* 获取指定商品
|
||||||
|
*
|
||||||
|
* @param spuId
|
||||||
|
* @param activityStatuses
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<PromotionActivityRespDTO> listPromotionActivitiesBySpuId(Integer spuId, Collection<Integer> activityStatuses) {
|
||||||
|
return this.listPromotionActivitiesBySpuIds(Collections.singleton(spuId), activityStatuses);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PromotionActivityDO> getPromotionActivityListBySpuIds(Collection<Integer> spuIds, Collection<Integer> activityStatuses) {
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param spuIds
|
||||||
|
* @param activityStatuses
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<PromotionActivityRespDTO> listPromotionActivitiesBySpuIds(Collection<Integer> spuIds, Collection<Integer> activityStatuses) {
|
||||||
if (spuIds.isEmpty() || activityStatuses.isEmpty()) {
|
if (spuIds.isEmpty() || activityStatuses.isEmpty()) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
@ -64,7 +77,7 @@ public class PromotionActivityService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 返回最终结果
|
// 返回最终结果
|
||||||
return activityList;
|
return PromotionActivityConvert.INSTANCE.convertList(activityList);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PromotionActivityPageBO getPromotionActivityPage(Integer pageNo,Integer pageSize,String title,Integer activityType,Collection<Integer> statuses) {
|
public PromotionActivityPageBO getPromotionActivityPage(Integer pageNo,Integer pageSize,String title,Integer activityType,Collection<Integer> statuses) {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package cn.iocoder.mall.promotionservice.dal.mysql.mapper.activity;
|
||||||
|
|
||||||
|
import cn.iocoder.mall.promotion.api.enums.PromotionActivityStatusEnum;
|
||||||
|
import cn.iocoder.mall.promotionservice.dal.mysql.dataobject.activity.PromotionActivityDO;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||||
|
public class PromotionActivityMapperTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PromotionActivityMapper promotionActivityMapper;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSelectListByStatus() {
|
||||||
|
List<PromotionActivityDO> result = promotionActivityMapper.selectListByStatus(
|
||||||
|
Collections.singleton(PromotionActivityStatusEnum.RUN.getValue()));
|
||||||
|
System.out.println(result.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
package cn.iocoder.mall.promotionservice;
|
Loading…
Reference in New Issue