diff --git a/fusion_helpdesk_central/__manifest__.py b/fusion_helpdesk_central/__manifest__.py index 004e39f8..c3ac1091 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.2.3.4', + 'version': '19.0.2.4.0', 'category': 'Productivity', 'summary': 'Admin UI on the central Odoo for issuing per-client API ' 'keys used by fusion_helpdesk client deployments.', diff --git a/fusion_helpdesk_central/data/mail_template_engagement.xml b/fusion_helpdesk_central/data/mail_template_engagement.xml index d139e2c3..61073537 100644 --- a/fusion_helpdesk_central/data/mail_template_engagement.xml +++ b/fusion_helpdesk_central/data/mail_template_engagement.xml @@ -48,22 +48,46 @@

Your team at has filed a request that needs your sign-off before - our team proceeds. A quick AI-prepared summary is - below; the full thread expands at the bottom if you - want the detail. + our team proceeds. The original request, our reply, + and a quick AI-prepared summary are below.

-
-
Summary
-
+
+
-
-
Request
-
+ +
+
+ Original Request — from +
+
+ +
- + +
+
+ Our Reply — from Nexa Systems Support +
+
+ +
+
+ + +
+
+ Summary for the Decision +
+
+ +
+
+ +
-
- View original request & full thread -
- -
-
-

This Approve / Reject link is single-use and will stop working once you've clicked it. @@ -129,10 +146,32 @@

Request of
-
-
- +
+ +
+
+ Original Request — from +
+
+ +
+ +
+
Our Reply
+
+ +
+
+ +
+
Summary for the Decision
+
+ +
+
+
diff --git a/fusion_helpdesk_central/migrations/19.0.2.4.0/pre-migration.py b/fusion_helpdesk_central/migrations/19.0.2.4.0/pre-migration.py new file mode 100644 index 00000000..fdbac075 --- /dev/null +++ b/fusion_helpdesk_central/migrations/19.0.2.4.0/pre-migration.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. +# License OPL-1 +"""Force re-import of the engagement mail templates on 19.0.2.4.0. + +The mail templates ship in `` so support's later +tweaks (different reply-to, custom signature, etc.) aren't blown away +by every routine module upgrade. The flip side: a structural change +to the template body in our own XML is silently skipped — the next +`-u` reads the new XML but Odoo refuses to overwrite the existing +row because of the noupdate flag. + +This release introduces the 3-section email layout (Original Request / +Our Reply / Summary) and we DELIBERATELY want it to land. So this +pre-migration deletes the existing template records + their +ir_model_data anchors BEFORE the upgrade's data load runs. The XML +import then re-creates them with the new body_html. + +Pre-migration > post-migration here because data load happens between +the two. If we deleted in post-migration, the data load would already +have skipped the update — too late. +""" +import logging + +_logger = logging.getLogger(__name__) + + +_TEMPLATE_XMLIDS = ( + 'mail_template_engagement', + 'mail_template_engagement_bulk', +) + + +def migrate(cr, version): + cr.execute( + """ + SELECT name, res_id FROM ir_model_data + WHERE module = 'fusion_helpdesk_central' + AND name IN %s + """, + (_TEMPLATE_XMLIDS,), + ) + rows = cr.fetchall() + if not rows: + _logger.info( + 'fusion_helpdesk_central 19.0.2.4.0 pre-migration: no ' + 'existing engagement templates to delete; nothing to do.' + ) + return + template_ids = [r[1] for r in rows] + cr.execute( + "DELETE FROM mail_template WHERE id IN %s", + (tuple(template_ids),), + ) + cr.execute( + """ + DELETE FROM ir_model_data + WHERE module = 'fusion_helpdesk_central' + AND name IN %s + """, + (_TEMPLATE_XMLIDS,), + ) + _logger.info( + 'fusion_helpdesk_central 19.0.2.4.0 pre-migration: dropped %s ' + 'engagement mail template(s) so the upgrade re-imports them ' + 'with the new 3-section layout: %s', + len(template_ids), ', '.join(r[0] for r in rows), + ) diff --git a/fusion_helpdesk_central/models/engagement_wizard.py b/fusion_helpdesk_central/models/engagement_wizard.py index 1ae5e438..d4aaface 100644 --- a/fusion_helpdesk_central/models/engagement_wizard.py +++ b/fusion_helpdesk_central/models/engagement_wizard.py @@ -416,7 +416,10 @@ class FusionHelpdeskEngagementWizard(models.TransientModel): if not email: raise UserError(_('Owner contact disappeared since you opened ' 'the wizard. Refresh and try again.')) - ticket._fc_reset_engagement(email, name, self.ai_summary or '') + ticket._fc_reset_engagement( + email, name, self.ai_summary or '', + findings=self.findings or '', + ) template = self.env.ref( 'fusion_helpdesk_central.mail_template_engagement', raise_if_not_found=False, @@ -442,11 +445,14 @@ class FusionHelpdeskEngagementWizard(models.TransientModel): if not email: raise UserError(_('Owner contact disappeared since you opened ' 'the wizard. Refresh and try again.')) - summary_by_id = {line.ticket_id.id: line.ai_summary or '' - for line in self.line_ids} + by_id = { + line.ticket_id.id: (line.ai_summary or '', line.findings or '') + for line in self.line_ids + } for ticket in self.ticket_ids: + summary, findings = by_id.get(ticket.id, ('', '')) ticket._fc_reset_engagement( - email, name, summary_by_id.get(ticket.id, ''), + email, name, summary, findings=findings, ) template = self.env.ref( 'fusion_helpdesk_central.mail_template_engagement_bulk', diff --git a/fusion_helpdesk_central/models/helpdesk_ticket.py b/fusion_helpdesk_central/models/helpdesk_ticket.py index b1ca7509..e1ce4c72 100644 --- a/fusion_helpdesk_central/models/helpdesk_ticket.py +++ b/fusion_helpdesk_central/models/helpdesk_ticket.py @@ -82,6 +82,14 @@ class HelpdeskTicket(models.Model): help='OpenAI-generated brief shown to the owner in the approval ' 'email. Editable in the wizard before sending; frozen after.', ) + x_fc_engagement_findings = fields.Text( + string='Engagement Findings', copy=False, + help='The support engineer\'s reply / analysis (typed in the ' + 'wizard\'s Findings field). Sent to the owner in the ' + 'approval email alongside the original request and the AI ' + 'summary so they see the back-and-forth context, not just ' + 'a paraphrase. Frozen at send-time.', + ) x_fc_engagement_turnaround_hours = fields.Float( string='Owner Turnaround (h)', compute='_compute_engagement_turnaround', @@ -238,7 +246,8 @@ class HelpdeskTicket(models.Model): monkeypatch it for deterministic assertions.""" return uuid.uuid4().hex - def _fc_reset_engagement(self, owner_email, owner_name, ai_summary): + def _fc_reset_engagement(self, owner_email, owner_name, ai_summary, + findings=''): """Stamp a fresh pending engagement on this ticket — invalidates any previous token + clears decided/reminded timestamps so the cron and the reporting view see a clean slate. @@ -248,6 +257,11 @@ class HelpdeskTicket(models.Model): up as the snapshot. If normalisation fails, we still proceed using the raw value — the email will probably bounce but state is consistent and re-engaging fixes it. + + `findings` is the support engineer's reply text from the wizard — + stored on the ticket so the mail template can show it as the + "My Reply" section without context-magic, and so it survives as + audit history once the engagement is decided. """ self.ensure_one() normalised = email_normalize(owner_email or '') or (owner_email or '') @@ -260,6 +274,7 @@ class HelpdeskTicket(models.Model): 'x_fc_engagement_reminded_at': False, 'x_fc_engagement_decided_at': False, 'x_fc_ai_summary': ai_summary or '', + 'x_fc_engagement_findings': findings or '', }) def action_add_owner_as_follower(self):