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:
irving
2025-10-31 02:48:03 -04:00
parent 422e781c60
commit e7ccadaea0
17 changed files with 480 additions and 30 deletions

View File

@@ -87,7 +87,7 @@ class BlindBoxServiceTest {
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)
);
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",
"seed-123");
@@ -115,7 +115,7 @@ class BlindBoxServiceTest {
List<BlindBoxCandidate> candidates = Collections.singletonList(
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");
@@ -137,11 +137,11 @@ class BlindBoxServiceTest {
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);
blindBoxService.dispatchReward("reward-1", "clerk-1");
blindBoxService.dispatchReward("reward-1", "clerk-1", "customer-1");
reward.setStatus(BlindBoxRewardStatus.USED.getCode());
CustomException ex = assertThrows(CustomException.class, () ->
blindBoxService.dispatchReward("reward-1", "clerk-1"));
blindBoxService.dispatchReward("reward-1", "clerk-1", "customer-1"));
assertTrue(ex.getMessage().contains("已使用"));
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);
CustomException ex = assertThrows(CustomException.class, () ->
blindBoxService.dispatchReward("reward-1", "clerk-1"));
blindBoxService.dispatchReward("reward-1", "clerk-1", "customer-1"));
assertTrue(ex.getMessage().contains("已过期"));
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() {
BlindBoxRewardEntity reward = new BlindBoxRewardEntity();
reward.setId("reward-1");
@@ -175,7 +187,6 @@ class BlindBoxServiceTest {
reward.setCreatedTime(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.setVersion(0);
return reward;
}