Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into feature/mall_product

# Conflicts:
#	sql/mysql/mall.sql
#	sql/mysql/ruoyi-vue-pro.sql
#	yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/vo/recharge/AppPayWalletRechargeCreateReqVO.java
#	yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java
#	yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserService.java
This commit is contained in:
YunaiV
2023-11-04 20:48:27 +08:00
194 changed files with 1637 additions and 2116 deletions

View File

@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.promotion.api.bargain;
import cn.iocoder.yudao.module.promotion.service.bargain.BargainActivityService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@@ -11,6 +12,7 @@ import javax.annotation.Resource;
* @author HUIHUI
*/
@Service
@Validated
public class BargainActivityApiImpl implements BargainActivityApi {
@Resource

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.bargain;
import cn.iocoder.yudao.module.promotion.api.bargain.dto.BargainValidateJoinRespDTO;
import cn.iocoder.yudao.module.promotion.service.bargain.BargainRecordService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@@ -12,6 +13,7 @@ import javax.annotation.Resource;
* @author HUIHUI
*/
@Service
@Validated
public class BargainRecordApiImpl implements BargainRecordApi {
@Resource

View File

@@ -1,13 +0,0 @@
package cn.iocoder.yudao.module.promotion.api.combination;
import org.springframework.stereotype.Service;
/**
* 拼团活动 Api 接口实现类
*
* @author HUIHUI
*/
@Service
public class CombinationActivityApiImpl implements CombinationActivityApi {
}

View File

@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.dal.dataobject.combination.CombinationR
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
import cn.iocoder.yudao.module.promotion.service.combination.CombinationRecordService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@@ -20,6 +21,7 @@ import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COMBINA
* @author HUIHUI
*/
@Service
@Validated
public class CombinationRecordApiImpl implements CombinationRecordApi {
@Resource
@@ -44,11 +46,6 @@ public class CombinationRecordApiImpl implements CombinationRecordApi {
return CombinationRecordStatusEnum.isSuccess(record.getStatus());
}
@Override
public void updateRecordStatusToFailed(Long userId, Long orderId) {
recordService.updateCombinationRecordStatusByUserIdAndOrderId(CombinationRecordStatusEnum.FAILED.getStatus(), userId, orderId);
}
@Override
public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId, Long skuId, Integer count) {
return recordService.validateJoinCombination(userId, activityId, headId, skuId, count);

View File

@@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.promotion.convert.coupon.CouponConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@@ -17,6 +18,7 @@ import javax.annotation.Resource;
* @author 芋道源码
*/
@Service
@Validated
public class CouponApiImpl implements CouponApi {
@Resource

View File

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.promotion.api.discount.dto.DiscountProductRespDTO
import cn.iocoder.yudao.module.promotion.convert.discount.DiscountActivityConvert;
import cn.iocoder.yudao.module.promotion.service.discount.DiscountActivityService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collection;
@@ -15,6 +16,7 @@ import java.util.List;
* @author 芋道源码
*/
@Service
@Validated
public class DiscountActivityApiImpl implements DiscountActivityApi {
@Resource

View File

@@ -1,28 +0,0 @@
package cn.iocoder.yudao.module.promotion.api.price;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
import cn.iocoder.yudao.module.promotion.service.price.PriceService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* 价格 API 实现类
*
* @author 芋道源码
*/
@Service
public class PriceApiImpl implements PriceApi {
@Resource
private PriceService priceService;
@Override
public PriceCalculateRespDTO calculatePrice(PriceCalculateReqDTO calculateReqDTO) {
//return priceService.calculatePrice(calculateReqDTO); TODO 没有 calculatePrice 这个方法
return null;
}
}

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.reward;
import cn.iocoder.yudao.module.promotion.api.reward.dto.RewardActivityMatchRespDTO;
import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collection;
@@ -14,6 +15,7 @@ import java.util.List;
* @author 芋道源码
*/
@Service
@Validated
public class RewardActivityApiImpl implements RewardActivityApi {
@Resource

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.promotion.api.seckill;
import cn.iocoder.yudao.module.promotion.api.seckill.dto.SeckillValidateJoinRespDTO;
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@@ -12,6 +13,7 @@ import javax.annotation.Resource;
* @author HUIHUI
*/
@Service
@Validated
public class SeckillActivityApiImpl implements SeckillActivityApi {
@Resource

View File

@@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.ToString;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - Banner Response VO")
@Data
@ToString(callSuper = true)
@@ -12,4 +14,7 @@ public class BannerRespVO extends BannerBaseVO {
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED)
private Long id;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022-07-01 23:59:59")
private LocalDateTime createTime;
}

View File

@@ -96,13 +96,13 @@ public class AppCouponTemplateController {
*/
private Long getProductScopeValue(Integer productScope, Long spuId) {
// 通用券:没有商品范围
if (productScope == null || ObjectUtils.equalsAny(productScope, PromotionProductScopeEnum.ALL.getScope(), null)) {
if (ObjectUtils.equalsAny(productScope, PromotionProductScopeEnum.ALL.getScope(), null)) {
return null;
}
// 品类券:查询商品的品类编号
if (Objects.equals(productScope, PromotionProductScopeEnum.CATEGORY.getScope()) && spuId != null) {
return Optional.ofNullable(productSpuApi.getSpu(spuId))
.map(ProductSpuRespDTO::getCategoryId).orElse(null);
ProductSpuRespDTO spu = productSpuApi.getSpu(spuId);
return spu != null ? spu.getCategoryId() : null;
}
// 商品卷:直接返回
return spuId;

View File

@@ -1,49 +0,0 @@
package cn.iocoder.yudao.module.promotion.convert.price;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Mapper
public interface PriceConvert {
PriceConvert INSTANCE = Mappers.getMapper(PriceConvert.class);
default PriceCalculateRespDTO convert(PriceCalculateReqDTO calculateReqDTO, List<ProductSkuRespDTO> skuList) {
// 创建 PriceCalculateRespDTO 对象
PriceCalculateRespDTO priceCalculate = new PriceCalculateRespDTO();
// 创建它的 Order 属性
PriceCalculateRespDTO.Order order = new PriceCalculateRespDTO.Order().setTotalPrice(0).setDiscountPrice(0)
.setCouponPrice(0).setPointPrice(0).setDeliveryPrice(0).setPayPrice(0)
.setItems(new ArrayList<>()).setCouponId(calculateReqDTO.getCouponId());
priceCalculate.setOrder(order).setPromotions(new ArrayList<>());
// 创建它的 OrderItem 属性
Map<Long, Integer> skuIdCountMap = CollectionUtils.convertMap(calculateReqDTO.getItems(),
PriceCalculateReqDTO.Item::getSkuId, PriceCalculateReqDTO.Item::getCount);
skuList.forEach(sku -> {
Integer count = skuIdCountMap.get(sku.getId());
PriceCalculateRespDTO.OrderItem orderItem = new PriceCalculateRespDTO.OrderItem()
.setSpuId(sku.getSpuId()).setSkuId(sku.getId()).setCount(count)
.setOriginalUnitPrice(sku.getPrice()).setOriginalPrice(sku.getPrice() * count)
.setDiscountPrice(0).setOrderPartPrice(0);
orderItem.setPayPrice(orderItem.getOriginalPrice()).setOrderDividePrice(orderItem.getOriginalPrice());
priceCalculate.getOrder().getItems().add(orderItem);
// 补充价格信息到 Order 中
order.setTotalPrice(order.getTotalPrice() + orderItem.getOriginalPrice())
.setPayPrice(order.getTotalPrice());
});
return priceCalculate;
}
CouponMeetRespDTO convert(CouponDO coupon);
}

View File

@@ -0,0 +1,31 @@
package cn.iocoder.yudao.module.promotion.mq.consumer.coupon;
import cn.iocoder.yudao.module.member.message.user.MemberUserCreateMessage;
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 用户注册时,发送优惠劵的消费者,基 {@link MemberUserCreateMessage} 消息
*
* @author owen
*/
@Component
@Slf4j
public class CouponTakeByRegisterConsumer {
@Resource
private CouponService couponService;
@EventListener
@Async // Spring Event 默认在 Producer 发送的线程,通过 @Async 实现异步
public void onMessage(MemberUserCreateMessage message) {
log.info("[onMessage][消息内容({})]", message);
couponService.takeCouponByRegister(message.getUserId());
}
}

View File

@@ -1,29 +0,0 @@
package cn.iocoder.yudao.module.promotion.mq.consumer.coupon;
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
import cn.iocoder.yudao.module.promotion.mq.message.coupon.UserCreateMessage;
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 针对 {@link UserCreateMessage} 的消费者
*
* @author owen
*/
@Component
@Slf4j
public class UserCreateConsumer extends AbstractStreamMessageListener<UserCreateMessage> {
@Resource
private CouponService couponService;
@Override
public void onMessage(UserCreateMessage message) {
log.info("[onMessage][消息内容({})]", message);
couponService.takeCouponByRegister(message.getUserId());
}
}

View File

@@ -0,0 +1,4 @@
/**
* 消息队列的消费者
*/
package cn.iocoder.yudao.module.promotion.mq.consumer;

View File

@@ -1,29 +0,0 @@
package cn.iocoder.yudao.module.promotion.mq.message.coupon;
import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessage;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
/**
* 会员用户创建消息
*
* @author owen
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class UserCreateMessage extends AbstractStreamMessage {
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
@Override
public String getStreamKey() {
return "member.create.send";
}
}

View File

@@ -0,0 +1,4 @@
/**
* 消息队列的消息
*/
package cn.iocoder.yudao.module.promotion.mq.message;

View File

@@ -0,0 +1,4 @@
/**
* 消息队列的生产者
*/
package cn.iocoder.yudao.module.promotion.mq.producer;

View File

@@ -108,8 +108,8 @@ public class CombinationActivityServiceImpl implements CombinationActivityServic
}
// 2. 校验商品 sku 都存在
Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),
ProductSkuRespDTO::getId);
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(singletonList(spuId));
Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
products.forEach(product -> {
if (!skuMap.containsKey(product.getSkuId())) {
throw exception(SKU_NOT_EXISTS);

View File

@@ -21,15 +21,6 @@ import java.util.Map;
*/
public interface CombinationRecordService {
/**
* 更新拼团状态
*
* @param status 状态
* @param userId 用户编号
* @param orderId 订单编号
*/
void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId);
/**
* 【下单前】校验是否满足拼团活动条件
*
@@ -62,15 +53,6 @@ public interface CombinationRecordService {
*/
CombinationRecordDO getCombinationRecord(Long userId, Long orderId);
/**
* 获取拼团记录
*
* @param userId 用户 id
* @param activityId 活动 id
* @return 拼团记录列表
*/
List<CombinationRecordDO> getCombinationRecordListByUserIdAndActivityId(Long userId, Long activityId);
/**
* 【下单前】校验是否满足拼团活动条件
*

View File

@@ -24,6 +24,7 @@ import cn.iocoder.yudao.module.promotion.dal.mysql.combination.CombinationRecord
import cn.iocoder.yudao.module.promotion.enums.combination.CombinationRecordStatusEnum;
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
@@ -64,27 +65,9 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
private ProductSkuApi productSkuApi;
@Resource
@Lazy
private TradeOrderApi tradeOrderApi;
@Override
@Transactional(rollbackFor = Exception.class)
public void updateCombinationRecordStatusByUserIdAndOrderId(Integer status, Long userId, Long orderId) {
// 校验拼团是否存在
CombinationRecordDO record = validateCombinationRecord(userId, orderId);
// 更新状态
combinationRecordMapper.updateById(new CombinationRecordDO().setId(record.getId()).setStatus(status));
}
private CombinationRecordDO validateCombinationRecord(Long userId, Long orderId) {
// 校验拼团是否存在
CombinationRecordDO recordDO = combinationRecordMapper.selectByUserIdAndOrderId(userId, orderId);
if (recordDO == null) {
throw exception(COMBINATION_RECORD_NOT_EXISTS);
}
return recordDO;
}
// TODO @芋艿:在详细预览下;
@Override
public KeyValue<CombinationActivityDO, CombinationProductDO> validateCombinationRecord(
@@ -229,11 +212,6 @@ public class CombinationRecordServiceImpl implements CombinationRecordService {
return combinationRecordMapper.selectByUserIdAndOrderId(userId, orderId);
}
@Override
public List<CombinationRecordDO> getCombinationRecordListByUserIdAndActivityId(Long userId, Long activityId) {
return combinationRecordMapper.selectListByUserIdAndActivityId(userId, activityId);
}
@Override
public CombinationValidateJoinRespDTO validateJoinCombination(Long userId, Long activityId, Long headId,
Long skuId, Integer count) {

View File

@@ -7,7 +7,6 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
@@ -80,12 +79,11 @@ public class CouponServiceImpl implements CouponService {
public PageResult<CouponDO> getCouponPage(CouponPageReqVO pageReqVO) {
// 获得用户编号
if (StrUtil.isNotEmpty(pageReqVO.getNickname())) {
Set<Long> userIds = CollectionUtils.convertSet(memberUserApi.getUserListByNickname(pageReqVO.getNickname()),
MemberUserRespDTO::getId);
if (CollUtil.isEmpty(userIds)) {
List<MemberUserRespDTO> users = memberUserApi.getUserListByNickname(pageReqVO.getNickname());
if (CollUtil.isEmpty(users)) {
return PageResult.empty();
}
pageReqVO.setUserIds(userIds);
pageReqVO.setUserIds(convertSet(users, MemberUserRespDTO::getId));
}
// 分页查询
return couponMapper.selectPage(pageReqVO);

View File

@@ -1,23 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.price;
import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
import java.util.List;
/**
* 价格计算 Service 接口
*
* @author 芋道源码
*/
public interface PriceService {
/**
* 获得优惠劵的匹配信息列表
*
* @param calculateReqDTO 价格请求
* @return 价格响应
*/
List<CouponMeetRespDTO> getMeetCouponList(PriceCalculateReqDTO calculateReqDTO);
}

View File

@@ -1,96 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.price;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateRespDTO;
import cn.iocoder.yudao.module.promotion.convert.price.PriceConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW;
/**
* 价格计算 Service 实现类
*
* 优惠计算顺序min(限时折扣, 会员折扣) > 满减送 > 优惠券。
* 参考文档:
* 1. <a href="https://help.youzan.com/displaylist/detail_4_4-1-60384">有赞文档:限时折扣、满减送、优惠券哪个优先计算?</a>
*
* TODO 芋艿:进一步完善
* 1. 限时折扣:指定金额、减免金额、折扣
* 2. 满减送:循环、折扣
* 3. 优惠劵:待定
*
* @author 芋道源码
*/
@Service
@Validated
@Slf4j
public class PriceServiceImpl implements PriceService {
@Resource
private CouponService couponService;
@Override
public List<CouponMeetRespDTO> getMeetCouponList(PriceCalculateReqDTO calculateReqDTO) {
// 先计算一轮价格
// PriceCalculateRespDTO priceCalculate = calculatePrice(calculateReqDTO);
PriceCalculateRespDTO priceCalculate = null;
// 获得用户的待使用优惠劵
List<CouponDO> couponList = couponService.getCouponList(calculateReqDTO.getUserId(), CouponStatusEnum.UNUSED.getStatus());
if (CollUtil.isEmpty(couponList)) {
return Collections.emptyList();
}
// 获得优惠劵的匹配信息
return CollectionUtils.convertList(couponList, coupon -> {
CouponMeetRespDTO couponMeetRespDTO = PriceConvert.INSTANCE.convert(coupon);
try {
// 校验优惠劵
couponService.validCoupon(coupon);
// 获得匹配的商品 SKU 数组
// TODO 芋艿:后续处理
// List<PriceCalculateRespDTO.OrderItem> orderItems = getMatchCouponOrderItems(priceCalculate, coupon);
List<PriceCalculateRespDTO.OrderItem> orderItems = null;
if (CollUtil.isEmpty(orderItems)) {
return couponMeetRespDTO.setMeet(false).setMeetTip("所结算商品没有符合条件的商品");
}
// 计算是否满足优惠劵的使用金额
Integer originPrice = getSumValue(orderItems, PriceCalculateRespDTO.OrderItem::getOrderDividePrice, Integer::sum);
assert originPrice != null;
if (originPrice < coupon.getUsePrice()) {
return couponMeetRespDTO.setMeet(false)
// .setMeetTip(String.format("差 %s 元可用优惠劵", formatPrice(coupon.getUsePrice() - originPrice)));
.setMeetTip("所结算的商品中未满足使用的金额");
}
} catch (ServiceException serviceException) {
couponMeetRespDTO.setMeet(false);
if (serviceException.getCode().equals(COUPON_VALID_TIME_NOT_NOW.getCode())) {
couponMeetRespDTO.setMeetTip("优惠劵未到使用时间");
} else {
log.error("[getMeetCouponList][calculateReqDTO({}) 获得优惠劵匹配信息异常]", calculateReqDTO, serviceException);
couponMeetRespDTO.setMeetTip("优惠劵不满足使用条件");
}
return couponMeetRespDTO;
}
// 满足
return couponMeetRespDTO.setMeet(true);
});
}
}

View File

@@ -123,8 +123,8 @@ public class SeckillActivityServiceImpl implements SeckillActivityService {
}
// 2. 校验商品 sku 都存在
Map<Long, ProductSkuRespDTO> skuMap = convertMap(productSkuApi.getSkuListBySpuId(singletonList(spuId)),
ProductSkuRespDTO::getId);
List<ProductSkuRespDTO> skus = productSkuApi.getSkuListBySpuId(singletonList(spuId));
Map<Long, ProductSkuRespDTO> skuMap = convertMap(skus, ProductSkuRespDTO::getId);
products.forEach(product -> {
if (!skuMap.containsKey(product.getSkuId())) {
throw exception(SKU_NOT_EXISTS);

View File

@@ -138,7 +138,7 @@ public class DiscountActivityServiceImplTest extends BaseDbUnitTest {
Long id = dbDiscountActivity.getId();
// 调用
discountActivityService.closeRewardActivity(id);
discountActivityService.closeDiscountActivity(id);
// 校验状态
DiscountActivityDO discountActivity = discountActivityMapper.selectById(id);
assertEquals(discountActivity.getStatus(), PromotionActivityStatusEnum.CLOSE.getStatus());

View File

@@ -1,104 +0,0 @@
package cn.iocoder.yudao.module.promotion.service.price;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.CouponMeetRespDTO;
import cn.iocoder.yudao.module.promotion.api.price.dto.PriceCalculateReqDTO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.coupon.CouponDO;
import cn.iocoder.yudao.module.promotion.enums.common.PromotionProductScopeEnum;
import cn.iocoder.yudao.module.promotion.enums.coupon.CouponStatusEnum;
import cn.iocoder.yudao.module.promotion.service.coupon.CouponService;
import cn.iocoder.yudao.module.promotion.service.reward.RewardActivityService;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.List;
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.module.promotion.enums.ErrorCodeConstants.COUPON_VALID_TIME_NOT_NOW;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;
/**
* {@link PriceServiceImpl} 的单元测试
*
* @author 芋道源码
*/
public class PriceServiceTest extends BaseMockitoUnitTest {
@InjectMocks
private PriceServiceImpl priceService;
@Mock
private RewardActivityService rewardActivityService;
@Mock
private CouponService couponService;
@Mock
private ProductSkuApi productSkuApi;
/**
* 测试满减送活动,不匹配的情况
*/
@Test
public void testCalculatePrice_rewardActivityNotMeet() {
}
@Test
public void testGetMeetCouponList() {
// 准备参数
PriceCalculateReqDTO calculateReqDTO = new PriceCalculateReqDTO().setUserId(1024L)
.setItems(singletonList(new PriceCalculateReqDTO.Item().setSkuId(10L).setCount(2)));
// mock 方法(商品 SKU 信息)
ProductSkuRespDTO productSku = randomPojo(ProductSkuRespDTO.class, o -> o.setId(10L).setPrice(100));
when(productSkuApi.getSkuList(eq(asSet(10L)))).thenReturn(singletonList(productSku));
// mock 方法(情况一:优惠劵未到使用时间)
CouponDO coupon01 = randomPojo(CouponDO.class);
doThrow(new ServiceException(COUPON_VALID_TIME_NOT_NOW)).when(couponService).validCoupon(coupon01);
// mock 方法(情况二:所结算商品没有符合条件的商品)
CouponDO coupon02 = randomPojo(CouponDO.class);
// mock 方法(情况三:使用金额不足)
CouponDO coupon03 = randomPojo(CouponDO.class, o -> o.setProductScope(PromotionProductScopeEnum.ALL.getScope())
.setUsePrice(300));
// mock 方法(情况五:满足条件)
CouponDO coupon04 = randomPojo(CouponDO.class, o -> o.setProductScope(PromotionProductScopeEnum.ALL.getScope())
.setUsePrice(190));
// mock 方法(获得用户的待使用优惠劵)
when(couponService.getCouponList(eq(1024L), eq(CouponStatusEnum.UNUSED.getStatus())))
.thenReturn(asList(coupon01, coupon02, coupon03, coupon04));
// 调用
List<CouponMeetRespDTO> list = priceService.getMeetCouponList(calculateReqDTO);
// 断言
assertEquals(list.size(), 4);
// 断言情况一:优惠劵未到使用时间
CouponMeetRespDTO couponMeetRespDTO01 = list.get(0);
assertPojoEquals(couponMeetRespDTO01, coupon01);
assertFalse(couponMeetRespDTO01.getMeet());
assertEquals(couponMeetRespDTO01.getMeetTip(), "优惠劵未到使用时间");
// 断言情况二:所结算商品没有符合条件的商品
CouponMeetRespDTO couponMeetRespDTO02 = list.get(1);
assertPojoEquals(couponMeetRespDTO02, coupon02);
assertFalse(couponMeetRespDTO02.getMeet());
assertEquals(couponMeetRespDTO02.getMeetTip(), "所结算商品没有符合条件的商品");
// 断言情况三:差 %s 元可用优惠劵
CouponMeetRespDTO couponMeetRespDTO03 = list.get(2);
assertPojoEquals(couponMeetRespDTO03, coupon03);
assertFalse(couponMeetRespDTO03.getMeet());
assertEquals(couponMeetRespDTO03.getMeetTip(), "所结算的商品中未满足使用的金额");
// 断言情况四:满足条件
CouponMeetRespDTO couponMeetRespDTO04 = list.get(3);
assertPojoEquals(couponMeetRespDTO04, coupon04);
assertTrue(couponMeetRespDTO04.getMeet());
assertNull(couponMeetRespDTO04.getMeetTip());
}
}