## 目标与原则 - 禁用“积分直接购买/抵扣”用于抽奖订单;保留积分兑换优惠券/商品能力。 - 优惠券支持“部分使用”,且订单累计抵扣≤总价的50%。 - 不新增任何新表:仅在`user_coupons`增加一列`balance_amount`,订单侧复用`orders.remark`记录使用明细。 ## 数据变更(最小) - `user_coupons`新增:`balance_amount`(分,默认NULL/0)。 - 直减金额券:发券时初始化为模板面值;使用时扣减;余额为0时`status=2/used_at`。 - 满减/折扣券:不产生余额(保持一次性)。 - 不新增`order_coupons`表;订单使用明细写入`orders.remark`(结构化片段)。 ## 使用明细编码(remark复用) - 约定片段:`|c::`,可重复出现多段代表多券。 - 示例:票价50,封顶25,使用面值100券→`|c:12345:2500`(单位分),用户券余额从10000降至7500。 - 退款:解析`orders.remark`,逐段恢复对应`user_coupons.balance_amount += applied_amount`;余额>0则`status=1/clear used_at`。 ## 后端改动点 - 抽奖下单(internal/api/activity/lottery_app.go:110–176) - 移除积分抵扣分支;`order.PointsAmount`保持0(新订单)。 - 计算`total`与`cap = total * rate(默认0.5)`;`remaining_cap = cap - order.DiscountAmount`。 - 直减金额券:`applied = min(user_coupons.balance_amount, remaining_cap)`;更新`order.DiscountAmount/ActualAmount`,扣减余额并按规则更新`status/used_at`;在`orders.remark`追加`|c::`。 - 满减/折扣券:计算规则折扣`rule_discount`,`applied = min(rule_discount, remaining_cap)`;一次性使用并在`remark`追加同样片段(余额不维护)。 - 券发放(internal/service/user/coupon_add.go:11–55) - 直减券初始化`balance_amount=discount_value`;其他类型`balance_amount=NULL/0`。 - 退款(internal/api/admin/pay_refund_admin.go:189–228;internal/api/pay/wechat_notify.go:28–174) - 解析`orders.remark`恢复直减券余额与状态;同步回退`orders.discount_amount/ActualAmount`。 ## 配置与校验 - `coupons_max_discount_rate`(默认0.5)。 - 兼容多券叠加:逐券按余额与剩余封顶扣减,超过封顶的券不使用;`remark`记录每次使用的`applied_amount`。 ## 前端改动 - 结算页: - 展示“最多抵扣50%”;支持金额券余额显示与预估本次可抵扣金额。 - 当券面值大于封顶,自动按封顶计算应付并提示“剩余XX元券余额保留”。 - 管理端订单详情:展示已应用的`c::`明细与用户券余额。 ## 文档与错误码 - Swagger:更新`/api/app/lottery/join`;保留/新增积分兑换券/商品接口文档。 - 错误码:`coupon_exceeds_cap`、`coupon_no_balance`、`insufficient_points`、`duplicate_redeem`。 ## 迁移与兼容 - 历史未使用直减券:初始化`balance_amount=discount_value`。 - 已使用券:`balance_amount=0/NULL`。 - 无新表;仅一列新增与`remark`编码扩展。 ## 测试示例 - 面值100券、票价50、封顶25→应付25,`remark`含`|c::2500`,余额7500。 - 多券叠加至封顶;超过部分不使用;退款逐段恢复余额。 - 新订单不产生积分抵扣流水。 ## 变更文件参考 - 抽奖下单:internal/api/activity/lottery_app.go:110–176。 - 发券:internal/service/user/coupon_add.go:11–55。 - 退款:internal/api/admin/pay_refund_admin.go:189–228;internal/api/pay/wechat_notify.go:28–174。 - 用户券模型:internal/repository/mysql/model/user_coupons.gen.go(新增`balance_amount`)。