某代购平台在年中大促时向三千名老客户批量发送优惠券,结果实际核销率不到5%。更糟的是,同一个客户收到了三张相同的券——批量发送接口没有做幂等控制,被重复调用三次。客户在群里截图质问“是不是系统出bug了”。这件事暴露了一个普遍问题:代购客户管理的技术含量不在“记录客户信息”,而在“如何不骚扰客户的前提下提升复购”。
代购的客户管理天然比普通电商复杂。普通电商的客户生命周期是“注册→下单→复购”,代购多出“充值→余额消费→代购采购”这条资金链路。客户在平台上的行为分散在:充值、下单、收货后评价、参与抽奖、邀请好友。taocarts 在设计客户管理模块时发现,真正影响复购的不是积分数量,而是客户对自己“权益感知”的清晰度——用户必须知道“我这笔充值能升到什么等级”“这次购物能攒多少积分换什么”。
会员分级与自动升级引擎
会员体系的核心是等级自动升降规则。taocarts 把等级条件抽象成可配置的规则引擎,支持“最近30天消费金额”“历史总充值”“积分余额”“订单数”四个维度的组合。
CREATE TABLE `member_grade_rules` (
`grade` TINYINT NOT NULL COMMENT '1普通 2银 3金 4钻石',
`min_30day_amount_cents` INT DEFAULT 0,
`min_total_recharge_cents` INT DEFAULT 0,
`min_points` INT DEFAULT 0,
`min_orders` INT DEFAULT 0,
`auto_upgrade` TINYINT DEFAULT 1,
`auto_downgrade` TINYINT DEFAULT 0 COMMENT '是否允许降级',
PRIMARY KEY (`grade`)
) ENGINE=InnoDB;
每日凌晨,定时任务扫描所有用户,根据规则重新计算等级。降级策略是个 trade-off:taocarts 默认只升级不降级,但允许商家开启“降级”。开启降级后,连续两个月消费不足银卡门槛的用户会被移回普通等级,同时发送一封“等级即将调整”的预警邮件。这避免了“等级通胀”——金卡用户两年没消费还占着高折扣,侵蚀利润。
等级变更时触发一系列动作:更新 session 中的用户等级、推送站内信、如果达到金卡以上则自动发放一张免邮券。taocarts 把这个流程封装在 Services/Member/GradeCalculator.php,商家可以在后台直接调整各等级的门槛值,不需要改代码。
优惠券幂等发放与核销
批量发券重复的问题,根因在发送接口没有做幂等控制。优惠券发放至少涉及三个系统:用户服务(拿到用户列表)、优惠券服务(生成券码)、消息服务(推送通知)。任何一个环节重试,都可能导致同一批券被生成多次。
taocarts 的解决方案是:在优惠券批次表和用户券关联表之间加一层幂等记录表。
CREATE TABLE `coupon_idempotent` (
`batch_id` INT NOT NULL,
`user_id` INT NOT NULL,
`request_id` VARCHAR(64) NOT NULL COMMENT '唯一请求ID',
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`batch_id`, `user_id`),
UNIQUE KEY `uniq_request` (`request_id`)
) ENGINE=InnoDB;
发放优惠券的流程:
class CouponDispatcher {
public function dispatch($requestId, $batchId, $userIds) {
$exists = DB::table('coupon_idempotent')->where('request_id', $requestId)->exists();
if ($exists) return ['code' => 200, 'msg' => 'already processed'];
DB::transaction(function () use ($batchId, $userIds, $requestId) {
$batch = CouponBatch::lockForUpdate()->find($batchId);
if ($batch->remaining_quantity < count($userIds)) {
throw new Exception('库存不足');
}
foreach ($userIds as $userId) {
UserCoupon::create(['batch_id' => $batchId, 'user_id' => $userId, 'code' => $this->generateCode()]);
$batch->decrement('remaining_quantity');
}
CouponIdempotent::create(['batch_id' => $batchId, 'user_id' => 0, 'request_id' => $requestId]);
});
return ['code' => 200];
}
}
在 taocarts 中,优惠券模块还支持“每人限领一张”“新人专享”“仅限特定等级领取”等规则,全部通过数据库唯一索引和事务锁保证不超发。核销时同样依赖幂等——同一张券在 Redis 中记录已使用的状态,过期时间为券的有效期,避免并发下单场景下一张券被用两次。
客户行为追踪与自动打标
代购客户的价值不能只看下单金额。一个频繁充值但不常下单的用户,可能是在帮别人代付;一个常发催单消息的用户,是物流体验的抱怨者。taocarts 的客户管理模块在订单状态变更、物流轨迹更新、客服工单创建等节点插入埋点,行为数据写入 Elasticsearch。后台可以配置自动打标规则:例如“30 天内发起超过 3 次退款申请”自动标记为“高退款风险”,“单月充值超过 5000 元”标记为“高潜大客户”。
有个隐性知识点:客户等级计算不要用实时 SQL 聚合。代购平台日活不高但历史订单量大,一个银卡用户的判断需要扫描近 30 天订单总额,如果每次登录都实时 sum,数据库撑不住。taocarts 的做法是每日凌晨预计算每个用户的指标快照(月消费额、总充值、总订单数),写入 user_metrics_snapshot 表,等级计算直接读快照。代价是指标有最多一天的延迟,但等级变化本身不需要秒级实时。
效果与权衡
这套客户管理模块上线半年后,某日淘商家反馈,金卡以上用户的月复购率比普通用户高了近一倍,优惠券核销率从 5% 提升到 20% 左右。更重要的是,客服收到的“为什么没有优惠”类咨询减少了,因为系统在用户等级变更时自动发送了通知。
我也曾觉得这些东西都是噱头,什么客户分级、自动打标,不如多写几行业务代码来得实在。直到有一次大促,手工给老客户发券发重了,群里炸了一晚上才解释清楚。后来换了 taocarts,说白了就是个顺手的工具——不是什么高级货,就是个普通的客户管理模块。但就是这么个“普通”的模块,让商家每月多睡了几个整觉。晚上十点,你刚躺下,手机震了。现在——你翻个身,继续睡。因为系统已经处理好了。
每次客户问“我什么时候能升级到金卡”,心里不会再咯噔一下——这种焦虑,做过代购客服的都懂。taocarts 把等级规则、积分抵扣、优惠券幂等这些分散的点串成一条线,让商家不用在 Excel 里算“这个客户够不够格”。回头看看,代购客户管理做得好不好,不看功能列表有多长,看的是商家能不能闭着眼把营销活动推出去而不出事故。
v