feat(fusion_helpdesk): customer follow-up + embedded ticket inbox
Squash-merge of feat/helpdesk-customer-followup. The billing and fusion_login_audit work from that branch is already on main (landed separately); this lands only the helpdesk feature. - Identity keystone: submit() forwards partner_email/partner_name/ x_fc_client_label so the central Helpdesk find-or-creates the customer partner and subscribes them as a follower (enables reply emails + magic link). - Embedded in-app 'My Tickets' inbox: server-side scoped read/reply RPC endpoints, per-user seen tracking (fusion.helpdesk.ticket.seen), systray unread badge. Defense-in-depth scope domain + _norm_email normalisation (wildcard emails cannot widen scope). - fusion_helpdesk_central: x_fc_client_label field + list/search views + branded acknowledgement email template. - Deployed and smoke-tested live: nexa central 19.0.1.1.0, entech client 19.0.1.4.1 (requires Contact Creation on the central service account). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import fusion_helpdesk_client_key
|
||||
from . import helpdesk_ticket
|
||||
|
||||
57
fusion_helpdesk_central/models/helpdesk_ticket.py
Normal file
57
fusion_helpdesk_central/models/helpdesk_ticket.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2026 Nexa Systems Inc.
|
||||
# License OPL-1
|
||||
"""Central-side helpdesk.ticket extensions for the customer follow-up flow.
|
||||
|
||||
Adds the `x_fc_client_label` deployment tag (set by the in-app reporter so
|
||||
the embedded inbox can scope per client) and sends a branded acknowledgement
|
||||
email — carrying the portal magic link — when an in-app ticket is created.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HelpdeskTicket(models.Model):
|
||||
_inherit = 'helpdesk.ticket'
|
||||
|
||||
x_fc_client_label = fields.Char(
|
||||
string='Client Deployment', index=True, copy=False,
|
||||
help='Deployment tag (e.g. ENTECH) set by the fusion_helpdesk in-app '
|
||||
'reporter. Scopes the embedded "My Tickets" inbox per client and '
|
||||
'lets support filter tickets by originating deployment.',
|
||||
)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
tickets = super().create(vals_list)
|
||||
tickets._fc_send_ack_email()
|
||||
return tickets
|
||||
|
||||
def _fc_send_ack_email(self):
|
||||
"""Send the branded acknowledgement (with magic link) to the customer.
|
||||
|
||||
Only fires for in-app-channel tickets (those tagged with a client
|
||||
label) that have a customer email — external web-form submissions
|
||||
rely on the native website confirmation, so this won't double-send.
|
||||
The whole thing is best-effort: a template/mail failure must never
|
||||
block ticket creation, so we log and move on.
|
||||
"""
|
||||
template = self.env.ref(
|
||||
'fusion_helpdesk_central.mail_template_ticket_ack',
|
||||
raise_if_not_found=False,
|
||||
)
|
||||
if not template:
|
||||
return
|
||||
for ticket in self:
|
||||
if not (ticket.x_fc_client_label and ticket.partner_email):
|
||||
continue
|
||||
try:
|
||||
template.send_mail(ticket.id, force_send=False)
|
||||
except Exception: # noqa: BLE001 — ack must never block create
|
||||
_logger.exception(
|
||||
'fusion_helpdesk_central: acknowledgement email failed '
|
||||
'for ticket %s (%s)', ticket.id, ticket.x_fc_client_label,
|
||||
)
|
||||
Reference in New Issue
Block a user