103 lines
4.1 KiB
Markdown
103 lines
4.1 KiB
Markdown
# 优惠券功能规划(先规划,后执行)
|
||
|
||
## 1. 目标与范围
|
||
|
||
- 支持租户侧创建/管理优惠券模板。
|
||
- 支持用户领取/选择/使用优惠券,订单创建时自动校验与核销。
|
||
- 优惠券状态可追踪:未使用/已使用/已过期。
|
||
- 保持多租户隔离,避免跨租户误用。
|
||
|
||
## 2. 当前现状
|
||
|
||
- 数据表已存在:`coupons`、`user_coupons`、`orders.coupon_id`。
|
||
- 服务层已有部分能力:`Coupon.ListUserCoupons`、`Coupon.Validate`、`Coupon.MarkUsed`。
|
||
- 用户侧 API 已有:`GET /t/:tenantCode/v1/me/coupons`。
|
||
- 前端已有「我的优惠券」页面,但暂无领取/选择流程。
|
||
|
||
## 3. 领域规则(V1)
|
||
|
||
- `total_quantity = 0` 表示不限量;>0 表示最多可领取次数。
|
||
- 每个用户对同一优惠券默认只允许领取一次(可通过规则调整)。
|
||
- 过期判断以 `end_at` 为准:`end_at < now` 则视为过期。
|
||
- 使用时:订单金额需满足 `min_order_amount`;折扣券需遵守 `max_discount`。
|
||
|
||
## 4. 枚举与类型规范(必做)
|
||
|
||
- 新增枚举类型并统一使用(避免硬编码字符串):
|
||
- `consts.CouponType`:`fix_amount` / `discount`
|
||
- `consts.UserCouponStatus`:`unused` / `used` / `expired`
|
||
- `backend/database/.transform.yaml` 映射:
|
||
- `coupons.type -> consts.CouponType`
|
||
- `user_coupons.status -> consts.UserCouponStatus`
|
||
- 运行 `atomctl gen enum` + `atomctl gen model`,保持生成文件一致性。
|
||
|
||
## 5. 接口规划(按模块)
|
||
|
||
### 5.1 用户侧(UserCenter)
|
||
|
||
- `GET /t/:tenantCode/v1/me/coupons?status=unused|used|expired`
|
||
- 已有,补齐过期自动标记逻辑。
|
||
- `GET /t/:tenantCode/v1/me/coupons/available?amount=<int64>`
|
||
- 返回「当前订单金额可用」的优惠券列表(用于结算页选择)。
|
||
- `POST /t/:tenantCode/v1/me/coupons/receive`
|
||
- 领取优惠券(参数:`coupon_id`)。
|
||
|
||
### 5.2 租户侧(CreatorCenter)
|
||
|
||
- `POST /t/:tenantCode/v1/creator/coupons`
|
||
- 创建优惠券模板。
|
||
- `GET /t/:tenantCode/v1/creator/coupons`
|
||
- 分页查询模板列表(支持状态、有效期、类型过滤)。
|
||
- `GET /t/:tenantCode/v1/creator/coupons/:id<int>`
|
||
- 查看模板详情。
|
||
- `PUT /t/:tenantCode/v1/creator/coupons/:id<int>`
|
||
- 更新模板(仅未开始或未领取时允许修改核心字段)。
|
||
- `POST /t/:tenantCode/v1/creator/coupons/:id<int>/grant`
|
||
- 定向发放给用户(参数:`user_ids` 批量)。
|
||
|
||
## 6. 服务层设计(关键逻辑)
|
||
|
||
- `Coupon.Create/Update/List/Get`:模板管理。
|
||
- `Coupon.Receive`:
|
||
- 校验有效期与库存(`total_quantity`)。
|
||
- 校验用户是否已领取。
|
||
- 事务内写入 `user_coupons`。
|
||
- `Coupon.ListUserCoupons`:
|
||
- join `coupons` 读取模板信息。
|
||
- 对过期券自动标记 `expired`(可更新 DB)。
|
||
- `Coupon.ListAvailable`:
|
||
- `status = unused`
|
||
- `start_at <= now <= end_at`
|
||
- `min_order_amount <= amount`
|
||
- `Coupon.Validate` / `MarkUsed`:
|
||
- 已有,改用枚举类型 + 统一错误码语义。
|
||
|
||
## 7. 并发与一致性
|
||
|
||
- 领取优惠券时在事务中锁定 `coupons` 行或使用条件更新,防止超发:
|
||
- `total_quantity > 0` 时,基于 `COUNT(user_coupons)` 判断库存。
|
||
- 若性能成为瓶颈,再考虑新增 `claimed_quantity` 字段(V2 优化)。
|
||
|
||
## 8. 前端联动
|
||
|
||
- 结算页新增「选择优惠券」抽屉(参考 `docs/design/portal/PAGE_ORDER.md`)。
|
||
- 用户中心「优惠券」页保持与后端状态一致(unused/used/expired)。
|
||
- 订单创建前调用 `available` 接口,展示可用券。
|
||
|
||
## 9. 测试规划
|
||
|
||
- Service 单测:
|
||
- 领取成功/重复领取/超库存/过期不可领取。
|
||
- Validate:金额不足、折扣封顶、跨租户禁止。
|
||
- MarkUsed:幂等/重复使用失败。
|
||
- Order 相关:
|
||
- 使用优惠券创建订单成功并核销。
|
||
|
||
## 10. 实施顺序(建议)
|
||
|
||
1) 枚举 + transform + gen(保证类型安全)。
|
||
2) Service:Receive/ListAvailable/ListUserCoupons 过期处理。
|
||
3) HTTP:用户端 + CreatorCenter 管理端接口。
|
||
4) 前端:结算页优惠券选择 + 领券入口。
|
||
5) 补测试 + 回归订单流程。
|