refactor: 盲盒功能代码优化和完善
修复和改进:
- 修复字段映射:blind_box_gift_id -> blind_box_id
- 移除不必要的 @Version 乐观锁字段
- 优化 Mapper 方法:统一使用 listActiveEntries,简化查询逻辑
- 新增客户端接口:盲盒购买、奖励查询和兑现
- 增强权限校验:奖励兑现时验证客户身份
- 完善单元测试:增加客户身份验证测试用例
- 代码格式化:调整 import 顺序,优化代码结构
客户端 API:
- GET /wx/blind-box/config/list - 查询可用盲盒列表
- POST /wx/blind-box/order/purchase - 购买盲盒
- GET /wx/blind-box/reward/list - 查询我的盲盒奖励
- POST /wx/blind-box/reward/{id}/dispatch - 兑现盲盒奖励
其他优化:
- 增强 SQL 查询安全性,添加 deleted 字段过滤
- 优化店员提成计算逻辑
- 改进参数可选性(levelId 参数改为可选)
This commit is contained in:
@@ -4,8 +4,8 @@ import cn.hutool.core.util.StrUtil;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.starry.admin.common.exception.CustomException;
|
import com.starry.admin.common.exception.CustomException;
|
||||||
import com.starry.admin.modules.blindbox.module.entity.BlindBoxConfigEntity;
|
|
||||||
import com.starry.admin.modules.blindbox.module.constant.BlindBoxConfigStatus;
|
import com.starry.admin.modules.blindbox.module.constant.BlindBoxConfigStatus;
|
||||||
|
import com.starry.admin.modules.blindbox.module.entity.BlindBoxConfigEntity;
|
||||||
import com.starry.admin.modules.blindbox.service.BlindBoxConfigService;
|
import com.starry.admin.modules.blindbox.service.BlindBoxConfigService;
|
||||||
import com.starry.admin.utils.SecurityUtils;
|
import com.starry.admin.utils.SecurityUtils;
|
||||||
import com.starry.common.result.R;
|
import com.starry.common.result.R;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.starry.admin.modules.blindbox.mapper;
|
|||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.starry.admin.modules.blindbox.module.dto.BlindBoxCandidate;
|
import com.starry.admin.modules.blindbox.module.dto.BlindBoxCandidate;
|
||||||
import com.starry.admin.modules.blindbox.module.entity.BlindBoxPoolEntity;
|
import com.starry.admin.modules.blindbox.module.entity.BlindBoxPoolEntity;
|
||||||
import com.starry.admin.modules.blindbox.module.constant.BlindBoxPoolStatus;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
@@ -17,24 +16,24 @@ public interface BlindBoxPoolMapper extends BaseMapper<BlindBoxPoolEntity> {
|
|||||||
@Select({
|
@Select({
|
||||||
"SELECT id AS poolId,",
|
"SELECT id AS poolId,",
|
||||||
" tenant_id AS tenantId,",
|
" tenant_id AS tenantId,",
|
||||||
" blind_box_gift_id AS blindBoxId,",
|
" blind_box_id AS blindBoxId,",
|
||||||
" reward_gift_id AS rewardGiftId,",
|
" reward_gift_id AS rewardGiftId,",
|
||||||
" reward_price AS rewardPrice,",
|
" reward_price AS rewardPrice,",
|
||||||
" weight,",
|
" weight,",
|
||||||
" remaining_stock AS remainingStock",
|
" remaining_stock AS remainingStock",
|
||||||
"FROM blind_box_pool",
|
"FROM blind_box_pool",
|
||||||
"WHERE tenant_id = #{tenantId}",
|
"WHERE tenant_id = #{tenantId}",
|
||||||
" AND blind_box_gift_id = #{blindBoxId}",
|
" AND blind_box_id = #{blindBoxId}",
|
||||||
" AND status = #{enabledStatus}",
|
" AND status = 1",
|
||||||
|
" AND deleted = 0",
|
||||||
" AND (valid_from IS NULL OR valid_from <= #{now})",
|
" AND (valid_from IS NULL OR valid_from <= #{now})",
|
||||||
" AND (valid_to IS NULL OR valid_to >= #{now})",
|
" AND (valid_to IS NULL OR valid_to >= #{now})",
|
||||||
" AND (remaining_stock IS NULL OR remaining_stock > 0)"
|
" AND (remaining_stock IS NULL OR remaining_stock > 0)"
|
||||||
})
|
})
|
||||||
List<BlindBoxCandidate> listEntries(
|
List<BlindBoxCandidate> listActiveEntries(
|
||||||
@Param("tenantId") String tenantId,
|
@Param("tenantId") String tenantId,
|
||||||
@Param("blindBoxId") String blindBoxId,
|
@Param("blindBoxId") String blindBoxId,
|
||||||
@Param("now") LocalDateTime now,
|
@Param("now") LocalDateTime now);
|
||||||
@Param("enabledStatus") int enabledStatus);
|
|
||||||
|
|
||||||
@Update({
|
@Update({
|
||||||
"UPDATE blind_box_pool",
|
"UPDATE blind_box_pool",
|
||||||
@@ -45,6 +44,7 @@ public interface BlindBoxPoolMapper extends BaseMapper<BlindBoxPoolEntity> {
|
|||||||
"WHERE tenant_id = #{tenantId}",
|
"WHERE tenant_id = #{tenantId}",
|
||||||
" AND id = #{poolId}",
|
" AND id = #{poolId}",
|
||||||
" AND reward_gift_id = #{rewardGiftId}",
|
" AND reward_gift_id = #{rewardGiftId}",
|
||||||
|
" AND deleted = 0",
|
||||||
" AND (remaining_stock IS NULL OR remaining_stock > 0)"
|
" AND (remaining_stock IS NULL OR remaining_stock > 0)"
|
||||||
})
|
})
|
||||||
int consumeRewardStock(
|
int consumeRewardStock(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.starry.admin.modules.blindbox.mapper;
|
|||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.starry.admin.modules.blindbox.module.entity.BlindBoxRewardEntity;
|
import com.starry.admin.modules.blindbox.module.entity.BlindBoxRewardEntity;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
@@ -29,4 +30,17 @@ public interface BlindBoxRewardMapper extends BaseMapper<BlindBoxRewardEntity> {
|
|||||||
@Param("clerkId") String clerkId,
|
@Param("clerkId") String clerkId,
|
||||||
@Param("orderId") String orderId,
|
@Param("orderId") String orderId,
|
||||||
@Param("usedTime") LocalDateTime usedTime);
|
@Param("usedTime") LocalDateTime usedTime);
|
||||||
|
|
||||||
|
@Select({
|
||||||
|
"SELECT * FROM blind_box_reward",
|
||||||
|
"WHERE tenant_id = #{tenantId}",
|
||||||
|
" AND customer_id = #{customerId}",
|
||||||
|
" AND deleted = 0",
|
||||||
|
" AND (#{status} IS NULL OR status = #{status})",
|
||||||
|
"ORDER BY created_time DESC"
|
||||||
|
})
|
||||||
|
List<BlindBoxRewardEntity> listByCustomer(
|
||||||
|
@Param("tenantId") String tenantId,
|
||||||
|
@Param("customerId") String customerId,
|
||||||
|
@Param("status") String status);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.starry.admin.modules.blindbox.module.entity;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.baomidou.mybatisplus.annotation.Version;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import com.starry.common.domain.BaseEntity;
|
import com.starry.common.domain.BaseEntity;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -20,7 +19,7 @@ public class BlindBoxRewardEntity extends BaseEntity<BlindBoxRewardEntity> {
|
|||||||
private String tenantId;
|
private String tenantId;
|
||||||
private String customerId;
|
private String customerId;
|
||||||
|
|
||||||
@TableField("blind_box_gift_id")
|
@TableField("blind_box_id")
|
||||||
private String blindBoxId;
|
private String blindBoxId;
|
||||||
private String rewardGiftId;
|
private String rewardGiftId;
|
||||||
private BigDecimal rewardPrice;
|
private BigDecimal rewardPrice;
|
||||||
@@ -42,6 +41,4 @@ public class BlindBoxRewardEntity extends BaseEntity<BlindBoxRewardEntity> {
|
|||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
private LocalDateTime usedTime;
|
private LocalDateTime usedTime;
|
||||||
|
|
||||||
@Version
|
|
||||||
private Integer version;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.starry.admin.modules.order.module.dto.PaymentInfo;
|
|||||||
import com.starry.admin.modules.order.service.IOrderLifecycleService;
|
import com.starry.admin.modules.order.service.IOrderLifecycleService;
|
||||||
import com.starry.admin.modules.order.service.IPlayOrderInfoService;
|
import com.starry.admin.modules.order.service.IPlayOrderInfoService;
|
||||||
import com.starry.admin.modules.shop.module.entity.PlayGiftInfoEntity;
|
import com.starry.admin.modules.shop.module.entity.PlayGiftInfoEntity;
|
||||||
|
import com.starry.admin.modules.shop.service.IPlayClerkGiftInfoService;
|
||||||
import com.starry.admin.modules.shop.service.IPlayGiftInfoService;
|
import com.starry.admin.modules.shop.service.IPlayGiftInfoService;
|
||||||
import com.starry.common.utils.IdUtils;
|
import com.starry.common.utils.IdUtils;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
@@ -26,6 +27,7 @@ public class BlindBoxDispatchService {
|
|||||||
private final IOrderLifecycleService orderLifecycleService;
|
private final IOrderLifecycleService orderLifecycleService;
|
||||||
private final IPlayOrderInfoService orderInfoService;
|
private final IPlayOrderInfoService orderInfoService;
|
||||||
private final IPlayGiftInfoService giftInfoService;
|
private final IPlayGiftInfoService giftInfoService;
|
||||||
|
private final IPlayClerkGiftInfoService clerkGiftInfoService;
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public OrderPlacementResult dispatchRewardOrder(BlindBoxRewardEntity reward, String clerkId) {
|
public OrderPlacementResult dispatchRewardOrder(BlindBoxRewardEntity reward, String clerkId) {
|
||||||
@@ -71,9 +73,13 @@ public class BlindBoxDispatchService {
|
|||||||
.remark("盲盒奖励兑现")
|
.remark("盲盒奖励兑现")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return orderLifecycleService.placeOrder(OrderPlacementCommand.builder()
|
OrderPlacementResult result = orderLifecycleService.placeOrder(OrderPlacementCommand.builder()
|
||||||
.orderContext(context)
|
.orderContext(context)
|
||||||
.balanceOperationAction("盲盒奖励兑现")
|
.balanceOperationAction("盲盒奖励兑现")
|
||||||
.build());
|
.build());
|
||||||
|
if (clerkId != null) {
|
||||||
|
clerkGiftInfoService.incrementGiftCount(clerkId, giftInfo.getId(), reward.getTenantId(), 1);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import java.time.format.DateTimeFormatter;
|
|||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package com.starry.admin.modules.blindbox.service;
|
|||||||
import com.starry.admin.common.exception.CustomException;
|
import com.starry.admin.common.exception.CustomException;
|
||||||
import com.starry.admin.modules.blindbox.mapper.BlindBoxPoolMapper;
|
import com.starry.admin.modules.blindbox.mapper.BlindBoxPoolMapper;
|
||||||
import com.starry.admin.modules.blindbox.mapper.BlindBoxRewardMapper;
|
import com.starry.admin.modules.blindbox.mapper.BlindBoxRewardMapper;
|
||||||
import com.starry.admin.modules.blindbox.module.constant.BlindBoxPoolStatus;
|
|
||||||
import com.starry.admin.modules.blindbox.module.constant.BlindBoxRewardStatus;
|
import com.starry.admin.modules.blindbox.module.constant.BlindBoxRewardStatus;
|
||||||
import com.starry.admin.modules.blindbox.module.dto.BlindBoxCandidate;
|
import com.starry.admin.modules.blindbox.module.dto.BlindBoxCandidate;
|
||||||
import com.starry.admin.modules.blindbox.module.entity.BlindBoxConfigEntity;
|
import com.starry.admin.modules.blindbox.module.entity.BlindBoxConfigEntity;
|
||||||
@@ -76,11 +75,7 @@ public class BlindBoxService {
|
|||||||
if (!tenantId.equals(config.getTenantId())) {
|
if (!tenantId.equals(config.getTenantId())) {
|
||||||
throw new CustomException("盲盒不存在或已下架");
|
throw new CustomException("盲盒不存在或已下架");
|
||||||
}
|
}
|
||||||
List<BlindBoxCandidate> candidates = poolMapper.listEntries(
|
List<BlindBoxCandidate> candidates = poolMapper.listActiveEntries(tenantId, blindBoxId, now);
|
||||||
tenantId,
|
|
||||||
blindBoxId,
|
|
||||||
now,
|
|
||||||
BlindBoxPoolStatus.ENABLED.getCode());
|
|
||||||
if (CollectionUtils.isEmpty(candidates)) {
|
if (CollectionUtils.isEmpty(candidates)) {
|
||||||
throw new CustomException("盲盒奖池暂无可用奖励");
|
throw new CustomException("盲盒奖池暂无可用奖励");
|
||||||
}
|
}
|
||||||
@@ -111,15 +106,18 @@ public class BlindBoxService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public OrderPlacementResult dispatchReward(String rewardId, String clerkId) {
|
public OrderPlacementResult dispatchReward(String rewardId, String clerkId, String customerId) {
|
||||||
BlindBoxRewardEntity reward = rewardMapper.lockByIdForUpdate(rewardId);
|
BlindBoxRewardEntity reward = rewardMapper.lockByIdForUpdate(rewardId);
|
||||||
if (reward == null) {
|
if (reward == null) {
|
||||||
throw new CustomException("盲盒奖励不存在");
|
throw new CustomException("盲盒奖励不存在");
|
||||||
}
|
}
|
||||||
|
if (customerId != null && !customerId.equals(reward.getCustomerId())) {
|
||||||
|
throw new CustomException("无权操作该盲盒奖励");
|
||||||
|
}
|
||||||
|
LocalDateTime now = LocalDateTime.now(clock);
|
||||||
if (!BlindBoxRewardStatus.UNUSED.getCode().equals(reward.getStatus())) {
|
if (!BlindBoxRewardStatus.UNUSED.getCode().equals(reward.getStatus())) {
|
||||||
throw new CustomException("盲盒奖励已使用");
|
throw new CustomException("盲盒奖励已使用");
|
||||||
}
|
}
|
||||||
LocalDateTime now = LocalDateTime.now(clock);
|
|
||||||
if (reward.getExpiresAt() != null && reward.getExpiresAt().isBefore(now)) {
|
if (reward.getExpiresAt() != null && reward.getExpiresAt().isBefore(now)) {
|
||||||
throw new CustomException("盲盒奖励已过期");
|
throw new CustomException("盲盒奖励已过期");
|
||||||
}
|
}
|
||||||
@@ -160,6 +158,10 @@ public class BlindBoxService {
|
|||||||
: value.setScale(2, RoundingMode.HALF_UP);
|
: value.setScale(2, RoundingMode.HALF_UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public java.util.List<BlindBoxRewardEntity> listRewards(String tenantId, String customerId, String status) {
|
||||||
|
return rewardMapper.listByCustomer(tenantId, customerId, status);
|
||||||
|
}
|
||||||
|
|
||||||
public interface RandomAdapter {
|
public interface RandomAdapter {
|
||||||
double nextDouble();
|
double nextDouble();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ package com.starry.admin.modules.blindbox.service.impl;
|
|||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.starry.admin.common.exception.CustomException;
|
import com.starry.admin.common.exception.CustomException;
|
||||||
import com.starry.admin.modules.blindbox.mapper.BlindBoxConfigMapper;
|
import com.starry.admin.modules.blindbox.mapper.BlindBoxConfigMapper;
|
||||||
|
import com.starry.admin.modules.blindbox.module.constant.BlindBoxConfigStatus;
|
||||||
import com.starry.admin.modules.blindbox.module.entity.BlindBoxConfigEntity;
|
import com.starry.admin.modules.blindbox.module.entity.BlindBoxConfigEntity;
|
||||||
import com.starry.admin.modules.blindbox.service.BlindBoxConfigService;
|
import com.starry.admin.modules.blindbox.service.BlindBoxConfigService;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.starry.admin.modules.blindbox.module.constant.BlindBoxConfigStatus;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package com.starry.admin.modules.weichat.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import com.starry.admin.common.aspect.CustomUserLogin;
|
||||||
|
import com.starry.admin.common.conf.ThreadLocalRequestDetail;
|
||||||
|
import com.starry.admin.common.exception.CustomException;
|
||||||
|
import com.starry.admin.modules.blindbox.module.entity.BlindBoxConfigEntity;
|
||||||
|
import com.starry.admin.modules.blindbox.service.BlindBoxConfigService;
|
||||||
|
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
|
||||||
|
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxConfigView;
|
||||||
|
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxPurchaseRequest;
|
||||||
|
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxPurchaseResult;
|
||||||
|
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxRewardDispatchRequest;
|
||||||
|
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxRewardView;
|
||||||
|
import com.starry.admin.modules.weichat.service.WxBlindBoxOrderService;
|
||||||
|
import com.starry.common.result.R;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/wx/blind-box")
|
||||||
|
@Validated
|
||||||
|
public class WxBlindBoxController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BlindBoxConfigService blindBoxConfigService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private WxBlindBoxOrderService wxBlindBoxOrderService;
|
||||||
|
|
||||||
|
@CustomUserLogin
|
||||||
|
@GetMapping("/config/list")
|
||||||
|
public R listConfigs() {
|
||||||
|
PlayCustomUserInfoEntity user = ThreadLocalRequestDetail.getCustomUserInfo();
|
||||||
|
if (user == null) {
|
||||||
|
throw new CustomException("用户未登录");
|
||||||
|
}
|
||||||
|
List<BlindBoxConfigEntity> configs = blindBoxConfigService.listActiveByTenant(user.getTenantId());
|
||||||
|
List<BlindBoxConfigView> views = CollUtil.emptyIfNull(configs).stream()
|
||||||
|
.map(this::toConfigView)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return R.ok(views);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CustomUserLogin
|
||||||
|
@PostMapping("/order/purchase")
|
||||||
|
public R purchase(@Valid @RequestBody BlindBoxPurchaseRequest request) {
|
||||||
|
BlindBoxPurchaseResult result = wxBlindBoxOrderService.purchase(request);
|
||||||
|
return R.ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CustomUserLogin
|
||||||
|
@PostMapping("/reward/{id}/dispatch")
|
||||||
|
public R dispatch(@PathVariable("id") String rewardId, @Valid @RequestBody BlindBoxRewardDispatchRequest body) {
|
||||||
|
BlindBoxRewardView view = wxBlindBoxOrderService.dispatchReward(rewardId, body.getClerkId());
|
||||||
|
return R.ok(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CustomUserLogin
|
||||||
|
@GetMapping("/reward/list")
|
||||||
|
public R listRewards(@RequestParam(value = "status", required = false) String status) {
|
||||||
|
PlayCustomUserInfoEntity user = ThreadLocalRequestDetail.getCustomUserInfo();
|
||||||
|
if (user == null) {
|
||||||
|
throw new CustomException("用户未登录");
|
||||||
|
}
|
||||||
|
List<BlindBoxRewardView> rewards = wxBlindBoxOrderService.listRewards(user.getTenantId(), user.getId(), status);
|
||||||
|
return R.ok(rewards);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlindBoxConfigView toConfigView(BlindBoxConfigEntity entity) {
|
||||||
|
BlindBoxConfigView view = new BlindBoxConfigView();
|
||||||
|
view.setId(entity.getId());
|
||||||
|
view.setName(entity.getName());
|
||||||
|
view.setCoverUrl(entity.getCoverUrl());
|
||||||
|
view.setDescription(entity.getDescription());
|
||||||
|
view.setPrice(entity.getPrice());
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,7 +57,7 @@ public class WxClerkCommodityController {
|
|||||||
@ApiResponses({
|
@ApiResponses({
|
||||||
@ApiResponse(code = 200, message = "操作成功", response = PlayCommodityReturnVo.class, responseContainer = "List")})
|
@ApiResponse(code = 200, message = "操作成功", response = PlayCommodityReturnVo.class, responseContainer = "List")})
|
||||||
@GetMapping("/custom/queryClerkAllCommodityByLevel")
|
@GetMapping("/custom/queryClerkAllCommodityByLevel")
|
||||||
public R queryClerkAllCommodityByLevel(@RequestParam("id") String levelId) {
|
public R queryClerkAllCommodityByLevel(@RequestParam(value = "id", required = false) String levelId) {
|
||||||
List<PlayCommodityAndLevelInfoEntity> levelInfoEntities = iPlayCommodityAndLevelInfoService.selectAll();
|
List<PlayCommodityAndLevelInfoEntity> levelInfoEntities = iPlayCommodityAndLevelInfoService.selectAll();
|
||||||
List<PlayCommodityReturnVo> tree = playCommodityInfoService.selectTree();
|
List<PlayCommodityReturnVo> tree = playCommodityInfoService.selectTree();
|
||||||
if (levelId == null || levelId.isEmpty()) {
|
if (levelId == null || levelId.isEmpty()) {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.starry.admin.modules.weichat.entity.blindbox;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 盲盒配置前端视图。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class BlindBoxConfigView {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String coverUrl;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
private BigDecimal price;
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.starry.admin.modules.weichat.entity.blindbox;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class BlindBoxPurchaseRequest {
|
||||||
|
|
||||||
|
@NotBlank(message = "盲盒ID不能为空")
|
||||||
|
private String blindBoxId;
|
||||||
|
|
||||||
|
@NotBlank(message = "店员ID不能为空")
|
||||||
|
private String clerkId;
|
||||||
|
|
||||||
|
private String weiChatCode;
|
||||||
|
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.starry.admin.modules.weichat.entity.blindbox;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class BlindBoxPurchaseResult {
|
||||||
|
|
||||||
|
private String orderId;
|
||||||
|
|
||||||
|
private BlindBoxRewardInfo reward;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public static class BlindBoxRewardInfo {
|
||||||
|
|
||||||
|
private String rewardId;
|
||||||
|
|
||||||
|
private String blindBoxId;
|
||||||
|
|
||||||
|
private String blindBoxName;
|
||||||
|
|
||||||
|
private String blindBoxCover;
|
||||||
|
|
||||||
|
private String rewardGiftId;
|
||||||
|
|
||||||
|
private String rewardGiftName;
|
||||||
|
|
||||||
|
private String rewardGiftImage;
|
||||||
|
|
||||||
|
private BigDecimal rewardGiftPrice;
|
||||||
|
|
||||||
|
private BigDecimal boxPrice;
|
||||||
|
|
||||||
|
private LocalDateTime expiresAt;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.starry.admin.modules.weichat.entity.blindbox;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class BlindBoxRewardDispatchRequest {
|
||||||
|
|
||||||
|
@NotBlank(message = "店员ID不能为空")
|
||||||
|
private String clerkId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.starry.admin.modules.weichat.entity.blindbox;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class BlindBoxRewardView {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String blindBoxId;
|
||||||
|
|
||||||
|
private String blindBoxName;
|
||||||
|
|
||||||
|
private String blindBoxCover;
|
||||||
|
|
||||||
|
private String rewardGiftId;
|
||||||
|
|
||||||
|
private String rewardGiftName;
|
||||||
|
|
||||||
|
private String rewardGiftImage;
|
||||||
|
|
||||||
|
private BigDecimal rewardGiftPrice;
|
||||||
|
|
||||||
|
private BigDecimal boxPrice;
|
||||||
|
|
||||||
|
private LocalDateTime expiresAt;
|
||||||
|
|
||||||
|
private String status;
|
||||||
|
}
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
package com.starry.admin.modules.weichat.service;
|
||||||
|
|
||||||
|
import com.starry.admin.common.conf.ThreadLocalRequestDetail;
|
||||||
|
import com.starry.admin.common.exception.CustomException;
|
||||||
|
import com.starry.admin.modules.blindbox.mapper.BlindBoxRewardMapper;
|
||||||
|
import com.starry.admin.modules.blindbox.module.entity.BlindBoxConfigEntity;
|
||||||
|
import com.starry.admin.modules.blindbox.module.entity.BlindBoxRewardEntity;
|
||||||
|
import com.starry.admin.modules.blindbox.service.BlindBoxConfigService;
|
||||||
|
import com.starry.admin.modules.blindbox.service.BlindBoxService;
|
||||||
|
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
|
||||||
|
import com.starry.admin.modules.custom.service.IPlayCustomUserInfoService;
|
||||||
|
import com.starry.admin.modules.order.module.constant.OrderConstant;
|
||||||
|
import com.starry.admin.modules.order.module.constant.OrderConstant.OrderActor;
|
||||||
|
import com.starry.admin.modules.order.module.constant.OrderConstant.RewardType;
|
||||||
|
import com.starry.admin.modules.order.module.dto.CommodityInfo;
|
||||||
|
import com.starry.admin.modules.order.module.dto.OrderCreationContext;
|
||||||
|
import com.starry.admin.modules.order.module.dto.OrderPlacementCommand;
|
||||||
|
import com.starry.admin.modules.order.module.dto.OrderPlacementResult;
|
||||||
|
import com.starry.admin.modules.order.module.dto.PaymentInfo;
|
||||||
|
import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity;
|
||||||
|
import com.starry.admin.modules.order.service.IOrderLifecycleService;
|
||||||
|
import com.starry.admin.modules.order.service.IPlayOrderInfoService;
|
||||||
|
import com.starry.admin.modules.shop.mapper.PlayGiftInfoMapper;
|
||||||
|
import com.starry.admin.modules.shop.module.entity.PlayGiftInfoEntity;
|
||||||
|
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxPurchaseRequest;
|
||||||
|
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxPurchaseResult;
|
||||||
|
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxPurchaseResult.BlindBoxRewardInfo;
|
||||||
|
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxRewardView;
|
||||||
|
import com.starry.common.utils.IdUtils;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class WxBlindBoxOrderService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BlindBoxConfigService blindBoxConfigService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BlindBoxService blindBoxService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IOrderLifecycleService orderLifecycleService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IPlayOrderInfoService playOrderInfoService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IPlayCustomUserInfoService customUserInfoService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PlayGiftInfoMapper playGiftInfoMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private BlindBoxRewardMapper blindBoxRewardMapper;
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public BlindBoxPurchaseResult purchase(BlindBoxPurchaseRequest request) {
|
||||||
|
PlayCustomUserInfoEntity sessionUser = ThreadLocalRequestDetail.getCustomUserInfo();
|
||||||
|
if (sessionUser == null || sessionUser.getId() == null) {
|
||||||
|
throw new CustomException("用户未登录");
|
||||||
|
}
|
||||||
|
PlayCustomUserInfoEntity customer = customUserInfoService.selectById(sessionUser.getId());
|
||||||
|
if (customer == null) {
|
||||||
|
throw new CustomException("用户不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
BlindBoxConfigEntity config = blindBoxConfigService.requireById(request.getBlindBoxId());
|
||||||
|
if (!Objects.equals(config.getTenantId(), customer.getTenantId())) {
|
||||||
|
throw new CustomException("盲盒不存在或已下架");
|
||||||
|
}
|
||||||
|
if (!Objects.equals(config.getStatus(), 1)) {
|
||||||
|
throw new CustomException("盲盒已下架");
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal boxPrice = Objects.requireNonNull(config.getPrice(), "盲盒价格未配置");
|
||||||
|
if (boxPrice.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
throw new CustomException("盲盒价格异常");
|
||||||
|
}
|
||||||
|
|
||||||
|
String orderId = IdUtils.getUuid();
|
||||||
|
OrderCreationContext orderRequest = buildOrderRequest(orderId, request, customer, config, boxPrice);
|
||||||
|
OrderPlacementResult result = orderLifecycleService.placeOrder(OrderPlacementCommand.builder()
|
||||||
|
.orderContext(orderRequest)
|
||||||
|
.balanceOperationAction("购买盲盒")
|
||||||
|
.build());
|
||||||
|
PlayOrderInfoEntity order = result.getOrder();
|
||||||
|
|
||||||
|
BlindBoxRewardEntity reward = blindBoxService.drawReward(
|
||||||
|
customer.getTenantId(),
|
||||||
|
orderId,
|
||||||
|
customer.getId(),
|
||||||
|
config.getId(),
|
||||||
|
UUID.randomUUID().toString());
|
||||||
|
|
||||||
|
PlayGiftInfoEntity giftInfo = playGiftInfoMapper.selectById(reward.getRewardGiftId());
|
||||||
|
|
||||||
|
return BlindBoxPurchaseResult.builder()
|
||||||
|
.orderId(order.getId())
|
||||||
|
.reward(buildRewardInfo(reward, config, giftInfo))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BlindBoxRewardView> listRewards(String tenantId, String customerId, String status) {
|
||||||
|
return blindBoxService.listRewards(tenantId, customerId, status).stream()
|
||||||
|
.map(this::toRewardView)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public BlindBoxRewardView dispatchReward(String rewardId, String clerkId) {
|
||||||
|
PlayCustomUserInfoEntity sessionUser = ThreadLocalRequestDetail.getCustomUserInfo();
|
||||||
|
if (sessionUser == null || sessionUser.getId() == null) {
|
||||||
|
throw new CustomException("用户未登录");
|
||||||
|
}
|
||||||
|
blindBoxService.dispatchReward(rewardId, clerkId, sessionUser.getId());
|
||||||
|
BlindBoxRewardEntity updated = blindBoxRewardMapper.selectById(rewardId);
|
||||||
|
if (updated == null) {
|
||||||
|
throw new CustomException("盲盒奖励不存在");
|
||||||
|
}
|
||||||
|
return toRewardView(updated);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlindBoxRewardView toRewardView(BlindBoxRewardEntity reward) {
|
||||||
|
BlindBoxConfigEntity config = blindBoxConfigService.getById(reward.getBlindBoxId());
|
||||||
|
PlayGiftInfoEntity gift = playGiftInfoMapper.selectById(reward.getRewardGiftId());
|
||||||
|
return BlindBoxRewardView.builder()
|
||||||
|
.id(reward.getId())
|
||||||
|
.blindBoxId(reward.getBlindBoxId())
|
||||||
|
.blindBoxName(config != null ? config.getName() : null)
|
||||||
|
.blindBoxCover(config != null ? config.getCoverUrl() : null)
|
||||||
|
.rewardGiftId(reward.getRewardGiftId())
|
||||||
|
.rewardGiftName(gift != null ? gift.getName() : reward.getRewardGiftId())
|
||||||
|
.rewardGiftImage(gift != null ? gift.getUrl() : null)
|
||||||
|
.rewardGiftPrice(reward.getRewardPrice())
|
||||||
|
.boxPrice(reward.getBoxPrice())
|
||||||
|
.expiresAt(reward.getExpiresAt())
|
||||||
|
.status(reward.getStatus())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlindBoxRewardInfo buildRewardInfo(
|
||||||
|
BlindBoxRewardEntity reward,
|
||||||
|
BlindBoxConfigEntity config,
|
||||||
|
PlayGiftInfoEntity giftInfo) {
|
||||||
|
return BlindBoxRewardInfo.builder()
|
||||||
|
.rewardId(reward.getId())
|
||||||
|
.blindBoxId(reward.getBlindBoxId())
|
||||||
|
.blindBoxName(config != null ? config.getName() : null)
|
||||||
|
.blindBoxCover(config != null ? config.getCoverUrl() : null)
|
||||||
|
.rewardGiftId(reward.getRewardGiftId())
|
||||||
|
.rewardGiftName(giftInfo != null ? giftInfo.getName() : reward.getRewardGiftId())
|
||||||
|
.rewardGiftImage(giftInfo != null ? giftInfo.getUrl() : null)
|
||||||
|
.rewardGiftPrice(reward.getRewardPrice())
|
||||||
|
.boxPrice(reward.getBoxPrice())
|
||||||
|
.expiresAt(reward.getExpiresAt())
|
||||||
|
.status(reward.getStatus())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private OrderCreationContext buildOrderRequest(
|
||||||
|
String orderId,
|
||||||
|
BlindBoxPurchaseRequest request,
|
||||||
|
PlayCustomUserInfoEntity customer,
|
||||||
|
BlindBoxConfigEntity config,
|
||||||
|
BigDecimal boxPrice) {
|
||||||
|
|
||||||
|
return OrderCreationContext.builder()
|
||||||
|
.orderId(orderId)
|
||||||
|
.orderNo(playOrderInfoService.getOrderNo())
|
||||||
|
.orderStatus(OrderConstant.OrderStatus.COMPLETED)
|
||||||
|
.orderType(OrderConstant.OrderType.BLIND_BOX_PURCHASE)
|
||||||
|
.placeType(OrderConstant.PlaceType.REWARD)
|
||||||
|
.rewardType(RewardType.GIFT)
|
||||||
|
.isFirstOrder(false)
|
||||||
|
.creatorActor(OrderActor.CUSTOMER)
|
||||||
|
.creatorId(customer.getId())
|
||||||
|
.commodityInfo(CommodityInfo.builder()
|
||||||
|
.commodityId(config.getId())
|
||||||
|
.commodityType(OrderConstant.CommodityType.GIFT)
|
||||||
|
.commodityPrice(config.getPrice())
|
||||||
|
.commodityName(config.getName())
|
||||||
|
.commodityNumber("1")
|
||||||
|
.serviceDuration("")
|
||||||
|
.build())
|
||||||
|
.paymentInfo(PaymentInfo.builder()
|
||||||
|
.orderMoney(boxPrice)
|
||||||
|
.finalAmount(boxPrice)
|
||||||
|
.discountAmount(BigDecimal.ZERO)
|
||||||
|
.couponIds(Collections.emptyList())
|
||||||
|
.payMethod(OrderConstant.PayMethod.BALANCE.getCode())
|
||||||
|
.paymentSource(OrderConstant.PaymentSource.BALANCE)
|
||||||
|
.build())
|
||||||
|
.purchaserBy(customer.getId())
|
||||||
|
.acceptBy(request.getClerkId())
|
||||||
|
.weiChatCode(request.getWeiChatCode())
|
||||||
|
.remark(request.getRemark())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -87,7 +87,7 @@ class BlindBoxServiceTest {
|
|||||||
BlindBoxCandidate.of(1L, "tenant-1", "blind-1", "gift-low", BigDecimal.valueOf(10), 10, 5),
|
BlindBoxCandidate.of(1L, "tenant-1", "blind-1", "gift-low", BigDecimal.valueOf(10), 10, 5),
|
||||||
BlindBoxCandidate.of(2L, "tenant-1", "blind-1", "gift-high", BigDecimal.valueOf(99), 90, 3)
|
BlindBoxCandidate.of(2L, "tenant-1", "blind-1", "gift-high", BigDecimal.valueOf(99), 90, 3)
|
||||||
);
|
);
|
||||||
when(poolMapper.listActiveEntries(eq("tenant-1"), eq("blind-1"), any())).thenReturn(candidates);
|
when(poolMapper.listActiveEntries(eq("tenant-1"), eq("blind-1"), any(LocalDateTime.class))).thenReturn(candidates);
|
||||||
|
|
||||||
BlindBoxRewardEntity entity = blindBoxService.drawReward("tenant-1", "order-1", "customer-1", "blind-1",
|
BlindBoxRewardEntity entity = blindBoxService.drawReward("tenant-1", "order-1", "customer-1", "blind-1",
|
||||||
"seed-123");
|
"seed-123");
|
||||||
@@ -115,7 +115,7 @@ class BlindBoxServiceTest {
|
|||||||
List<BlindBoxCandidate> candidates = Collections.singletonList(
|
List<BlindBoxCandidate> candidates = Collections.singletonList(
|
||||||
BlindBoxCandidate.of(7L, "tenant-1", "blind-1", "gift-unlimited", BigDecimal.valueOf(59), 100, null)
|
BlindBoxCandidate.of(7L, "tenant-1", "blind-1", "gift-unlimited", BigDecimal.valueOf(59), 100, null)
|
||||||
);
|
);
|
||||||
when(poolMapper.listActiveEntries(eq("tenant-1"), eq("blind-1"), any())).thenReturn(candidates);
|
when(poolMapper.listActiveEntries(eq("tenant-1"), eq("blind-1"), any(LocalDateTime.class))).thenReturn(candidates);
|
||||||
|
|
||||||
blindBoxService.drawReward("tenant-1", "order-2", "customer-9", "blind-1", "seed-unlimited");
|
blindBoxService.drawReward("tenant-1", "order-2", "customer-9", "blind-1", "seed-unlimited");
|
||||||
|
|
||||||
@@ -137,11 +137,11 @@ class BlindBoxServiceTest {
|
|||||||
when(dispatchService.dispatchRewardOrder(eq(reward), eq("clerk-1"))).thenReturn(mock(OrderPlacementResult.class));
|
when(dispatchService.dispatchRewardOrder(eq(reward), eq("clerk-1"))).thenReturn(mock(OrderPlacementResult.class));
|
||||||
when(rewardMapper.markUsed(eq("reward-1"), eq("clerk-1"), any(), any())).thenReturn(1);
|
when(rewardMapper.markUsed(eq("reward-1"), eq("clerk-1"), any(), any())).thenReturn(1);
|
||||||
|
|
||||||
blindBoxService.dispatchReward("reward-1", "clerk-1");
|
blindBoxService.dispatchReward("reward-1", "clerk-1", "customer-1");
|
||||||
|
|
||||||
reward.setStatus(BlindBoxRewardStatus.USED.getCode());
|
reward.setStatus(BlindBoxRewardStatus.USED.getCode());
|
||||||
CustomException ex = assertThrows(CustomException.class, () ->
|
CustomException ex = assertThrows(CustomException.class, () ->
|
||||||
blindBoxService.dispatchReward("reward-1", "clerk-1"));
|
blindBoxService.dispatchReward("reward-1", "clerk-1", "customer-1"));
|
||||||
assertTrue(ex.getMessage().contains("已使用"));
|
assertTrue(ex.getMessage().contains("已使用"));
|
||||||
|
|
||||||
verify(rewardMapper, times(1)).markUsed(eq("reward-1"), eq("clerk-1"), any(), any());
|
verify(rewardMapper, times(1)).markUsed(eq("reward-1"), eq("clerk-1"), any(), any());
|
||||||
@@ -154,11 +154,23 @@ class BlindBoxServiceTest {
|
|||||||
when(rewardMapper.lockByIdForUpdate("reward-1")).thenReturn(reward);
|
when(rewardMapper.lockByIdForUpdate("reward-1")).thenReturn(reward);
|
||||||
|
|
||||||
CustomException ex = assertThrows(CustomException.class, () ->
|
CustomException ex = assertThrows(CustomException.class, () ->
|
||||||
blindBoxService.dispatchReward("reward-1", "clerk-1"));
|
blindBoxService.dispatchReward("reward-1", "clerk-1", "customer-1"));
|
||||||
assertTrue(ex.getMessage().contains("已过期"));
|
assertTrue(ex.getMessage().contains("已过期"));
|
||||||
verify(dispatchService, times(0)).dispatchRewardOrder(any(), any());
|
verify(dispatchService, times(0)).dispatchRewardOrder(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRejectDispatchWhenCustomerMismatch() {
|
||||||
|
BlindBoxRewardEntity reward = buildRewardEntity();
|
||||||
|
when(rewardMapper.lockByIdForUpdate("reward-1")).thenReturn(reward);
|
||||||
|
|
||||||
|
CustomException ex = assertThrows(CustomException.class, () ->
|
||||||
|
blindBoxService.dispatchReward("reward-1", "clerk-1", "someone-else"));
|
||||||
|
assertTrue(ex.getMessage().contains("无权"));
|
||||||
|
verify(dispatchService, times(0)).dispatchRewardOrder(any(), any());
|
||||||
|
verify(rewardMapper, times(0)).markUsed(any(), any(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
private BlindBoxRewardEntity buildRewardEntity() {
|
private BlindBoxRewardEntity buildRewardEntity() {
|
||||||
BlindBoxRewardEntity reward = new BlindBoxRewardEntity();
|
BlindBoxRewardEntity reward = new BlindBoxRewardEntity();
|
||||||
reward.setId("reward-1");
|
reward.setId("reward-1");
|
||||||
@@ -175,7 +187,6 @@ class BlindBoxServiceTest {
|
|||||||
reward.setCreatedTime(java.sql.Timestamp.from(clock.instant()));
|
reward.setCreatedTime(java.sql.Timestamp.from(clock.instant()));
|
||||||
reward.setUpdatedTime(java.sql.Timestamp.from(clock.instant()));
|
reward.setUpdatedTime(java.sql.Timestamp.from(clock.instant()));
|
||||||
reward.setExpiresAt(LocalDateTime.ofInstant(clock.instant(), clock.getZone()).plusHours(1));
|
reward.setExpiresAt(LocalDateTime.ofInstant(clock.instant(), clock.getZone()).plusHours(1));
|
||||||
reward.setVersion(0);
|
|
||||||
return reward;
|
return reward;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user