The owner only saw the AI summary, which was a paraphrase of the user
report — they couldn't see the actual request OR what we said back.
Restructure the engagement email into three sections so the owner can
read the conversation and not just the AI's take:
1. Original Request (from the reporter) — ticket.description, no
longer buried in a <details> collapsible at the bottom
2. Our Reply — the wizard's "Your Findings" text, now persisted on
the ticket so the email template can render it directly. This is
the engineer's analysis / response to the request.
3. Summary for the Decision — the AI-generated brief
Approve / Reject buttons stay below all three. Bulk email mirrors the
same per-card structure.
New ticket field x_fc_engagement_findings (Text, copy=False) stores
the findings at send-time so they survive as audit history. Wizard's
_action_send_single / _action_send_bulk pass findings into
_fc_reset_engagement; bulk uses per-line findings + per-line summary.
Mail templates are in <data noupdate="1"> so a plain -u doesn't
re-import them. Pre-migration in migrations/19.0.2.4.0/pre-migration.py
deletes the existing template records + ir_model_data so the upgrade's
data load re-creates them with the new body_html. Pre- (not post-)
because data load happens between the two phases.
Smoke-tested live on nexa: rendered template HTML contains all three
section headers at the expected positions with their expected content
markers (ORIGINAL FROM RIYA in Original Request, REPLY-FROM-GURPREET
in Our Reply, the summary text in Summary for the Decision).
Bumps fusion_helpdesk_central to 19.0.2.4.0.
209 lines
13 KiB
XML
209 lines
13 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!--
|
|
Copyright 2026 Nexa Systems Inc.
|
|
License OPL-1
|
|
|
|
Two mail templates for the owner-approval engagement flow:
|
|
|
|
* mail_template_engagement — single ticket
|
|
* mail_template_engagement_bulk — multiple tickets, one card per ticket,
|
|
per-ticket approve/reject buttons
|
|
|
|
Both use {{ ctx.fhc_personal_note }} + {{ ctx.fhc_is_reminder }} from the
|
|
wizard's with_context(**data) so dynamic per-send data reaches the body.
|
|
|
|
noupdate=1 so support's later tweaks (e.g. a different reply-to)
|
|
survive every fusion_helpdesk_central upgrade.
|
|
-->
|
|
<odoo>
|
|
<data noupdate="1">
|
|
|
|
<!-- ============== SINGLE TICKET ENGAGEMENT ============== -->
|
|
<record id="mail_template_engagement" model="mail.template">
|
|
<field name="name">Helpdesk: Owner Approval Request (Single)</field>
|
|
<field name="model_id" ref="helpdesk.model_helpdesk_ticket"/>
|
|
<field name="subject">{{ ctx.get('fhc_is_reminder') and 'Reminder: still waiting on your approval' or 'Action needed: please review' }} — "{{ object.name }}"</field>
|
|
<field name="email_to">{{ object.x_fc_engagement_email }}</field>
|
|
<field name="reply_to">{{ (object.user_id.email or object.team_id.alias_email or object.company_id.email or '') }}</field>
|
|
<field name="lang">en_US</field>
|
|
<field name="auto_delete" eval="True"/>
|
|
<field name="body_html" type="html">
|
|
<div style="margin:0; padding:0; font-family:Arial, Helvetica, sans-serif; color:#21252b; font-size:14px;">
|
|
<p>Hi <t t-out="object.x_fc_engagement_name or 'there'"/>,</p>
|
|
|
|
<t t-if="ctx.get('fhc_is_reminder')">
|
|
<p style="background:#fff8e6; border-left:3px solid #d4a017; padding:8px 12px; margin:12px 0;">
|
|
Following up on the request below — the original
|
|
email was sent a few days ago and we haven't
|
|
heard back yet. Same Approve / Reject buttons,
|
|
same one click.
|
|
</p>
|
|
</t>
|
|
<t t-elif="ctx.get('fhc_personal_note')">
|
|
<p style="font-style:italic; color:#444;">
|
|
<t t-out="ctx.get('fhc_personal_note')"/>
|
|
</p>
|
|
</t>
|
|
|
|
<p>
|
|
Your team at <b><t t-out="object.x_fc_client_label or 'your deployment'"/></b>
|
|
has filed a request that needs your sign-off before
|
|
our team proceeds. The original request, our reply,
|
|
and a quick AI-prepared summary are below.
|
|
</p>
|
|
|
|
<div style="margin:14px 0; font-weight:600; font-size:1.05rem;">
|
|
<t t-out="object.name"/>
|
|
</div>
|
|
|
|
<!-- 1. Original request from the reporter. -->
|
|
<div style="margin:18px 0; padding:12px 14px; background:#fff; border:1px solid #d8dadd; border-radius:6px;">
|
|
<div style="font-size:0.78rem; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; color:#6c757d; margin-bottom:8px;">
|
|
Original Request<t t-if="object.partner_name"> — from <t t-out="object.partner_name"/></t>
|
|
</div>
|
|
<div style="line-height:1.5;">
|
|
<t t-out="object.description or '(no description provided)'"/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 2. Support engineer's reply (the wizard's findings). -->
|
|
<div t-if="object.x_fc_engagement_findings"
|
|
style="margin:18px 0; padding:12px 14px; background:#eef5ff; border:1px solid #c7dcfa; border-radius:6px;">
|
|
<div style="font-size:0.78rem; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; color:#1e3a5f; margin-bottom:8px;">
|
|
Our Reply — from Nexa Systems Support
|
|
</div>
|
|
<div style="white-space:pre-wrap; line-height:1.5;">
|
|
<t t-out="object.x_fc_engagement_findings"/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 3. AI-prepared summary. -->
|
|
<div style="margin:18px 0; padding:12px 14px; background:#f9fafb; border:1px solid #e5e7eb; border-radius:6px;">
|
|
<div style="font-size:0.78rem; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; color:#6c757d; margin-bottom:8px;">
|
|
Summary for the Decision
|
|
</div>
|
|
<div style="white-space:pre-wrap; line-height:1.5;">
|
|
<t t-out="object.x_fc_ai_summary or '(no AI summary — read the original request and our reply above)'"/>
|
|
</div>
|
|
</div>
|
|
|
|
<table cellpadding="0" cellspacing="0" style="margin:24px 0 8px 0;">
|
|
<tr>
|
|
<td style="padding-right:8px;">
|
|
<a t-attf-href="{{ object.get_base_url() }}/fusion_helpdesk/engagement/{{ object.x_fc_engagement_token }}/approve"
|
|
target="_blank"
|
|
style="background:linear-gradient(135deg, #5cc66f 0%, #28a745 100%); padding:12px 22px; text-decoration:none; color:#ffffff; border-radius:6px; font-weight:700; font-size:14px; display:inline-block;">
|
|
✓ Approve
|
|
</a>
|
|
</td>
|
|
<td>
|
|
<a t-attf-href="{{ object.get_base_url() }}/fusion_helpdesk/engagement/{{ object.x_fc_engagement_token }}/reject"
|
|
target="_blank"
|
|
style="background:linear-gradient(135deg, #e85d68 0%, #dc3545 100%); padding:12px 22px; text-decoration:none; color:#ffffff; border-radius:6px; font-weight:700; font-size:14px; display:inline-block;">
|
|
✗ Reject
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p style="color:#6c757d; font-size:12px; margin-top:24px;">
|
|
This Approve / Reject link is single-use and will
|
|
stop working once you've clicked it.
|
|
</p>
|
|
<p style="color:#6c757d; font-size:12px;">— Nexa Systems Support</p>
|
|
</div>
|
|
</field>
|
|
</record>
|
|
|
|
<!-- ============== BULK ENGAGEMENT ============== -->
|
|
<record id="mail_template_engagement_bulk" model="mail.template">
|
|
<field name="name">Helpdesk: Owner Approval Request (Bulk)</field>
|
|
<field name="model_id" ref="helpdesk.model_helpdesk_ticket"/>
|
|
<field name="subject">Action needed: {{ len(ctx.get('fhc_bulk_ticket_ids') or []) }} requests need your sign-off</field>
|
|
<field name="email_to">{{ object.x_fc_engagement_email }}</field>
|
|
<field name="reply_to">{{ (object.user_id.email or object.team_id.alias_email or object.company_id.email or '') }}</field>
|
|
<field name="lang">en_US</field>
|
|
<field name="auto_delete" eval="True"/>
|
|
<field name="body_html" type="html">
|
|
<div style="margin:0; padding:0; font-family:Arial, Helvetica, sans-serif; color:#21252b; font-size:14px;">
|
|
<p>Hi <t t-out="object.x_fc_engagement_name or 'there'"/>,</p>
|
|
|
|
<t t-if="ctx.get('fhc_personal_note')">
|
|
<p style="font-style:italic; color:#444;">
|
|
<t t-out="ctx.get('fhc_personal_note')"/>
|
|
</p>
|
|
</t>
|
|
|
|
<p>
|
|
<t t-out="len(ctx.get('fhc_bulk_ticket_ids') or [])"/>
|
|
requests from <b><t t-out="object.x_fc_client_label or 'your deployment'"/></b>
|
|
need your sign-off. Each can be approved or rejected
|
|
independently — clicking a button on one card only
|
|
acts on that card.
|
|
</p>
|
|
|
|
<t t-set="bulk_tickets" t-value="object.env['helpdesk.ticket'].browse(ctx.get('fhc_bulk_ticket_ids') or [])"/>
|
|
<t t-foreach="bulk_tickets" t-as="bt">
|
|
<div style="margin:18px 0; padding:14px 16px; background:#fff; border:1px solid #d8dadd; border-radius:8px;">
|
|
<div style="font-size:0.75rem; color:#6c757d; margin-bottom:6px;">Request <t t-out="bt_index + 1"/> of <t t-out="bt_size"/></div>
|
|
<div style="font-weight:600; font-size:1.02rem; margin-bottom:12px;"><t t-out="bt.name"/></div>
|
|
|
|
<div style="margin-bottom:10px; padding:10px 12px; background:#fafafa; border:1px solid #e5e7eb; border-radius:6px; font-size:0.9rem;">
|
|
<div style="font-size:0.72rem; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; color:#6c757d; margin-bottom:6px;">
|
|
Original Request<t t-if="bt.partner_name"> — from <t t-out="bt.partner_name"/></t>
|
|
</div>
|
|
<div style="line-height:1.5;">
|
|
<t t-out="bt.description or '(no description provided)'"/>
|
|
</div>
|
|
</div>
|
|
|
|
<div t-if="bt.x_fc_engagement_findings"
|
|
style="margin-bottom:10px; padding:10px 12px; background:#eef5ff; border:1px solid #c7dcfa; border-radius:6px; font-size:0.9rem;">
|
|
<div style="font-size:0.72rem; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; color:#1e3a5f; margin-bottom:6px;">Our Reply</div>
|
|
<div style="white-space:pre-wrap; line-height:1.5;">
|
|
<t t-out="bt.x_fc_engagement_findings"/>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="margin-bottom:12px; padding:10px 12px; background:#f9fafb; border:1px solid #e5e7eb; border-radius:6px; font-size:0.9rem;">
|
|
<div style="font-size:0.72rem; font-weight:700; text-transform:uppercase; letter-spacing:0.06em; color:#6c757d; margin-bottom:6px;">Summary for the Decision</div>
|
|
<div style="white-space:pre-wrap; line-height:1.5;">
|
|
<t t-out="bt.x_fc_ai_summary or '(no AI summary — read the original request and our reply above)'"/>
|
|
</div>
|
|
</div>
|
|
|
|
<table cellpadding="0" cellspacing="0">
|
|
<tr>
|
|
<td style="padding-right:8px;">
|
|
<a t-attf-href="{{ object.get_base_url() }}/fusion_helpdesk/engagement/{{ bt.x_fc_engagement_token }}/approve"
|
|
target="_blank"
|
|
style="background:linear-gradient(135deg, #5cc66f 0%, #28a745 100%); padding:10px 18px; text-decoration:none; color:#ffffff; border-radius:6px; font-weight:700; font-size:13px; display:inline-block;">
|
|
✓ Approve
|
|
</a>
|
|
</td>
|
|
<td>
|
|
<a t-attf-href="{{ object.get_base_url() }}/fusion_helpdesk/engagement/{{ bt.x_fc_engagement_token }}/reject"
|
|
target="_blank"
|
|
style="background:linear-gradient(135deg, #e85d68 0%, #dc3545 100%); padding:10px 18px; text-decoration:none; color:#ffffff; border-radius:6px; font-weight:700; font-size:13px; display:inline-block;">
|
|
✗ Reject
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</t>
|
|
|
|
<p style="color:#6c757d; font-size:12px; margin-top:24px;">
|
|
Each Approve / Reject link is single-use. Tap the
|
|
button on the card you want to decide on; the others
|
|
stay live in this email until you act on them or we
|
|
send a fresh request.
|
|
</p>
|
|
<p style="color:#6c757d; font-size:12px;">— Nexa Systems Support</p>
|
|
</div>
|
|
</field>
|
|
</record>
|
|
|
|
</data>
|
|
</odoo>
|