[MERGE][IMP] (website_)sale: send and improve emails when payment is processed from portal or ecommerce
Purpose of this merge is to improve emails sent when confirming sale orders. A new template is added that contains lines with image for bought product to be used in eCommerce. See sub commits and task for more details. Related to task ID 1873634 closes odoo/odoo#33283 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
@@ -262,13 +262,15 @@
|
||||
<t t-esc="access_name"/>
|
||||
</a>
|
||||
</div>
|
||||
<div style="margin: 0px; padding: 0px; font-size:13px;">
|
||||
Best regards,
|
||||
</div>
|
||||
<div>&nbsp;</div>
|
||||
<div t-if="record.user_id and record.user_id.sudo().signature" style="font-size: 13px;">
|
||||
<div t-raw="record.user_id.sudo().signature"/>
|
||||
</div>
|
||||
<t t-if="record.user_id and not record.env.user._is_superuser()">
|
||||
<div style="margin: 0px; padding: 0px; font-size:13px;">
|
||||
Best regards,
|
||||
</div>
|
||||
<div>&nbsp;</div>
|
||||
<div t-if="record.user_id.sudo().signature" style="font-size: 13px;">
|
||||
<div t-raw="record.user_id.sudo().signature"/>
|
||||
</div>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- FOOTER -->
|
||||
|
||||
@@ -19,8 +19,8 @@ This module contains all the common features of Sales Management and eCommerce.
|
||||
'report/invoice_report_templates.xml',
|
||||
'report/report_all_channels_sales_views.xml',
|
||||
'data/ir_sequence_data.xml',
|
||||
'data/sale_data.xml',
|
||||
'data/mail_data.xml',
|
||||
'data/sale_data.xml',
|
||||
'wizard/sale_make_invoice_advance_views.xml',
|
||||
'views/sale_views.xml',
|
||||
'views/sales_team_views.xml',
|
||||
|
||||
@@ -220,6 +220,7 @@ class CustomerPortal(CustomerPortal):
|
||||
|
||||
if not order_sudo.has_to_be_paid():
|
||||
order_sudo.action_confirm()
|
||||
order_sudo._send_order_confirmation_mail()
|
||||
|
||||
pdf = request.env.ref('sale.action_report_saleorder').sudo().render_qweb_pdf([order_sudo.id])[0]
|
||||
|
||||
|
||||
+167
-19
@@ -60,11 +60,14 @@
|
||||
<xpath expr="//t[@t-set='access_name']" position="after">
|
||||
<t t-if="record._name == 'sale.order'">
|
||||
<t t-if="record.has_to_be_signed(include_draft=True)">
|
||||
<t t-if="record.has_to_be_paid()" t-set="access_name">Sign and pay online</t>
|
||||
<t t-else="" t-set="access_name">Accept and sign online</t>
|
||||
<t t-if="record.has_to_be_paid()" t-set="access_name">Sign & Pay Quotation</t>
|
||||
<t t-else="" t-set="access_name">Accept & Sign Quotation</t>
|
||||
</t>
|
||||
<t t-elif="record.has_to_be_paid(include_draft=True)">
|
||||
<t t-set="access_name">Pay online</t>
|
||||
<t t-set="access_name">Accept & Pay Quotation</t>
|
||||
</t>
|
||||
<t t-elif="record.state in ('draft', 'sent')">
|
||||
<t t-set="access_name">View Quotation</t>
|
||||
</t>
|
||||
</t>
|
||||
</xpath>
|
||||
@@ -80,25 +83,170 @@
|
||||
<div style="margin: 0px; padding: 0px;">
|
||||
<p style="margin: 0px; padding: 0px; font-size: 13px;">
|
||||
% set doc_name = 'quotation' if object.state in ('draft', 'sent') else 'order'
|
||||
% if object.partner_id.parent_id:
|
||||
Dear ${object.partner_id.name} (${object.partner_id.parent_id.name}),
|
||||
Hello,
|
||||
<br/><br/>
|
||||
Your
|
||||
% if ctx.get('proforma'):
|
||||
Pro forma invoice for ${doc_name} <strong>${object.name}</strong>
|
||||
% if object.origin:
|
||||
(with reference: ${object.origin} )
|
||||
% endif
|
||||
amounting in <strong>${format_amount(object.amount_total, object.pricelist_id.currency_id)}</strong> is available.
|
||||
% else:
|
||||
Dear ${object.partner_id.name},
|
||||
${doc_name} <strong>${object.name}</strong>
|
||||
% if object.origin:
|
||||
(with reference: ${object.origin} )
|
||||
% endif
|
||||
amounting in <strong>${format_amount(object.amount_total, object.pricelist_id.currency_id)}</strong> is ready for review.
|
||||
% endif
|
||||
<br /><br />
|
||||
Here is
|
||||
% if ctx.get('proforma')
|
||||
in attachment your pro-forma invoice
|
||||
% else
|
||||
the ${doc_name} <strong>${object.name}</strong>
|
||||
% endif
|
||||
% if object.origin:
|
||||
(with reference: ${object.origin} )
|
||||
% endif
|
||||
amounting in <strong>${format_amount(object.amount_total, object.pricelist_id.currency_id)}</strong>
|
||||
from ${object.company_id.name}.
|
||||
<br /><br />
|
||||
<br/><br/>
|
||||
Do not hesitate to contact us if you have any question.
|
||||
<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="user_signature" eval="False"/>
|
||||
<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) | safe}</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/>
|
||||
% set transaction = object.get_portal_last_transaction()
|
||||
Your order <strong>${object.name}</strong> amounting in <strong>${format_amount(object.amount_total, object.currency_id)}</strong>
|
||||
% if object.state == 'sale' or (transaction and transaction.state in ('done', 'authorized')) :
|
||||
has been confirmed.<br/>
|
||||
Thank you for your trust!
|
||||
% elif transaction and transaction.state == 'pending' :
|
||||
is pending. It will be confirmed when the payment is received.
|
||||
% if object.reference:
|
||||
Your payment reference is <strong>${object.reference}</strong>.
|
||||
% endif
|
||||
% endif
|
||||
<br/><br/>
|
||||
Do not hesitate to contact us if you have any question.
|
||||
<br/><br/>
|
||||
% if object.website_id:
|
||||
<table width="100%" style="color: #454748; font-size: 12px; border-collapse: collapse;">
|
||||
<tr style="border-bottom: 2px solid #dee2e6;">
|
||||
<td width="18%"><strong>Products</strong></td>
|
||||
<td></td>
|
||||
<td><strong>Quantity</strong></td>
|
||||
<td width="10%" align="center"><strong>Price</strong></td>
|
||||
</tr>
|
||||
% for line in object.order_line:
|
||||
% if not line.is_delivery:
|
||||
<tr style="${loop.cycle('background-color: #f2f2f2', 'background-color: #ffffff')}">
|
||||
% if line.display_type == 'line_section':
|
||||
<td colspan="4"><strong>${line.name}</strong></td>
|
||||
% elif line.display_type == 'line_note':
|
||||
<td colspan="4"><i>${line.name}</i></td>
|
||||
% else:
|
||||
<td style="width: 150px;">
|
||||
<img src="/web/image/product.product/${line.product_id.id}/image_small" width="64" alt="Product image"></img>
|
||||
</td>
|
||||
<td align="left">${line.product_id.name}</td>
|
||||
<td>${line.product_uom_qty}</td>
|
||||
% if object.user_id.has_group('account.group_show_line_subtotals_tax_excluded'):
|
||||
<td align="right">${format_amount(line.price_reduce_taxexcl, object.currency_id)}</td>
|
||||
% endif
|
||||
% if object.user_id.has_group('account.group_show_line_subtotals_tax_included'):
|
||||
<td align="right">${format_amount(line.price_reduce_taxinc, object.currency_id)}</td>
|
||||
% endif
|
||||
% endif
|
||||
</tr>
|
||||
% endif
|
||||
% endfor
|
||||
</table>
|
||||
<table width="40%" style="color: #454748; font-size: 12px; border-spacing: 0px 4px;" align="right">
|
||||
% if object.carrier_id:
|
||||
<tr>
|
||||
<td style="border-top: 1px solid #dee2e6;" align="right"><strong>Delivery:</strong></td>
|
||||
<td style="border-top: 1px solid #dee2e6;" align="right">${format_amount(object.amount_delivery, object.currency_id)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="30%" align="right"><strong>SubTotal:</strong></td>
|
||||
<td align="right">${format_amount(object.amount_untaxed, object.currency_id)}</td>
|
||||
</tr>
|
||||
% else:
|
||||
<tr>
|
||||
<td style="border-top: 1px solid #dee2e6;" width="30%" align="right"><strong>SubTotal:</strong></td>
|
||||
<td style="border-top: 1px solid #dee2e6;" align="right">${format_amount(object.amount_untaxed, object.currency_id)}</td>
|
||||
</tr>
|
||||
% endif
|
||||
<tr>
|
||||
<td align="right"><strong>Taxes:</strong></td>
|
||||
<td align="right">${format_amount(object.amount_tax, object.currency_id)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border-top: 1px solid #dee2e6;" align="right"><strong>Total:</strong></td>
|
||||
<td style="border-top: 1px solid #dee2e6;" align="right">${format_amount(object.amount_total, object.currency_id)}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<table width="100%" style="color: #454748; font-size: 12px;">
|
||||
% if object.partner_invoice_id:
|
||||
<tr>
|
||||
<td style="padding-top: 10px;">
|
||||
<strong>Bill to:</strong>
|
||||
${object.partner_invoice_id.street or ''}
|
||||
${object.partner_invoice_id.city or ''}
|
||||
${object.partner_invoice_id.state_id.name or ''}
|
||||
${object.partner_invoice_id.zip or ''}
|
||||
${object.partner_invoice_id.country_id.name or ''}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Payment Method:</strong>
|
||||
% if transaction.payment_token_id:
|
||||
${transaction.payment_token_id.name}
|
||||
% else:
|
||||
${transaction.acquirer_id.name}
|
||||
% endif
|
||||
(${format_amount(transaction.amount, object.currency_id)})
|
||||
</td>
|
||||
</tr>
|
||||
% endif
|
||||
% if object.partner_shipping_id and not object.only_services:
|
||||
<tr>
|
||||
<td>
|
||||
<br/>
|
||||
<strong>Ship to:</strong>
|
||||
${object.partner_shipping_id.street or ''}
|
||||
${object.partner_shipping_id.city or ''}
|
||||
${object.partner_shipping_id.state_id.name or ''}
|
||||
${object.partner_shipping_id.zip or ''}
|
||||
${object.partner_shipping_id.country_id.name or ''}
|
||||
</td>
|
||||
</tr>
|
||||
% if object.carrier_id:
|
||||
<tr>
|
||||
<td>
|
||||
<strong>Shipping Method:</strong>
|
||||
${object.carrier_id.name}
|
||||
% if object.carrier_id.fixed_price == 0.0:
|
||||
(Free)
|
||||
% else:
|
||||
(${format_amount(object.carrier_id.fixed_price, object.currency_id)})
|
||||
% endif
|
||||
</td>
|
||||
</tr>
|
||||
% endif
|
||||
% endif
|
||||
</table>
|
||||
% endif
|
||||
</p>
|
||||
</div>
|
||||
</field>
|
||||
|
||||
@@ -9,5 +9,11 @@
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = records.action_share()</field>
|
||||
</record>
|
||||
|
||||
<!-- set default order confirmation template -->
|
||||
<record id="default_confirmation_template" model="ir.config_parameter">
|
||||
<field name="key">sale.default_confirmation_template</field>
|
||||
<field name="value" ref="sale.mail_template_sale_confirmation"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -61,25 +61,28 @@ class PaymentTransaction(models.Model):
|
||||
super(PaymentTransaction, self)._set_transaction_pending()
|
||||
|
||||
for record in self:
|
||||
sales_orders = record.sale_order_ids.filtered(lambda so: so.state == 'draft')
|
||||
sales_orders.force_quotation_send()
|
||||
sales_orders = record.sale_order_ids.filtered(lambda so: so.state in ['draft', 'sent'])
|
||||
sales_orders.filtered(lambda so: so.state == 'draft').with_context(tracking_disable=True).write({'state': 'sent'})
|
||||
|
||||
if record.acquirer_id.provider == 'transfer':
|
||||
for so in record.sale_order_ids:
|
||||
so.reference = record._compute_sale_order_reference(so)
|
||||
# send order confirmation mail
|
||||
sales_orders._send_order_confirmation_mail()
|
||||
|
||||
@api.multi
|
||||
def _set_transaction_authorized(self):
|
||||
# Override of '_set_transaction_authorized' in the 'payment' module
|
||||
# to confirm the quotations automatically.
|
||||
super(PaymentTransaction, self)._set_transaction_authorized()
|
||||
sales_orders = self.mapped('sale_order_ids').filtered(lambda so: so.state == 'draft')
|
||||
sales_orders.force_quotation_send()
|
||||
sales_orders = self.mapped('sale_order_ids').filtered(lambda so: so.state == 'sent')
|
||||
sales_orders = self.mapped('sale_order_ids').filtered(lambda so: so.state in ['draft', 'sent'])
|
||||
for so in sales_orders:
|
||||
# For loop because some override of action_confirm are ensure_one.
|
||||
so.action_confirm()
|
||||
|
||||
# send order confirmation mail
|
||||
sales_orders._send_order_confirmation_mail()
|
||||
|
||||
@api.multi
|
||||
def _reconcile_after_transaction_done(self):
|
||||
# Override of '_set_transaction_done' in the 'payment' module
|
||||
@@ -87,7 +90,9 @@ class PaymentTransaction(models.Model):
|
||||
sales_orders = self.mapped('sale_order_ids').filtered(lambda so: so.state in ('draft', 'sent'))
|
||||
for so in sales_orders:
|
||||
# For loop because some override of action_confirm are ensure_one.
|
||||
so.with_context(send_email=True).action_confirm()
|
||||
so.action_confirm()
|
||||
# send order confirmation mail
|
||||
sales_orders._send_order_confirmation_mail()
|
||||
# invoice the sale orders if needed
|
||||
self._invoice_sale_orders()
|
||||
res = super(PaymentTransaction, self)._reconcile_after_transaction_done()
|
||||
|
||||
@@ -71,6 +71,10 @@ class ResConfigSettings(models.TransientModel):
|
||||
domain="[('model', '=', 'account.invoice')]",
|
||||
config_parameter='sale.default_email_template',
|
||||
default=lambda self: self.env.ref('account.email_template_edi_invoice', False))
|
||||
confirmation_template_id = fields.Many2one('mail.template', string='Confirmation Email',
|
||||
domain="[('model', '=', 'sale.order')]",
|
||||
config_parameter='sale.default_confirmation_template',
|
||||
help="Email sent to the customer once the order is paid.")
|
||||
|
||||
def set_values(self):
|
||||
super(ResConfigSettings, self).set_values()
|
||||
|
||||
+22
-25
@@ -600,21 +600,24 @@ class SaleOrder(models.Model):
|
||||
def action_cancel(self):
|
||||
return self.write({'state': 'cancel'})
|
||||
|
||||
def _find_mail_template(self, force_confirmation_template=False):
|
||||
template_id = False
|
||||
|
||||
if force_confirmation_template or (self.state == 'sale' and not self.env.context.get('proforma', False)):
|
||||
template_id = int(self.env['ir.config_parameter'].sudo().get_param('sale.default_confirmation_template'))
|
||||
template_id = self.env['mail.template'].search([('id', '=', template_id)]).id
|
||||
if not template_id:
|
||||
template_id = self.env['ir.model.data'].xmlid_to_res_id('sale.mail_template_sale_confirmation', raise_if_not_found=False)
|
||||
if not template_id:
|
||||
template_id = self.env['ir.model.data'].xmlid_to_res_id('sale.email_template_edi_sale', raise_if_not_found=False)
|
||||
|
||||
return template_id
|
||||
|
||||
@api.multi
|
||||
def action_quotation_send(self):
|
||||
'''
|
||||
This function opens a window to compose an email, with the edi sale template message loaded by default
|
||||
'''
|
||||
''' Opens a wizard to compose an email, with relevant mail template loaded by default '''
|
||||
self.ensure_one()
|
||||
ir_model_data = self.env['ir.model.data']
|
||||
try:
|
||||
template_id = ir_model_data.get_object_reference('sale', 'email_template_edi_sale')[1]
|
||||
except ValueError:
|
||||
template_id = False
|
||||
try:
|
||||
compose_form_id = ir_model_data.get_object_reference('mail', 'email_compose_message_wizard_form')[1]
|
||||
except ValueError:
|
||||
compose_form_id = False
|
||||
template_id = self._find_mail_template()
|
||||
ctx = {
|
||||
'default_model': 'sale.order',
|
||||
'default_res_id': self.ids[0],
|
||||
@@ -632,8 +635,8 @@ class SaleOrder(models.Model):
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'mail.compose.message',
|
||||
'views': [(compose_form_id, 'form')],
|
||||
'view_id': compose_form_id,
|
||||
'views': [(False, 'form')],
|
||||
'view_id': False,
|
||||
'target': 'new',
|
||||
'context': ctx,
|
||||
}
|
||||
@@ -647,14 +650,11 @@ class SaleOrder(models.Model):
|
||||
return super(SaleOrder, self.with_context(mail_post_autofollow=True)).message_post(**kwargs)
|
||||
|
||||
@api.multi
|
||||
def force_quotation_send(self):
|
||||
for order in self:
|
||||
email_act = order.action_quotation_send()
|
||||
if email_act and email_act.get('context'):
|
||||
email_ctx = email_act['context']
|
||||
email_ctx.update(default_email_from=order.company_id.email)
|
||||
order.with_context(**email_ctx).message_post_with_template(email_ctx.get('default_template_id'))
|
||||
return True
|
||||
def _send_order_confirmation_mail(self):
|
||||
template_id = self._find_mail_template(force_confirmation_template=True)
|
||||
if template_id:
|
||||
for order in self:
|
||||
order.with_context(force_send=True).message_post_with_template(template_id, composition_mode='comment', notif_layout="mail.mail_notification_paynow")
|
||||
|
||||
@api.multi
|
||||
def action_done(self):
|
||||
@@ -674,9 +674,6 @@ class SaleOrder(models.Model):
|
||||
This method should be extended when the confirmation should generated
|
||||
other documents. In this method, the SO are in 'sale' state (not yet 'done').
|
||||
"""
|
||||
if self.env.context.get('send_email'):
|
||||
self.force_quotation_send()
|
||||
|
||||
# create an analytic account if at least an expense product
|
||||
for order in self:
|
||||
if any([expense_policy not in [False, 'no'] for expense_policy in order.order_line.mapped('product_id.expense_policy')]):
|
||||
|
||||
@@ -86,7 +86,9 @@ class TestSaleOrder(TestCommonSaleNoChart):
|
||||
self.sale_order.order_line._compute_product_updatable()
|
||||
self.assertTrue(self.sale_order.order_line[0].product_updatable)
|
||||
# send quotation
|
||||
self.sale_order.force_quotation_send()
|
||||
email_act = self.sale_order.action_quotation_send()
|
||||
email_ctx = email_act.get('context', {})
|
||||
self.sale_order.with_context(**email_ctx).message_post_with_template(email_ctx.get('default_template_id'))
|
||||
self.assertTrue(self.sale_order.state == 'sent', 'Sale: state after sending is wrong')
|
||||
self.sale_order.order_line._compute_product_updatable()
|
||||
self.assertTrue(self.sale_order.order_line[0].product_updatable)
|
||||
|
||||
@@ -22,6 +22,8 @@ class TestSaleSignature(odoo.tests.HttpCase):
|
||||
})
|
||||
|
||||
# must be sent to the user so he can see it
|
||||
sales_order.force_quotation_send()
|
||||
email_act = sales_order.action_quotation_send()
|
||||
email_ctx = email_act.get('context', {})
|
||||
sales_order.with_context(**email_ctx).message_post_with_template(email_ctx.get('default_template_id'))
|
||||
|
||||
self.start_tour("/", 'sale_signature', login="portal")
|
||||
|
||||
@@ -177,6 +177,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box" id="confirmation_email_setting" attrs="{'invisible': [('portal_confirmation_pay', '=', False) , ('portal_confirmation_sign', '=', False)]}">
|
||||
<div class="o_setting_right_pane">
|
||||
<span class="o_form_label">Confirmation Email</span>
|
||||
<div class="text-muted">
|
||||
Automatic email sent after the customer has signed or paid online
|
||||
</div>
|
||||
<div class="row mt16">
|
||||
<label for="confirmation_template_id" string="Email Template" class="col-lg-4 o_light_label"/>
|
||||
<field name="confirmation_template_id" class="oe_inline"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="group_sale_delivery_address"/>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="sale.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@id='sale_config_online_confirmation_pay']" position="after">
|
||||
<xpath expr="//div[@id='confirmation_email_setting']" position="after">
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="group_sale_order_template"/>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="mail_template_sale_cart_recovery" model="mail.template">
|
||||
<field name="name">Sale Order: Cart Recovery Email</field>
|
||||
<field name="name">Sales Order: Cart Recovery Email</field>
|
||||
<field name="model_id" ref="sale.model_sale_order"/>
|
||||
<field name="subject">You left items in your cart!</field>
|
||||
<field name="email_from">${(object.user_id.email_formatted or user.email_formatted or '') | safe}</field>
|
||||
|
||||
@@ -87,7 +87,7 @@ tour.register('shop_mail', {
|
||||
},
|
||||
{
|
||||
content: "wait mail to be sent, and go see it",
|
||||
trigger: '.o_thread_message_content:contains("Here is"):contains("the order")',
|
||||
trigger: '.o_thread_message_content:contains("Your"):contains("order")',
|
||||
run: function () {
|
||||
window.location.href = "/web#action=mail.action_view_mail_mail&view_type=list";
|
||||
},
|
||||
@@ -98,7 +98,7 @@ tour.register('shop_mail', {
|
||||
},
|
||||
{
|
||||
content: "check it's the correct email, and the URL is correct too",
|
||||
trigger: 'div.oe_form_field_html[name="body_html"] p:contains("Here is"):contains("the order")',
|
||||
trigger: 'div.oe_form_field_html[name="body_html"] p:contains("Your"):contains("order")',
|
||||
extra_trigger: 'div.oe_form_field_html[name="body_html"] a[href^="http://my-test-domain.com"]',
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -308,6 +308,18 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box" id="confirmation_email_setting">
|
||||
<div class="o_setting_right_pane">
|
||||
<span class="o_form_label">Confirmation Email</span>
|
||||
<div class="text-muted">
|
||||
Email sent to the customer after the checkout
|
||||
</div>
|
||||
<div class="row mt16">
|
||||
<label for="confirmation_template_id" string="Email Template" class="col-lg-4 o_light_label"/>
|
||||
<field name="confirmation_template_id" class="oe_inline"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-lg-6 o_setting_box" id="abandoned_carts_setting" title="Abandoned carts are all carts left unconfirmed by website visitors. You can find them in *Website > Orders > Abandoned Carts*. From there you can send recovery emails to visitors who entered their contact details.">
|
||||
<div class="o_setting_left_pane"/>
|
||||
<div class="o_setting_right_pane">
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ class _Cleaner(clean.Cleaner):
|
||||
'margin', 'margin-top', 'margin-left', 'margin-bottom', 'margin-right',
|
||||
'white-space',
|
||||
# box model
|
||||
'border', 'border-color', 'border-radius', 'border-style', 'border-width', 'border-top',
|
||||
'border', 'border-color', 'border-radius', 'border-style', 'border-width', 'border-top', 'border-bottom',
|
||||
'height', 'width', 'max-width', 'min-width', 'min-height',
|
||||
# tables
|
||||
'border-collapse', 'border-spacing', 'caption-side', 'empty-cells', 'table-layout']
|
||||
|
||||
Reference in New Issue
Block a user