执行时间: 2026-10-24
执行智能体: 任务6专用
核验状态: 待独立核验
2026-10-23-basic-membership-spec-revision.md)| # | 权益 | 口径 | 对应实现 |
|---|---|---|---|
| 4 | 指定商品会员价 | 享受(原无) | discount_purchase 生效:products.member_price + min_discount_level(NULL 时默认 BASIC) |
ProductOrderService.getEligibleMemberPrice:min_discount_level 为 NULL 时默认按 BASIC 判定(修复 FREE 也可享的漏洞);等级比较用 getLevelOrderActivityDTO.resolveMemberPrice:会员等级集合纳入 BASIC(FAMILY/PREMIUM 保持不变;PROVIDER 仍不享)mvn clean compile 通过min_discount_level=FAMILY 的商品 BASIC 得原价代码位置: ProductOrderService.java 第 2166-2188 行
当前实现:
private Integer getEligibleMemberPrice(Product product, Long buyerId) {
if (product == null || product.getMemberPrice() == null || product.getMemberPrice() <= 0) {
return product != null ? product.getPrice() : 0;
}
// 用户会员等级(FREE 兜底)
String userLevel = "FREE";
if (buyerId != null) {
User user = userMapper.selectById(buyerId);
if (user != null) {
userLevel = membershipService.getMemberLevel(buyerId);
}
}
// 产品未设置最低级别时默认 BASIC
String minLevel = (product.getMinDiscountLevel() == null || product.getMinDiscountLevel().isEmpty())
? "BASIC" : product.getMinDiscountLevel();
// 比较级别数字:级别数字越小越低
int userLevelOrder = membershipService.getLevelOrder(userLevel);
int minLevelOrder = membershipService.getLevelOrder(minLevel);
// 用户级别 >= 最低要求级别,则可享会员价
if (userLevelOrder >= minLevelOrder) {
return product.getMemberPrice();
}
return product.getPrice();
}
逻辑分析:
| 场景 | min_discount_level | userLevel | userLevelOrder | minLevelOrder | 结果 |
|---|---|---|---|---|---|
| FREE 买 min_level=NULL 商品 | NULL → "BASIC" | "FREE" | 1 | 2 | ❌ FREE < BASIC → 原价 ✓ |
| BASIC 买 min_level=NULL 商品 | NULL → "BASIC" | "BASIC" | 2 | 2 | ✅ BASIC >= BASIC → 会员价 ✓ |
| FAMILY 买 min_level=NULL 商品 | NULL → "BASIC" | "FAMILY" | 3 | 2 | ✅ FAMILY >= BASIC → 会员价 ✓ |
| BASIC 买 min_level=FAMILY 商品 | "FAMILY" | "BASIC" | 2 | 3 | ❌ BASIC < FAMILY → 原价 ✓ |
| FAMILY 买 min_level=FAMILY 商品 | "FAMILY" | "FAMILY" | 3 | 3 | ✅ FAMILY >= FAMILY → 会员价 ✓ |
结论:✅ PASS
getLevelOrder 进行等级比较 ✓代码位置: ActivityDTO.java 第 137-146 行
当前实现:
public static Integer resolveMemberPrice(Integer basePrice, Integer memberPrice, String memberLevel) {
if (basePrice == null) return null;
// If user has member level and a memberPrice is set, use memberPrice
if (memberLevel != null && ("BASIC".equals(memberLevel) || "FAMILY".equals(memberLevel) || "PREMIUM".equals(memberLevel))) {
if (memberPrice != null) {
return memberPrice;
}
}
return basePrice;
}
逻辑分析:
| memberLevel | 是否享会员价 | 说明 |
|---|---|---|
| null / "" | ❌ | 非会员 |
| "FREE" | ❌ | 免费用户不享受 |
| "BASIC" | ✅ | 9.9元体验会员纳入 ✓ |
| "FAMILY" | ✅ | 保持不变 ✓ |
| "PREMIUM" | ✅ | 保持不变 ✓ |
| "PROVIDER" | ❌ | 服务商不享受 ✓ |
结论:✅ PASS
调用点1: ProductOrderService.java:263(单商品下单)
order.setUnitPrice(getEligibleMemberPrice(product, buyerId));
调用点2: ProductOrderService.java:762(多商品下单/购物车)
int unitPrice = getEligibleMemberPrice(product, buyerId);
结论:✅ PASS
两个调用点均调用同一方法 getEligibleMemberPrice,逻辑完全一致。
特价订单流程(createSpecialDealOrder):
// 第422-423行
order.setUnitPrice(deal.getSpecialPrice());
order.setTotalAmount(deal.getSpecialPrice() * quantity);
特价订单直接使用 deal.getSpecialPrice() 作为单价,完全不调用 getEligibleMemberPrice。
结论:✅ PASS
特价覆盖会员价的原有逻辑保持不变。
var、List.of() 等新特性mvn clean compile -q 退出码为 0,编译通过结论:✅ PASS
原草稿实现:
String minLevel = product.getMinDiscountLevel() != null ? product.getMinDiscountLevel() : "BASIC";
问题: 未处理 min_discount_level 为空字符串("")的情况。虽然数据库字段为 VARCHAR(50) 且默认值为 NULL,但为保险起见应同时处理空字符串。
修复后的代码:
String minLevel = (product.getMinDiscountLevel() == null || product.getMinDiscountLevel().isEmpty())
? "BASIC" : product.getMinDiscountLevel();
影响: 增强了代码的健壮性,防止未来数据异常时出现 NPE 或逻辑错误。
EXIT_CODE=0
编译成功,无任何 error 或 warning。
cfc-backend/src/main/java/com/etotem/cfc/dto/ActivityDTO.java | 5 +++--
cfc-backend/src/main/java/com/etotem/cfc/service/ProductOrderService.java | 16 ++++++++--------
2 files changed, 11 insertions(+), 10 deletions(-)
| 验收项 | 结论 |
|---|---|
| 1. getEligibleMemberPrice 逻辑正确性 | ✅ PASS |
| 2. ActivityDTO.resolveMemberPrice 纳入 BASIC | ✅ PASS |
| 3. 单商品/多商品调用点一致 | ✅ PASS |
| 4. 特价活动流程不受影响 | ✅ PASS |
| 5. Java 8 兼容 + 编译通过 | ✅ PASS |
任务状态: ✅ 已完成,等待独立核验智能体验收