9.2 KiB
租客成长等级与主动短信触达方案
一、租客成长等级
功能范围
- 只统计租号订单,即
rental_orders。 - 不统计撞车订单,即
mohong_orders。 - 积分只按已完成租号订单的实付租金累计,不含押金。
- 等级三档:铂金、钻石、巅峰。
- 下单租号时按用户当前等级使用折扣。
- 折扣和升级门槛后台可配置。
- 历史订单保存价格、等级、折扣快照,后台修改配置不影响历史订单。
积分规则
推荐规则:
成长积分 = 已完成租号订单实付租金金额
1 元实付租金 = 1 积分
不建议统计押金,原因是押金可能退款、免押、暂扣或赔付,直接计入成长积分会让财务口径变复杂。
积分发放时机建议放在租号订单完成后,而不是支付成功后。这样可以避免用户付款后退款、取消或关闭订单导致刷积分。
后台配置
使用现有 system_configs,新增配置项:
renter.growth_level_rules
建议默认值:
{
"enabled": true,
"points_per_yuan": 1,
"levels": [
{ "code": "platinum", "name": "铂金", "min_points": 300, "discount_bps": 9900 },
{ "code": "diamond", "name": "钻石", "min_points": 1000, "discount_bps": 9800 },
{ "code": "peak", "name": "巅峰", "min_points": 5000, "discount_bps": 9500 }
]
}
discount_bps 使用万分比,避免小数误差。例如 9800 表示 9.8 折。
数据库字段
users 建议新增:
renter_growth_points:租客成长积分。renter_growth_level:当前租客成长等级。
rental_orders 建议新增:
rent_original_amount_cent:原始租金。rent_discount_amount_cent:租金优惠金额。renter_growth_level:下单时命中的等级编码。renter_growth_level_name:下单时命中的等级名称。renter_discount_bps:下单时命中的折扣。growth_points_awarded:本单已发放积分,用于防重复。
下单折扣
在订单创建阶段应用折扣,支付阶段不重新计算。
现有租号订单创建位置:
backend/internal/modules/order/lifecycle.go
现有支付金额来自:
backend/internal/modules/payment/payment_start.go
amountCent := row.RentAmountCent + row.DepositAmountCent
因此订单创建时应直接把 RentAmountCent 写成折后租金,后续支付、退款、结算、仲裁都沿用订单金额。
推荐折扣范围:
- 只折扣租金。
- 押金不参与折扣。
- 折扣优先扣平台费,不影响号主收入。
- 如果折扣金额超过平台费,第一版建议限制为最多扣到平台费为 0,避免平台费出现负数。
自动升级
租号订单首次完成时:
- 校验
growth_points_awarded = 0,避免重复发放。 - 根据折后租金计算本单积分。
- 累加到
users.renter_growth_points。 - 根据
min_points自动计算用户当前等级。 - 更新
users.renter_growth_level。 - 回写
rental_orders.growth_points_awarded。
默认只升级不降级。若后台未来调整门槛,可以选择只影响后续升级判断,不主动批量降级。
前端范围
后台系统配置页:
- 配置是否启用。
- 配置每元积分。
- 配置三个等级的门槛积分。
- 配置三个等级的折扣。
后台用户管理:
- 展示成长等级。
- 展示成长积分。
- 支持后台调整积分或等级,操作写审计日志。
用户端订单页:
- 展示租金原价。
- 展示等级折扣。
- 展示优惠金额。
- 展示折后租金。
- 展示押金。
- 展示应付合计。
测试范围
- 铂金、钻石、巅峰不同等级折扣计算正确。
- 押金不打折。
- 折扣不影响号主收入。
- 支付金额等于折后租金加实付押金。
- 撞车订单完成不增加成长积分。
- 租号订单完成只发放一次成长积分。
- 积分达到门槛后自动升级。
- 后台修改配置不影响历史订单快照。
二、主动短信触达
业务目标
用户完成一笔租号订单后,平台可以主动发送短信,告知用户本月已经累计完成多少笔租号订单,以及距离领取奖励还差多少笔。
示例文案:
尊敬的 用户名:
您好,您已经在 大锤商行 累计完成 1 笔租号订单,再完成 x 笔即可领取 xxxx。
统计口径
- 只统计
rental_orders。 - 只统计状态为
completed的租号订单。 - 不统计
mohong_orders撞车订单。 - 按自然月统计,建议使用订单完成时间
settled_at。 - 月统计区间为当前月第一天 00:00:00 到下月第一天 00:00:00。
统计 SQL 口径示例:
SELECT COUNT(*)
FROM rental_orders
WHERE renter_id = ?
AND status = 'completed'
AND settled_at >= ?
AND settled_at < ?;
触发时机
推荐触发点:租号订单完成后。
现有完成入口:
backend/internal/modules/order/checkout_finalize.go
finalizeCheckout 会把订单状态改为 completed。短信不建议在事务内直接发送,避免短信服务失败导致订单完成失败。
推荐流程:
- 订单完成事务内写入短信待发送记录。
- 事务提交后由后台任务发送短信。
- 发送成功、失败、重试次数都落库。
短信通道
项目已有短信集成:
backend/internal/integrations/sms
当前 Provider 只支持登录验证码:
SendLoginCode(ctx context.Context, phone string, code string) error
主动短信需要扩展为模板短信能力,例如:
SendTemplate(ctx context.Context, phone string, templateCode string, params map[string]string) error
阿里云短信实际发送不能随意拼接任意文案,必须使用已审核的短信模板。因此后台可配置“模板 code、奖励规则、预览文案”,真实发送时只传模板变量。
后台配置
使用 system_configs,新增配置项:
sms.rental_completion_reminder
建议默认值:
{
"enabled": false,
"brand_name": "大锤商行",
"template_code": "",
"monthly_user_limit": 4,
"cooldown_hours": 24,
"rewards": [
{ "target_orders": 3, "reward_name": "成长礼包", "enabled": true },
{ "target_orders": 5, "reward_name": "专属优惠券", "enabled": true }
],
"preview_template": "尊敬的 {{nickname}}:您好,您已经在 {{brand_name}} 累计完成 {{completed_count}} 笔租号订单,再完成 {{remaining_count}} 笔即可领取 {{reward_name}}。"
}
规则说明:
enabled:总开关。brand_name:短信里展示的品牌名。template_code:阿里云审核通过的营销或通知短信模板 code。monthly_user_limit:单用户单月最多发送次数。cooldown_hours:同一用户两次主动短信最小间隔。rewards:奖励门槛,从小到大配置。preview_template:后台预览使用,真实发送以短信供应商模板为准。
计算 x 的规则:
- 获取用户本月完成租号订单数
completed_count。 - 找到第一个
target_orders > completed_count的奖励。 remaining_count = target_orders - completed_count。- 如果没有下一个奖励,默认不发送,或后续配置为发送达成提醒。
数据库表
建议新增短信发送记录表:
sms_messages
字段建议:
iduser_idphonebiz_type:例如rental_completion_reminderbiz_id:租号订单 ID。template_codetemplate_paramscontent_previewstatus:pending、sent、failed、cancelledretry_countlast_errorsent_atcreated_atupdated_at
建议加唯一索引:
uk_sms_messages_biz_type_biz_id_user
用于保证同一笔完成订单不会重复创建短信任务。
发送任务
新增后台任务,例如:
backend/internal/jobs/smsdispatch
任务逻辑:
- 查询
pending且重试次数未超限的短信。 - 调用短信 provider 发送模板短信。
- 成功后标记
sent,写sent_at。 - 失败后记录
last_error,增加retry_count。 - 超过最大重试次数后标记
failed。
限流与防打扰
发送前需要校验:
- 系统配置已启用。
- 用户手机号有效。
- 本订单尚未创建过同类短信。
- 用户本月主动短信次数未超过
monthly_user_limit。 - 用户距离上次主动短信超过
cooldown_hours。 - 找得到下一个奖励门槛。
第一版可以先不做用户退订,但如果短信属于营销性质,建议后续加用户短信订阅状态或退订名单。
前端范围
后台系统配置页:
- 开关。
- 品牌名。
- 模板 code。
- 单用户月发送上限。
- 冷却时间。
- 奖励门槛和奖励名称。
- 文案预览。
后台短信记录页可以作为二期,第一版可先通过数据库和日志排查。
测试范围
- 租号订单完成后创建短信待发送记录。
- 撞车订单完成不创建短信。
- 本月完成订单数统计正确。
- 根据奖励门槛计算
remaining_count正确。 - 找不到下一奖励时不发送。
- 单用户月上限生效。
- 冷却时间生效。
- 同一订单不会重复创建短信任务。
- 短信发送失败不影响订单完成。