很多售后团队做 Odoo Helpdesk 补偿流程时,会把需求说成一句话:
工单里给客户发一张优惠券就行。
但企业版 Helpdesk + Loyalty 的实现比“发一张券”复杂得多。它至少同时处理四件事:
- 优惠券和礼品卡不是一回事,生成路径不同;
- “发送邮件”和“生成网站分享链接”不是同一个动作;
- 工单和 loyalty card 之间需要双向留痕,后续客服才能回查;
- 客服侧看到的是 ticket 视角,客户侧拿到的却可能是门户/网站可消费的 share link。
所以这个模块真正解决的不是“客服发券”,而是:
把售后补偿做成一条既能回溯、又能对外交付的服务恢复链路。
这也是为什么你会看到同样是从工单生成 coupon,标准代码却拆成邮件发送、网站分享、gift card 生成、工单统计入口几条线。
先看主链路
1)工单先成为补偿动作的主记录
helpdesk_sale_loyalty.models.helpdesk_ticket 在 ticket 上挂了 coupon_ids,同时计算 coupons_count 和 gift_card_count。
这意味着在企业版设计里,补偿并不是“发出去就算了”,而是持续挂在工单上的一个状态对象。客服后续追问“这张券有没有生成”“客户收到的是 coupon 还是 gift card”“之前已经补偿过几次”,都可以从 ticket 回看。
open_coupons() 则把 ticket 重新打开到对应的 loyalty.card 列表/表单,形成客服侧的运营回路。
2)标准“发券邮件”动作其实先建 loyalty card,再开邮件向导
helpdesk_sale_coupon_generate.action_coupon_generate_send() 的顺序非常清楚:
- 用
loyalty.card创建真正的券; - 把新券挂到
ticket.coupon_ids; - 在工单 chatter 里写一条“Coupon created”来源消息;
- 反过来在 coupon 上也写 origin link,指回 ticket;
- 再根据 communication plan 的默认模板,打开
mail.compose.message向导。
也就是说:
邮件不是补偿的本体,loyalty card 才是。
这点很关键。很多项目二开时只顾着“自动发邮件”,最后漏掉了 loyalty card 的回写或 origin 留痕,后续客服根本没法追踪。
3)网站分享动作不是邮件动作的一个参数,而是另一条显式分支
在 website_helpdesk_sale_loyalty 里,action_coupon_generate_share() 并不会打开邮件向导。
它做的事情是:
- 同样先创建
loyalty.card; - 同样挂回
ticket.coupon_ids; - 然后直接调用
coupon.share的create_share_action(coupon=coupon),产出分享动作。
这说明网站场景下,标准企业版把“通过门户/网站发送一个可消费链接”视为与“邮件模板发券”并列的交付方式,而不是附属按钮。
对客服业务来说,这很有现实意义:
- 如果客户正在门户里跟进售后,发 share link 比发正式邮件更快;
- 如果客服需要人工确认后再发外链,这条路径更灵活;
- 如果你想在站外 IM、企业微信或客服工作台继续分发,也更容易接入。
4)Gift Card 还要处理网站消息回写
Gift card 路径又和 coupon 不完全一样。
在 helpdesk_sale_giftcard_generate_wizard.generate_giftcard() 里,系统会:
- 强制
coupon_qty = 1、mode = selected,把客户限定为当前 ticket 的 partner; - 调用通用 loyalty 生成逻辑;
- 把生成出来的 gift card 继续挂到
ticket.coupon_ids; - 遍历
coupon.website_message_ids,把网站侧消息正文和附件回贴到 ticket chatter; - 再补一条带后台跳转链接的“Gift Card created”消息;
- 同时在 coupon 侧写 origin link 回 ticket。
这段设计特别值得注意:
礼品卡不只是“生成一种特殊优惠券”,它还默认带着一套网站消息与附件回流机制。
这让客服在工单里能看到客户侧真正收到过什么内容,而不只是看到一张卡号记录。
为什么要把这些动作拆这么细
因为“生成补偿对象”和“把补偿交付给客户”是两件不同的事
标准代码把 loyalty card 生成放在前,把邮件向导 / share action / chatter 留痕放在后。这个顺序说明产品设计者在强调一件事:
- 先确保补偿对象被创建、可审计、可追踪;
- 再决定通过哪个渠道交付给客户。
如果反过来做,很多售后团队都会陷入一个典型问题:邮件发了,但系统里没有一张可回查的 card;或者客服明明补偿过,却无法判断客户最终拿到的是哪一种链接或模板。
因为客服补偿本质上也是一条网站交付链
只要用了 coupon.share 和 website_message_ids,这条链就已经不是纯后台逻辑了。它天然跨到了网站/门户交付层。
这也是为什么这个题比普通 Loyalty 更适合放在 企业, 网站 类目里:标准源码关注的正是“客服补偿如何以网站可消费形式被客户拿到”。
实战里最容易踩的坑
坑 1:只做自动发信,不做工单与 loyalty card 互链
如果你只在 ticket 按钮里“生成券并立即发邮件”,却没保留 chatter 留痕和 origin link,客服事后会失去追踪能力。标准实现的价值,恰恰在于 ticket 与 coupon 双向可追溯。
坑 2:把 share link 当成邮件模板里的一个变量
网站分享动作是独立 action,不只是某个模板字段。把它错误地塞进邮件模板,通常会失去标准分享流程里的权限、URL 生成和后续扩展能力。
坑 3:忽略 coupon 与 gift card 的交付差异
Gift card 路径会把 website_message_ids 回写到 ticket,这和普通 coupon 明显不同。如果你把两者粗暴统一成一个“补偿弹窗”,最后要么遗漏附件,要么客服看不到客户实际收到的内容。
给实施和二开的建议
- 先确定补偿对象类型。 面向未来消费折扣,用 coupon;面向储值或金额型补偿,用 gift card。
- 把“生成 card”和“发给客户”拆开思考。 这样无论邮件、share link 还是客服手工转发,都能挂在同一条审计链上。
- 保留 ticket ↔ loyalty card 的双向留痕。 这是客服二线排障和客诉复盘的关键。
- 如果要接第三方客服渠道,优先复用 share action。 因为标准网站交付链已经替你把“可消费对象”抽象好了。
一句话总结
Odoo 企业版网站 Helpdesk 补偿不是“客服发一封优惠券邮件”。
它的真实设计是:先在工单里生成可审计的 loyalty card,再根据场景分流到邮件发送、网站 share link 或 gift card 网站消息回写,并始终保持 ticket 与补偿对象的双向关联。
理解了这一点,你做售后补偿二开时才不会只盯着“怎么发出去”,而会把“怎么留痕、怎么回查、怎么在网站侧交付”一起设计进去。
DISCUSSION
评论区