Jinja as a templating engine was problematic in differents respect:
- introduce external dependency to Odoo (less controll)
- add another templating mechanism in the stack
- specific feature in qweb cannot be reused
- difficulty in rendering easily editable templates
- more knowledge required with no betterment
By replacing jinja with qweb we can now build tools to edit a qweb
that will work with the previously jinja encoded document
(essentially `mail.template` records).
There is a catch however. Some email fields (eg. email_to) used jinja
syntax for rendering dynamic variables (ie. ${object.something} and
${object.something_that_should_not_be_escaped | safe}).
We still want user to use dynamic variables for some char fields (eg.
subject, from, to, ...). We made a new rendering engine called
"inline_template" that will render an expression enclosed by `{{` and
`}}`.
To be able to edit the templates from the backend interface, a
plugin to the Odoo editor has been made for seamlessly edit the
document.
This qweb plugin includes:
- make dynamic variables (eg. `<t t-out="variable"/>`) not editable
(for preventing the user to shoot himself in the foot)
- group and hide related logical branching (ie. t-if, t-elif, and t-else)
in order to see only one at once
- a floating select input to switch visibility of a particular logical
branching
Task-27033
X-original-commit: odoo/odoo@68182baff4
Part-of: odoo/odoo#77377
228 lines
12 KiB
XML
228 lines
12 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
<data noupdate="1">
|
|
<record id="email_template_edi_sale" model="mail.template">
|
|
<field name="name">Sales Order: Send by email</field>
|
|
<field name="model_id" ref="sale.model_sale_order"/>
|
|
<field name="subject">{{ object.company_id.name }} {{ object.state in ('draft', 'sent') and (ctx.get('proforma') and 'Proforma' or 'Quotation') or 'Order' }} (Ref {{ object.name or 'n/a' }})</field>
|
|
<field name="email_from">{{ (object.user_id.email_formatted or user.email_formatted) }}</field>
|
|
<field name="partner_to">{{ object.partner_id.id }}</field>
|
|
<field name="body_html" type="html">
|
|
<div style="margin: 0px; padding: 0px;">
|
|
<p style="margin: 0px; padding: 0px; font-size: 13px;">
|
|
<t t-set="doc_name" t-value="'quotation' if object.state in ('draft', 'sent') else 'order'"/>
|
|
Hello,
|
|
<br/><br/>
|
|
Your
|
|
<t t-if="ctx.get('proforma')">
|
|
Pro forma invoice for <t t-out="doc_name or ''">quotation</t> <strong t-out="object.name or ''">S00052</strong>
|
|
<t t-if="object.origin">
|
|
(with reference: <t t-out="object.origin or ''"></t> )
|
|
</t>
|
|
amounting in <strong t-out="format_amount(object.amount_total, object.pricelist_id.currency_id) or ''">$ 10.00</strong> is available.
|
|
</t>
|
|
<t t-else="">
|
|
<t t-out="doc_name or ''">quotation</t> <strong t-out="object.name or ''"></strong>
|
|
<t t-if="object.origin">
|
|
(with reference: <t t-out="object.origin or ''">S00052</t> )
|
|
</t>
|
|
amounting in <strong t-out="format_amount(object.amount_total, object.pricelist_id.currency_id) or ''">$ 10.00</strong> is ready for review.
|
|
</t>
|
|
<br/><br/>
|
|
Do not hesitate to contact us if you have any questions.
|
|
<br/>
|
|
</p>
|
|
</div>
|
|
</field>
|
|
<field name="report_template" ref="action_report_saleorder"/>
|
|
<field name="report_name">{{ (object.name or '').replace('/','_') }}</field>
|
|
<field name="lang">{{ object.partner_id.lang }}</field>
|
|
<field name="auto_delete" eval="True"/>
|
|
</record>
|
|
|
|
<record id="mail_template_sale_confirmation" model="mail.template">
|
|
<field name="name">Sales Order: Confirmation Email</field>
|
|
<field name="model_id" ref="sale.model_sale_order"/>
|
|
<field name="subject">{{ object.company_id.name }} {{ (object.get_portal_last_transaction().state == 'pending') and 'Pending Order' or 'Order' }} (Ref {{ object.name or 'n/a' }})</field>
|
|
<field name="email_from">{{ (object.user_id.email_formatted or user.email_formatted) }}</field>
|
|
<field name="partner_to">{{ object.partner_id.id }}</field>
|
|
<field name="body_html" type="html">
|
|
<div style="margin: 0px; padding: 0px;">
|
|
<p style="margin: 0px; padding: 0px; font-size: 12px;">
|
|
Hello,
|
|
<br/><br/>
|
|
<t t-set="transaction" t-value="object.get_portal_last_transaction()"/>
|
|
Your order <strong t-out="object.name or ''">S00049</strong> amounting in <strong t-out="format_amount(object.amount_total, object.currency_id) or ''">$ 10.00</strong>
|
|
<t t-if="object.state == 'sale' or (transaction and transaction.state in ('done', 'authorized'))">
|
|
has been confirmed.<br/>
|
|
Thank you for your trust!
|
|
</t>
|
|
<t t-elif="transaction and transaction.state == 'pending'">
|
|
is pending. It will be confirmed when the payment is received.
|
|
<t t-if="object.reference">
|
|
Your payment reference is <strong t-out="object.reference or ''"></strong>.
|
|
</t>
|
|
</t>
|
|
<br/><br/>
|
|
Do not hesitate to contact us if you have any questions.
|
|
<br/><br/>
|
|
</p>
|
|
<t t-if="hasattr(object, 'website_id') and object.website_id">
|
|
<div style="margin: 0px; padding: 0px;">
|
|
<table width="100%" style="color: #454748; font-size: 12px; border-collapse: collapse;">
|
|
<tr style="border-bottom: 2px solid #dee2e6;">
|
|
<td style="width: 150px;"><strong>Products</strong></td>
|
|
<td></td>
|
|
<td width="15%" align="center"><strong>Quantity</strong></td>
|
|
<td width="20%" align="right"><strong>
|
|
<t t-if="object.user_id.has_group('account.group_show_line_subtotals_tax_excluded')">
|
|
VAT Excl.
|
|
</t>
|
|
<t t-else="">
|
|
VAT Incl.
|
|
</t>
|
|
</strong></td>
|
|
</tr>
|
|
</table>
|
|
<t t-foreach="object.order_line" t-as="line">
|
|
<t t-if="(not hasattr(line, 'is_delivery') or not line.is_delivery) and line.display_type in ['line_section', 'line_note']">
|
|
<table width="100%" style="color: #454748; font-size: 12px; border-collapse: collapse;">
|
|
<t t-set="loop_cycle_number" t-value="0" />
|
|
<tr t-att-style="'background-color: #f2f2f2' if loop_cycle_number % 2 == 0 else 'background-color: #ffffff'">
|
|
<t t-set="loop_cycle_number" t-value="loop_cycle_number + 1" />
|
|
<td colspan="4">
|
|
<t t-if="line.display_type == 'line_section'">
|
|
<strong t-out="line.name or ''">Taking care of Trees Course</strong>
|
|
</t>
|
|
<t t-elif="line.display_type == 'line_note'">
|
|
<i t-out="line.name or ''">Taking care of Trees Course</i>
|
|
</t>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</t>
|
|
<t t-elif="(not hasattr(line, 'is_delivery') or not line.is_delivery)">
|
|
<table width="100%" style="color: #454748; font-size: 12px; border-collapse: collapse;">
|
|
<t t-set="loop_cycle_number" t-value="0" />
|
|
<tr t-att-style="'background-color: #f2f2f2' if loop_cycle_number % 2 == 0 else 'background-color: #ffffff'">
|
|
<t t-set="loop_cycle_number" t-value="loop_cycle_number + 1" />
|
|
<td style="width: 150px;">
|
|
<img t-attf-src="/web/image/product.product/{{ line.product_id.id }}/image_128" style="width: 64px; height: 64px; object-fit: contain;" alt="Product image"></img>
|
|
</td>
|
|
<td align="left" t-out="line.product_id.name or ''"> Taking care of Trees Course</td>
|
|
<td width="15%" align="center" t-out="line.product_uom_qty or ''">1</td>
|
|
<td width="20%" align="right"><strong>
|
|
<t t-if="object.user_id.has_group('account.group_show_line_subtotals_tax_excluded')">
|
|
<t t-out="format_amount(line.price_reduce_taxexcl, object.currency_id) or ''">$ 10.00</t>
|
|
</t>
|
|
<t t-else="">
|
|
<t t-out="format_amount(line.price_reduce_taxinc, object.currency_id) or ''">$ 10.00</t>
|
|
</t>
|
|
</strong></td>
|
|
</tr>
|
|
</table>
|
|
</t>
|
|
</t>
|
|
</div>
|
|
<div style="margin: 0px; padding: 0px;" t-if="hasattr(object, 'carrier_id') and object.carrier_id">
|
|
<table width="100%" style="color: #454748; font-size: 12px; border-spacing: 0px 4px;" align="right">
|
|
<tr>
|
|
<td style="width: 60%"/>
|
|
<td style="width: 30%; border-top: 1px solid #dee2e6;" align="right"><strong>Delivery:</strong></td>
|
|
<td style="width: 10%; border-top: 1px solid #dee2e6;" align="right" t-out="format_amount(object.amount_delivery, object.currency_id) or ''">$ 0.00</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="width: 60%"/>
|
|
<td style="width: 30%;" align="right"><strong>SubTotal:</strong></td>
|
|
<td style="width: 10%;" align="right" t-out="format_amount(object.amount_untaxed, object.currency_id) or ''">$ 10.00</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div style="margin: 0px; padding: 0px;" t-else="">
|
|
<table width="100%" style="color: #454748; font-size: 12px; border-spacing: 0px 4px;" align="right">
|
|
<tr>
|
|
<td style="width: 60%"/>
|
|
<td style="width: 30%; border-top: 1px solid #dee2e6;" align="right"><strong>SubTotal:</strong></td>
|
|
<td style="width: 10%; border-top: 1px solid #dee2e6;" align="right" t-out="format_amount(object.amount_untaxed, object.currency_id) or ''">$ 10.00</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div style="margin: 0px; padding: 0px;">
|
|
<table width="100%" style="color: #454748; font-size: 12px; border-spacing: 0px 4px;" align="right">
|
|
<tr>
|
|
<td style="width: 60%"/>
|
|
<td style="width: 30%;" align="right"><strong>Taxes:</strong></td>
|
|
<td style="width: 10%;" align="right" t-out="format_amount(object.amount_tax, object.currency_id) or ''">$ 0.00</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="width: 60%"/>
|
|
<td style="width: 30%; border-top: 1px solid #dee2e6;" align="right"><strong>Total:</strong></td>
|
|
<td style="width: 10%; border-top: 1px solid #dee2e6;" align="right" t-out="format_amount(object.amount_total, object.currency_id) or ''">$ 10.00</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div t-if="object.partner_invoice_id" style="margin: 0px; padding: 0px;">
|
|
<table width="100%" style="color: #454748; font-size: 12px;">
|
|
<tr>
|
|
<td style="padding-top: 10px;">
|
|
<strong>Bill to:</strong>
|
|
<t t-out="object.partner_invoice_id.street or ''">1201 S Figueroa St</t>
|
|
<t t-out="object.partner_invoice_id.city or ''">Los Angeles</t>
|
|
<t t-out="object.partner_invoice_id.state_id.name or ''">California</t>
|
|
<t t-out="object.partner_invoice_id.zip or ''">90015</t>
|
|
<t t-out="object.partner_invoice_id.country_id.name or ''">United States</t>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>
|
|
<strong>Payment Method:</strong>
|
|
<t t-if="transaction.token_id">
|
|
<t t-out="transaction.token_id.name or ''"></t>
|
|
</t>
|
|
<t t-else="">
|
|
<t t-out="transaction.acquirer_id.sudo().name or ''"></t>
|
|
</t>
|
|
(<t t-out="format_amount(transaction.amount, object.currency_id) or ''">$ 10.00</t>)
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div t-if="object.partner_shipping_id and not object.only_services" style="margin: 0px; padding: 0px;">
|
|
<table width="100%" style="color: #454748; font-size: 12px;">
|
|
<tr>
|
|
<td>
|
|
<br/>
|
|
<strong>Ship to:</strong>
|
|
<t t-out="object.partner_shipping_id.street or ''">1201 S Figueroa St</t>
|
|
<t t-out="object.partner_shipping_id.city or ''">Los Angeles</t>
|
|
<t t-out="object.partner_shipping_id.state_id.name or ''">California</t>
|
|
<t t-out="object.partner_shipping_id.zip or ''">90015</t>
|
|
<t t-out="object.partner_shipping_id.country_id.name or ''">United States</t>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<table t-if="hasattr(object, 'carrier_id') and object.carrier_id" width="100%" style="color: #454748; font-size: 12px;">
|
|
<tr>
|
|
<td>
|
|
<strong>Shipping Method:</strong>
|
|
<t t-out="object.carrier_id.name or ''"></t>
|
|
<t t-if="object.carrier_id.fixed_price == 0.0">
|
|
(Free)
|
|
</t>
|
|
<t t-else="">
|
|
(<t t-out="format_amount(object.carrier_id.fixed_price, object.currency_id) or ''">$ 10.00</t>)
|
|
</t>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</t>
|
|
</div></field>
|
|
<field name="report_template" ref="action_report_saleorder"/>
|
|
<field name="report_name">{{ (object.name or '').replace('/','_') }}</field>
|
|
<field name="lang">{{ object.partner_id.lang }}</field>
|
|
<field name="auto_delete" eval="True"/>
|
|
</record>
|
|
</data>
|
|
</odoo>
|