一、功能概述
美团买菜系统的优惠券通用功能需要支持多种类型的优惠券(满减、折扣、无门槛等)在买菜业务场景下的灵活使用,包括商品级、品类级、全平台级的优惠券发放、领取、使用和结算。
二、系统架构设计
1. 核心模块划分
- 优惠券模板管理模块:定义优惠券规则和属性
- 优惠券发放模块:处理优惠券的发放逻辑
- 优惠券领取中心:用户领取优惠券的入口
- 优惠券使用模块:校验和使用优惠券
- 结算系统集成:与订单结算系统对接
- 数据分析模块:优惠券使用效果分析
2. 数据库设计
```sql
-- 优惠券模板表
CREATE TABLE coupon_template (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
type TINYINT NOT NULL COMMENT 1-满减 2-折扣 3-无门槛,
discount_type TINYINT COMMENT 1-金额 2-比例,
discount_value DECIMAL(10,2) NOT NULL,
min_order_amount DECIMAL(10,2) DEFAULT 0,
valid_days INT COMMENT 有效期天数,
valid_start_time DATETIME,
valid_end_time DATETIME,
适用范围 TINYINT COMMENT 1-全平台 2-指定品类 3-指定商品,
适用品类ID VARCHAR(1000) COMMENT JSON格式,
适用商品ID VARCHAR(1000) COMMENT JSON格式,
发放总量 INT DEFAULT 0,
每人限领 INT DEFAULT 1,
status TINYINT DEFAULT 1 COMMENT 1-有效 0-无效,
create_time DATETIME,
update_time DATETIME
);
-- 用户优惠券表
CREATE TABLE user_coupon (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
coupon_template_id BIGINT NOT NULL,
status TINYINT DEFAULT 0 COMMENT 0-未使用 1-已使用 2-已过期,
order_id BIGINT DEFAULT NULL,
get_time DATETIME,
use_time DATETIME,
expire_time DATETIME,
FOREIGN KEY (coupon_template_id) REFERENCES coupon_template(id)
);
```
三、核心功能实现
1. 优惠券模板创建
```java
public class CouponTemplate {
private Long id;
private String name;
private Integer type; // 1-满减 2-折扣 3-无门槛
private BigDecimal discountValue;
private Integer minOrderAmount; // 满减门槛
private Date validStartTime;
private Date validEndTime;
private Integer validDays; // 领取后N天内有效
private String applicableScope; // 适用范围JSON
// getters and setters
}
// 创建优惠券模板服务
public CouponTemplate createCouponTemplate(CouponTemplateDTO dto) {
// 参数校验
validateTemplate(dto);
// 转换为实体
CouponTemplate template = convertToEntity(dto);
// 保存到数据库
couponTemplateRepository.save(template);
return template;
}
```
2. 优惠券发放逻辑
```java
public interface CouponDistributionStrategy {
void distribute(List userIds, Long templateId);
}
// 全量发放策略
public class BatchDistributionStrategy implements CouponDistributionStrategy {
@Override
public void distribute(List userIds, Long templateId) {
CouponTemplate template = couponTemplateRepository.findById(templateId)
.orElseThrow(() -> new RuntimeException("优惠券模板不存在"));
for (Long userId : userIds) {
// 检查用户是否已领取过
if (userCouponRepository.countByUserIdAndTemplateId(userId, templateId) >=
template.getPerUserLimit()) {
continue;
}
// 创建用户优惠券
UserCoupon userCoupon = new UserCoupon();
userCoupon.setUserId(userId);
userCoupon.setTemplateId(templateId);
userCoupon.setStatus(CouponStatus.UNUSED);
userCoupon.setExpireTime(calculateExpireTime(template));
userCouponRepository.save(userCoupon);
}
}
}
```
3. 优惠券使用校验
```java
public class CouponValidator {
public boolean validate(UserCoupon userCoupon, Order order) {
// 1. 检查优惠券状态
if (userCoupon.getStatus() != CouponStatus.UNUSED) {
return false;
}
// 2. 检查有效期
if (userCoupon.getExpireTime().before(new Date())) {
return false;
}
// 3. 检查订单金额是否满足最低要求
CouponTemplate template = getCouponTemplate(userCoupon.getTemplateId());
if (template.getMinOrderAmount() > 0 &&
order.getTotalAmount().compareTo(template.getMinOrderAmount()) < 0) {
return false;
}
// 4. 检查商品/品类限制
if (!checkProductRestrictions(template, order.getItems())) {
return false;
}
return true;
}
private boolean checkProductRestrictions(CouponTemplate template, List items) {
// 实现商品/品类限制检查逻辑
// ...
}
}
```
4. 结算系统集成
```java
public class OrderCalculator {
public Order calculateWithCoupon(Order order, Long couponId) {
UserCoupon userCoupon = userCouponRepository.findById(couponId)
.orElseThrow(() -> new RuntimeException("优惠券不存在"));
if (!couponValidator.validate(userCoupon, order)) {
throw new RuntimeException("优惠券不可用");
}
// 应用优惠券
applyCouponDiscount(userCoupon, order);
// 更新优惠券状态
userCoupon.setStatus(CouponStatus.USED);
userCoupon.setUsedTime(new Date());
userCouponRepository.save(userCoupon);
return order;
}
private void applyCouponDiscount(UserCoupon userCoupon, Order order) {
CouponTemplate template = couponTemplateRepository.findById(userCoupon.getTemplateId())
.orElseThrow(() -> new RuntimeException("优惠券模板不存在"));
switch (template.getType()) {
case FIXED_DISCOUNT:
order.setDiscountAmount(template.getDiscountValue());
order.setPayableAmount(order.getSubtotal() - template.getDiscountValue());
break;
case PERCENTAGE_DISCOUNT:
double discount = order.getSubtotal() * template.getDiscountPercentage() / 100;
order.setDiscountAmount(discount);
order.setPayableAmount(order.getSubtotal() - discount);
break;
// 其他优惠类型处理...
}
}
}
```
四、关键业务逻辑实现
1. 优惠券适用范围校验
```java
public class CouponScopeChecker {
public boolean isApplicable(CouponTemplate template, List items) {
// 检查全平台通用
if (template.getScopeType() == ScopeType.PLATFORM_WIDE) {
return true;
}
// 检查品类限制
if (template.getScopeType() == ScopeType.CATEGORY_BASED) {
for (CartItem item : items) {
if (!template.getCategoryIds().contains(item.getCategoryId())) {
return false;
}
}
return true;
}
// 检查商品限制
if (template.getScopeType() == ScopeType.PRODUCT_BASED) {
for (CartItem item : items) {
if (!template.getProductIds().contains(item.getProductId())) {
return false;
}
}
return true;
}
return false;
}
}
```
2. 优惠券堆叠使用规则
```java
public class CouponStackingRule {
public List filterApplicableCoupons(List coupons, Cart cart) {
// 1. 按优先级排序:无门槛 > 满减 > 折扣
coupons.sort((c1, c2) -> {
int priority1 = getCouponPriority(c1);
int priority2 = getCouponPriority(c2);
return Integer.compare(priority2, priority1);
});
// 2. 应用互斥规则
List applicableCoupons = new ArrayList<>();
for (UserCoupon coupon : coupons) {
if (canApplyWithOthers(applicableCoupons, coupon)) {
applicableCoupons.add(coupon);
}
}
return applicableCoupons;
}
private int getCouponPriority(UserCoupon coupon) {
// 无门槛优先
if (coupon.getType() == CouponType.NO_THRESHOLD) {
return 1;
}
// 满减次之
if (coupon.getType() == CouponType.FULL_REDUCTION) {
return 2;
}
// 折扣最后
return 3;
}
private boolean canApplyWithOthers(List current, UserCoupon newCoupon) {
// 实现优惠券互斥逻辑
// 例如:无门槛券不能与其他券叠加
if (newCoupon.getType() == CouponType.NO_THRESHOLD && !current.isEmpty()) {
return false;
}
// 其他叠加规则...
return true;
}
}
```
五、API接口设计
1. 优惠券领取接口
```
POST /api/coupons/claim
请求参数:
{
"couponId": "string", // 优惠券模板ID
"userId": "string" // 用户ID
}
响应:
{
"success": boolean,
"message": "string",
"couponId": "string" // 实际发放的优惠券ID
}
```
2. 优惠券使用接口
```
POST /api/orders/apply-coupon
请求参数:
{
"orderId": "string",
"couponId": "string"
}
响应:
{
"success": boolean,
"message": "string",
"discountApplied": number,
"finalAmount": number
}
```
3. 可用优惠券列表接口
```
GET /api/coupons/available
查询参数:
{
"userId": "string",
"cartId": "string" // 可选,用于商品级校验
}
响应:
[
{
"id": "string",
"name": "string",
"type": "string",
"discount": number,
"expiryDate": "string"
}
]
```
六、安全与风控考虑
1. 防刷机制:
- 用户领取频率限制
- IP地址限制
- 设备指纹识别
2. 优惠券防伪:
- 唯一券码生成
- 加密传输
- 使用状态实时更新
3. 并发控制:
- 乐观锁控制优惠券使用
- 分布式锁防止超发
六、测试用例设计
1. 单元测试
- 优惠券模板创建测试
- 优惠券领取逻辑测试
- 优惠券使用条件校验测试
- 结算金额计算测试
2. 集成测试
- 优惠券领取到使用的全流程测试
- 多优惠券叠加使用测试
- 品类/商品级优惠券适用性测试
3. 性能测试
- 高并发优惠券领取测试
- 结算系统优惠券使用压力测试
- 优惠券过期批量处理测试
七、部署与监控
1. 部署方案:
- 灰度发布策略
- 数据库分库分表设计
- 缓存策略(Redis存储可用优惠券)
2. 监控指标:
- 优惠券领取成功率
- 优惠券使用率
- 结算系统优惠券处理延迟
- 错误率监控
3. 告警机制:
- 优惠券库存不足告警
- 系统异常使用检测
- 结算金额异常波动检测
八、扩展功能考虑
1. 社交分享优惠券:用户分享获得额外优惠
2. 地理位置限定优惠券:基于LBS的定向发放
3. 时间限定优惠券:特定时间段有效
4. 优惠券组合包:多种优惠券打包销售
5. AI推荐优惠券:基于用户购买历史的个性化推荐
九、安全考虑
1. 防刷机制:
- 限制单个用户领取数量
- 验证码校验
- 行为分析防机器人
2. 数据加密:
- 敏感数据传输加密
- 存储加密
3. 审计日志:
- 完整记录优惠券操作
- 防止篡改和伪造
十、实施路线图
1. 第一阶段:
- 基础优惠券模板管理
- 简单满减券实现
- 用户领取功能
2. 第二阶段:
- 复杂优惠券规则支持
- 品类/商品级优惠券
- 优惠券叠加使用
3. 第三阶段:
- 智能优惠券推荐
- 动态优惠券定价
- 大数据分析优化
此方案提供了美团买菜系统优惠券通用功能的全面实现路径,涵盖了从基础功能到高级特性的完整开发流程,可根据实际业务需求分阶段实施。