合并代码

This commit is contained in:
huchuansai
2025-10-09 09:39:56 +08:00
9 changed files with 191 additions and 24 deletions

View File

@@ -144,6 +144,10 @@ public class PlayCouponInfoController {
}
entity.setDiscountContent(discountContent);
entity.setCouponOnLineState("1");
// 领取白名单校验当为2时必须配置白名单
if ("2".equals(vo.getClaimConditionType()) && (vo.getCustomWhitelist() == null || vo.getCustomWhitelist().isEmpty())) {
throw new CustomException("领取条件为白名单时,必须设置领取白名单");
}
boolean success = playCouponInfoService.create(entity);
if (success) {
return R.ok();

View File

@@ -118,10 +118,16 @@ public class PlayCouponInfoEntity extends BaseEntity<PlayCouponInfoEntity> {
private Integer clerkObtainedMaxQuantity;
/**
* 领取条件类型0:所有人可领取,1:指定条件领取)
* 领取条件类型0=所有人可领取1=按条件领取2=仅白名单可领取。
*/
private String claimConditionType;
/**
* 领取白名单claimConditionType=2 生效。JSON存储用户ID列表。
*/
@TableField(typeHandler = StringTypeHandler.class)
private List<String> customWhitelist;
/**
* 顾客等级选择状态(0:未选择,1:选择)
*/

View File

@@ -0,0 +1,25 @@
package com.starry.admin.modules.shop.module.enums;
/**
* 优惠券领取条件类型
*/
public enum CouponClaimConditionType {
ALL("0"),
FILTER("1"),
WHITELIST("2");
private final String code;
CouponClaimConditionType(String code) {
this.code = code;
}
public String code() { return code; }
public static CouponClaimConditionType of(String code) {
for (CouponClaimConditionType t : values()) {
if (t.code.equals(code)) return t;
}
return ALL;
}
}

View File

@@ -120,12 +120,17 @@ public class PlayCouponInfoAddVo {
private Integer clerkObtainedMaxQuantity;
/**
* 领取条件类型0:所有人可领取,1:指定条件领取)
* 领取条件类型0=所有人1=按条件2=白名单。
*/
@NotNull(message = "领取条件类型不能为空")
@Pattern(regexp = "[0|1]", message = "店员范围只能为0或1")
@Pattern(regexp = "^(0|1|2)$", message = "领取条件类型只能为0或1或2")
private String claimConditionType;
/**
* 领取白名单claimConditionType=2 时校验用户ID列表
*/
private List<String> customWhitelist;
/**
* 顾客等级选择状态(0:未选择,1:选择)
*/

View File

@@ -109,10 +109,16 @@ public class PlayCouponInfoReturnVo {
private Integer clerkObtainedMaxQuantity;
/**
* 领取条件类型0:所有人可领取,1:指定条件领取)
* 领取条件类型0=所有人1=按条件2=白名单。
*/
private String claimConditionType;
/**
* 领取白名单claimConditionType=2 生效)
*/
@TableField(typeHandler = StringTypeHandler.class)
private List<String> customWhitelist;
/**
* 顾客等级选择状态(0:未选择,1:选择)
*/

View File

@@ -10,6 +10,7 @@ import com.starry.admin.common.exception.CustomException;
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
import com.starry.admin.modules.shop.mapper.PlayCouponInfoMapper;
import com.starry.admin.modules.shop.module.entity.PlayCouponInfoEntity;
import com.starry.admin.modules.shop.module.enums.CouponClaimConditionType;
import com.starry.admin.modules.shop.module.vo.PlayCouponInfoQueryVo;
import com.starry.admin.modules.shop.module.vo.PlayCouponInfoReturnVo;
import com.starry.admin.modules.shop.service.IPlayCouponInfoService;
@@ -84,10 +85,17 @@ public class PlayCouponInfoServiceImpl extends ServiceImpl<PlayCouponInfoMapper,
@Override
public String getReasonForNotObtainingCoupons(PlayCouponInfoEntity entity,
PlayCustomUserInfoEntity customUserInfo) {
// 优惠券是否设置指定条件领取
if ("0".equals(entity.getClaimConditionType())) {
CouponClaimConditionType type = CouponClaimConditionType.of(entity.getClaimConditionType());
switch (type) {
case ALL:
return "";
case WHITELIST:
if (entity.getCustomWhitelist() == null || entity.getCustomWhitelist().isEmpty()) {
return "未配置白名单";
}
return entity.getCustomWhitelist().contains(customUserInfo.getId()) ? "" : "非指定用户";
case FILTER:
default:
// 顾客等级判断
String msg = reasonForNotObtainingCoupons(entity.getCustomLevelCheckType(), entity.getCustomLevel(),
customUserInfo.getLevelId(), "0");
@@ -96,15 +104,14 @@ public class PlayCouponInfoServiceImpl extends ServiceImpl<PlayCouponInfoMapper,
}
// 顾客性别判断
msg = reasonForNotObtainingCoupons(entity.getCustomSexCheckType(), entity.getCustomSex(),
customUserInfo.getSex().toString(), "`1");
String.valueOf(customUserInfo.getSex()), "1");
if (StrUtil.isNotEmpty(msg)) {
return msg;
}
// 顾客关注公众号状态判断
// 顾客是否是新用户判断
// TODO: 关注状态、新用户等其他条件可在此扩展
return "";
}
}
/**
* 获取优惠券不可领取的原因

View File

@@ -9,6 +9,7 @@ import com.starry.admin.modules.clerk.module.entity.PlayClerkUserInfoEntity;
import com.starry.admin.modules.clerk.service.IPlayClerkUserInfoService;
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
import com.starry.admin.modules.shop.module.entity.PlayCouponInfoEntity;
import com.starry.admin.modules.shop.module.enums.CouponClaimConditionType;
import com.starry.admin.modules.shop.module.vo.PlayCommodityInfoVo;
import com.starry.admin.modules.shop.module.vo.PlayCouponDetailsReturnVo;
import com.starry.admin.modules.shop.service.IPlayCommodityInfoService;
@@ -94,14 +95,22 @@ public class WxCouponController {
@CustomUserLogin
@PostMapping("/custom/queryAll")
public R queryAll() {
String currentCustomId = ThreadLocalRequestDetail.getCustomUserInfo().getId();
List<PlayCouponDetailsReturnVo> obtainedCoupons = couponDetailsService
.selectByCustomId(ThreadLocalRequestDetail.getCustomUserInfo().getId());
.selectByCustomId(currentCustomId);
List<PlayCouponInfoEntity> couponInfoEntities = couponInfoService.queryAll();
List<WxCouponReceiveReturnVo> returnVos = new ArrayList<>(couponInfoEntities.size());
for (PlayCouponInfoEntity couponInfoEntity : couponInfoEntities) {
if ("0".equals(couponInfoEntity.getCouponOnLineState())) {
continue;
}
// 领取白名单:非白名单用户不可见
if (CouponClaimConditionType.WHITELIST.code().equals(couponInfoEntity.getClaimConditionType())) {
List<String> wl = couponInfoEntity.getCustomWhitelist();
if (wl == null || !wl.contains(currentCustomId)) {
continue;
}
}
WxCouponReceiveReturnVo vo = ConvertUtil.entityToVo(couponInfoEntity, WxCouponReceiveReturnVo.class);
for (PlayCouponDetailsReturnVo obtainedCoupon : obtainedCoupons) {
if (obtainedCoupon.getCouponId().equals(couponInfoEntity.getId())) {

View File

@@ -0,0 +1,5 @@
-- Add whitelist for coupon self-claim restriction (specific users only)
-- MySQL dialect
ALTER TABLE `play_coupon_info`
ADD COLUMN `custom_whitelist` TEXT NULL COMMENT '领取白名单用户ID(JSON)';

View File

@@ -0,0 +1,100 @@
package com.starry.admin.modules.shop.service;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import com.starry.admin.common.conf.ThreadLocalRequestDetail;
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
import com.starry.admin.modules.shop.module.entity.PlayCouponInfoEntity;
import com.starry.admin.modules.shop.service.IPlayCommodityInfoService;
import com.starry.admin.modules.shop.service.IPlayCouponDetailsService;
import com.starry.admin.modules.shop.service.IPlayCouponInfoService;
import com.starry.admin.modules.shop.service.impl.PlayCouponInfoServiceImpl;
import com.starry.admin.modules.weichat.controller.WxCouponController;
import com.starry.admin.modules.weichat.entity.WxCouponReceiveReturnVo;
import com.starry.common.result.R;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class CouponWhitelistTest {
@Test
@DisplayName("领取校验-白名单:白名单用户可领,非白名单被拒")
void testWhitelistCheckInService() {
PlayCouponInfoServiceImpl service = new PlayCouponInfoServiceImpl();
PlayCouponInfoEntity coupon = new PlayCouponInfoEntity();
coupon.setClaimConditionType("2");
coupon.setCustomWhitelist(Arrays.asList("userA", "userB"));
PlayCustomUserInfoEntity userA = new PlayCustomUserInfoEntity();
userA.setId("userA");
PlayCustomUserInfoEntity userX = new PlayCustomUserInfoEntity();
userX.setId("userX");
String ok = service.getReasonForNotObtainingCoupons(coupon, userA);
String deny = service.getReasonForNotObtainingCoupons(coupon, userX);
assertEquals("", ok, "白名单用户应允许领取");
assertEquals("非指定用户", deny, "非白名单用户应被拒绝");
}
@Mock
private IPlayCouponDetailsService couponDetailsService;
@Mock
private IPlayCouponInfoService couponInfoService;
@Mock
private IPlayCommodityInfoService commodityInfoService;
@InjectMocks
private WxCouponController wxCouponController;
@AfterEach
void clearTL() { ThreadLocalRequestDetail.remove(); }
@Test
@DisplayName("列表过滤-白名单:非白名单用户不可见")
void testWhitelistHiddenInQueryAll() {
// 当前用户
PlayCustomUserInfoEntity current = new PlayCustomUserInfoEntity();
current.setId("uid-1");
ThreadLocalRequestDetail.setRequestDetail(current);
// 构造两张券一张白名单包含uid-1一张不包含
PlayCouponInfoEntity visible = new PlayCouponInfoEntity();
visible.setId("c1");
visible.setCouponOnLineState("1");
visible.setClaimConditionType("2");
visible.setCustomWhitelist(Collections.singletonList("uid-1"));
PlayCouponInfoEntity hidden = new PlayCouponInfoEntity();
hidden.setId("c2");
hidden.setCouponOnLineState("1");
hidden.setClaimConditionType("2");
hidden.setCustomWhitelist(Collections.singletonList("other"));
when(couponDetailsService.selectByCustomId("uid-1")).thenReturn(new ArrayList<>());
when(couponInfoService.queryAll()).thenReturn(Arrays.asList(visible, hidden));
R resp = wxCouponController.queryAll();
@SuppressWarnings("unchecked")
List<WxCouponReceiveReturnVo> list = (List<WxCouponReceiveReturnVo>) resp.getData();
assertNotNull(list);
assertEquals(1, list.size(), "非白名单券应被过滤不可见");
assertEquals("c1", list.get(0).getId());
}
}