From 9dceff5baf8f01b850d10e970ee7f04bdba4f495 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Wed, 27 May 2026 03:38:39 -0400 Subject: [PATCH] feat(fusion_helpdesk_central): client-label field, views, branded ack email x_fc_client_label on helpdesk.ticket (+ list/search exposure), create() override sends a branded acknowledgement (magic link via get_portal_url) for in-app-channel tickets only. 3 Enterprise tests (run on nexa). Co-Authored-By: Claude Opus 4.7 (1M context) --- fusion_helpdesk_central/__manifest__.py | 4 +- .../data/mail_template_ack.xml | 55 +++++++++++++++ fusion_helpdesk_central/models/__init__.py | 1 + .../models/helpdesk_ticket.py | 57 ++++++++++++++++ fusion_helpdesk_central/tests/__init__.py | 2 + .../tests/test_identity.py | 68 +++++++++++++++++++ .../views/helpdesk_ticket_views.xml | 34 ++++++++++ 7 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 fusion_helpdesk_central/data/mail_template_ack.xml create mode 100644 fusion_helpdesk_central/models/helpdesk_ticket.py create mode 100644 fusion_helpdesk_central/tests/__init__.py create mode 100644 fusion_helpdesk_central/tests/test_identity.py create mode 100644 fusion_helpdesk_central/views/helpdesk_ticket_views.xml diff --git a/fusion_helpdesk_central/__manifest__.py b/fusion_helpdesk_central/__manifest__.py index e1199021..8f2f61e7 100644 --- a/fusion_helpdesk_central/__manifest__.py +++ b/fusion_helpdesk_central/__manifest__.py @@ -3,7 +3,7 @@ # License OPL-1 { 'name': 'Fusion Helpdesk Central — Client API Keys', - 'version': '19.0.1.0.2', + 'version': '19.0.1.1.0', 'category': 'Productivity', 'summary': 'Admin UI on the central Odoo for issuing per-client API ' 'keys used by fusion_helpdesk client deployments.', @@ -28,7 +28,9 @@ Depends only on `helpdesk`. No client-side install needed. 'data': [ 'security/ir.model.access.csv', 'data/ir_config_parameter_data.xml', + 'data/mail_template_ack.xml', 'views/fusion_helpdesk_client_key_views.xml', + 'views/helpdesk_ticket_views.xml', ], 'installable': True, 'auto_install': False, diff --git a/fusion_helpdesk_central/data/mail_template_ack.xml b/fusion_helpdesk_central/data/mail_template_ack.xml new file mode 100644 index 00000000..7efdfa6a --- /dev/null +++ b/fusion_helpdesk_central/data/mail_template_ack.xml @@ -0,0 +1,55 @@ + + + + + + Helpdesk: Ticket Acknowledgement (Fusion) + + We received your request [{{ object.ticket_ref or object.id }}] + {{ object.partner_id.id }} + {{ object.partner_id.lang }} + + +
+

Hello ,

+

+ Thanks for reaching out — we've received your request and our + support team will be in touch. Here are the details: +

+ + + + + + + + + +
Reference
Subject
+

+ + View & track your ticket + +

+

+ You can reply directly to this email to add information, follow up + from the link above, or sign up for an account from that page to + manage all of your requests in one place. +

+

+
+
+
+
+
diff --git a/fusion_helpdesk_central/models/__init__.py b/fusion_helpdesk_central/models/__init__.py index 91073a9b..61b5123a 100644 --- a/fusion_helpdesk_central/models/__init__.py +++ b/fusion_helpdesk_central/models/__init__.py @@ -1,2 +1,3 @@ # -*- coding: utf-8 -*- from . import fusion_helpdesk_client_key +from . import helpdesk_ticket diff --git a/fusion_helpdesk_central/models/helpdesk_ticket.py b/fusion_helpdesk_central/models/helpdesk_ticket.py new file mode 100644 index 00000000..fd9c872b --- /dev/null +++ b/fusion_helpdesk_central/models/helpdesk_ticket.py @@ -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, + ) diff --git a/fusion_helpdesk_central/tests/__init__.py b/fusion_helpdesk_central/tests/__init__.py new file mode 100644 index 00000000..2bded2f8 --- /dev/null +++ b/fusion_helpdesk_central/tests/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import test_identity diff --git a/fusion_helpdesk_central/tests/test_identity.py b/fusion_helpdesk_central/tests/test_identity.py new file mode 100644 index 00000000..f886efad --- /dev/null +++ b/fusion_helpdesk_central/tests/test_identity.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. +# License OPL-1 +"""Identity-keystone tests for the central helpdesk extensions. + +Runs on an Enterprise environment (helpdesk installed) — e.g. odoo-nexa or +odoo-trial. Validates that passing partner_email resolves the customer + +follower (native), that the client label is stored, and that the branded +acknowledgement only fires for in-app-channel tickets. +""" +from odoo.tests import TransactionCase, tagged + + +@tagged('post_install', '-at_install', 'fusion_helpdesk_central') +class TestTicketIdentity(TransactionCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.team = cls.env['helpdesk.team'].search([], limit=1) + + def _ack_mails(self, ticket): + return self.env['mail.mail'].search([ + ('model', '=', 'helpdesk.ticket'), + ('res_id', '=', ticket.id), + ]).filtered(lambda m: 'received your request' in (m.subject or '')) + + def test_partner_resolution_follower_and_label(self): + ticket = self.env['helpdesk.ticket'].create({ + 'name': 'Keystone test', + 'team_id': self.team.id, + 'partner_email': 'keystone.newperson@example.com', + 'partner_name': 'Key Stone', + 'x_fc_client_label': 'ENTECH', + }) + self.assertEqual(ticket.x_fc_client_label, 'ENTECH') + self.assertTrue( + ticket.partner_id, + "native create() should find-or-create a partner from partner_email") + self.assertEqual(ticket.partner_id.email, 'keystone.newperson@example.com') + self.assertIn( + ticket.partner_id, ticket.message_partner_ids, + "the customer must be subscribed as a follower") + + def test_ack_email_for_inapp_ticket(self): + ticket = self.env['helpdesk.ticket'].create({ + 'name': 'Ack test', + 'team_id': self.team.id, + 'partner_email': 'ack.person@example.com', + 'partner_name': 'Ack Person', + 'x_fc_client_label': 'ENTECH', + }) + self.assertTrue( + self._ack_mails(ticket), + "an in-app ticket with a customer email should get our ack email") + + def test_no_ack_without_client_label(self): + # Simulates an external web-form ticket — no client label, so our + # acknowledgement must NOT fire (avoids double-acknowledgement). + ticket = self.env['helpdesk.ticket'].create({ + 'name': 'External web ticket', + 'team_id': self.team.id, + 'partner_email': 'external.web@example.com', + 'partner_name': 'External Web', + }) + self.assertFalse( + self._ack_mails(ticket), + "no client label => our acknowledgement should not send") diff --git a/fusion_helpdesk_central/views/helpdesk_ticket_views.xml b/fusion_helpdesk_central/views/helpdesk_ticket_views.xml new file mode 100644 index 00000000..61f73229 --- /dev/null +++ b/fusion_helpdesk_central/views/helpdesk_ticket_views.xml @@ -0,0 +1,34 @@ + + + + + + fhc.helpdesk.ticket.list.client_label + helpdesk.ticket + + + + + + + + + + fhc.helpdesk.ticket.search.client_label + helpdesk.ticket + + + + + + + + + +