Skip to content

[T3274] FIX: double-escaped QWeb entities crashing mail template rendering - #2133

Open
danpa32 wants to merge 1 commit into
18.0from
T3274-fix-onboarding-welcome-generation
Open

[T3274] FIX: double-escaped QWeb entities crashing mail template rendering#2133
danpa32 wants to merge 1 commit into
18.0from
T3274-fix-onboarding-welcome-generation

Conversation

@danpa32

@danpa32 danpa32 commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

T3274 — Fix onboarding welcome generation

There is another pull-request related to it as I work on 2 different module:
CompassionCH/compassion-switzerland#1792

Original report

Manual test procedure failed at step 11: the "Sponsorship
Onboarding Welcome" and "Sponsorship Onboarding Photo by Post" communications
were both never generated. A previous investigation found a QWeb compilation
error (double-escaped >) in the "Donation - Thank You Letter"
template, a stale noupdate view crashing on a removed _is_qr_iban()
method, and flagged ~80 other mail_template rows with the same
double-escape issue.

Root cause

Two independent bugs, plus one structural gap that turned the first into two
symptoms instead of one:

  1. report_compassion_qr_slip view stuck on stale v14 content. The view
    was reworked for v18 ,
    but its ir_model_data had noupdate=True — most likely set
    automatically by an in-place edit via the view editor at some point — so
    the ordinary module upgrade never reloaded it. This is what actually crashes:
    get_sponsorship_payment_slip_attachments() (used by the Welcome config)
    renders report_compassion.report_2bvr_sponsorship/
    report_single_bvr_sponsorship, which t-calls this view.

  2. _send_new_dossier() has no per-config error isolation.
    (partner_communication_switzerland/models/contracts.py) It loops over
    configs = new_dossier + child_picture (Welcome, then Photo-by-post) with
    a plain for loop. When Welcome's iteration raised (bug 7.0 add validation to cron #1), the loop
    aborted before ever reaching Photo-by-post's iteration. Confirmed via a
    throwaway migration script: calling get_photo_by_post_attachment() and
    rendering its report directly, in isolation, both succeed — Photo-by-post
    has no bug of its own, it's collateral damage from Welcome's crash.

  3. Double-escaped QWeb entities (> instead of >, same for
    </"/') in several mail_template rows, including a raw
    % if EXPR: pragma line (never converted to a real <t t-if>, same
    class of bug as T3315) in the Welcome template itself
    (mail_onboarding_sponsorship_confirmation, en_US/it_IT), plus a dead
    % set könnt = ... line in de_DE. Surveyed the whole DB: 76
    mail_template rows affected, 45 of which have no owning module at all
    (created directly via the UI) — a per-module migration could never reach
    those.

  4. fr/de/it translations of Python-sourced strings silently ignored.
    Found manually while testing the fixes above: the Welcome email's
    payment-slip sentence rendered in English on an otherwise-French
    communication. Root cause: Odoo 18 only loads a .po entry as a Python
    code translation if its comment block contains a #. odoo-python marker
    line (odoo/tools/translate.py's CodeTranslations). partner_ communication_switzerland's de.po/fr_CH.po/it.po still use the
    pre-v17 comment format (#, python-format, no #. odoo-python), carried
    over from the v14 migration and never regenerated — so every
    _()-translated string sourced from Python code in this module silently
    fell back to English for these three languages, regardless of the .po
    file actually having a correct translation. Verified this is not unique
    to this one phrase: 43/42/42 entries respectively in these three files
    use the old format; this old-format issue exists in 12 .po files across
    compassion-switzerland and 23 across compassion-modules — out of scope
    here (own ticket), only fixed for this module's fr/de/it files in this
    ticket.

What changed

2 repos:

compassion-switzerland

  • report_compassion: pre-migration clearing the
    stale noupdate flag on report_compassion_qr_slip so the existing
    (already-correct) tracked view reloads.

  • partner_communication_switzerland/models/contracts.py: _send_new_dossier
    now wraps each config's send in a savepoint + try/except, logs and
    continues on failure instead of aborting the rest.

  • partner_communication_switzerland: migration
    converting the raw pragma lines in the Welcome template's body_html
    (en_US, it_IT, de_DE).

  • partner_communication_switzerland/i18n/{de,fr_CH,it}.po: added the
    missing #. odoo-python marker to every Python-code-sourced entry
    (mechanical, comment-only change, no msgid/msgstr edits).

compassion-modules:

  • partner_communication: migration doing a
    purely mechanical unescape of &amp;gt;/&amp;lt;/&amp;quot;/&amp;apos;
    across every mail_template row regardless of owning module (placed here
    since it's a shared dependency guaranteed installed wherever any of these
    templates live).

Out of scope

SUB sponsorships: confirmed by design, zero automated communication is
sent when a sponsorship validates in sds_state == "sub" — staff sends the
"SUB Accept" letter manually. Unchanged since 2021. If the acceptance
criterion "correct communication for SUB" means this should become
automatic, that's a product decision, not a bug fix — not touched in this
ticket.

Also not touched: report_compassion_qr_parent and communication_style
(report_compassion) are independently noupdate=True in the DB despite
their files not being noupdate by design — same class of anomaly as bug
#1 above, but not on the crash path for these two onboarding communications.
Worth a follow-up ticket if they turn out to matter elsewhere.

How to test manually

  1. Upgrade all four modules (-u report_compassion,partner_communication_ switzerland,partner_communication,recurring_contract)
  2. Follow the original manual test procedure (new sponsorship → validate →
    pay first invoice → check communications).
  3. Confirm both "Sponsorship Onboarding - Welcome and payment information"
    and "Sponsorship Onboarding - Photo by post" jobs are created and reach
    "ready"/"done", with the payment slip PDF attached to Welcome and the
    Welcome email body free of visible %/code text.

…ering

Several mail_template rows have their ">"/"<"/'"'/"'" QWeb
comparison/string-literal operators double-escaped (e.g. "&amp;gt;"
instead of "&gt;"). Odoo 18's stricter QWeb compiler evaluates the
still-escaped "&amp;gt;" text as a Python operator and crashes -
found via the "Donation - Thank You Letter" template (T3315), but
confirmed present in 76 mail_template rows in compassion_18, 45 of
which have no owning module at all (created directly via the UI), so
a per-module migration could never reach them.

Placed in partner_communication since it's a shared dependency of
every affected module and guaranteed installed wherever any of these
templates live. Purely mechanical string unescaping, safe regardless
of which module (if any) owns the row.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant