Hello everyone, is there any Odoo developer here?
I’m facing an issue on Odoo 15 (Website Sale) related to automatic email sending after order confirmation.
This worked correctly before, but the issue appeared after introducing multiple email templates, one per rule.
Functional overview (minimal)
Sale order is confirmed from the website
After confirmation:
One standard order email is sent
Additional emails are sent depending on product rules
Each rule uses a different mail.template
Each email should display only the order lines related to that rule
Controller used on order confirmation
@http.route(['/shop/confirmation'], type='http', auth="public", website=True, sitemap=False)ute(['/shop/confirmation'], type='http', auth="public", website=True, sitemap=False)
def shop_payment_confirmation(self, **post):
""" Automatically confirm an order from website """
if 'valid_rules' in post and not bool(int(post['valid_rules'])):
return
purchase_capability, msg = request.env.user.partner_id.check_purchase_capability(
request.website.company_id
)
if msg:
return
sale_order_id = request.session.get('sale_last_order_id') or 0
order = request.env['sale.order'].sudo().browse(sale_order_id)
if order.exists():
if order.state not in ('draft', 'sent'):
return request.redirect('/shop/cart')
for line in order.order_line.filtered('product_packaging_id'):
max_qty = line.product_packaging_id.virtual_available_qty
if max_qty <= 0:
return request.redirect('/shop/confirm_order')
order.action_confirm()
order.action_create_activity()
request.website.sale_reset()
res = super(WebsiteSale, self).shop_payment_confirmation(**post)
# send mail if there is at least one product for distribution
so_line_with_distribution_id = order.order_line.filtered(
lambda r: r.product_id.product_tmpl_id.is_for_distribution
)
if so_line_with_distribution_id:
product_tmpl_ids = so_line_with_distribution_id.mapped('product_id').mapped('product_tmpl_id')
order._send_distribution_mail(product_tmpl_ids)
return res
Mail sending logic
def get_coupon_domain(self):
return [('promo_code_usage', '=', 'distribution')]
def _send_distribution_mail(self, product_tmpl_ids):
self.ensure_one()
coupon_program_ids = self.code_promo_program_id.search(self.get_coupon_domain())
email_values = list()
used_coupon_ids = self.env['coupon.program']
for product_tmpl_id in product_tmpl_ids:
used_coupon_ids |= coupon_program_ids.get_the_right_one(product_tmpl_id)
for coupon_program_id in used_coupon_ids:
email_values.append(self._get_mail_values(coupon_program_id))
mail_ids = self.env['mail.mail'].sudo().create(email_values)
mail_ids.send(raise_exception=False)
Mail values generation
def _get_mail_values(self, coupon_program_id):
template_id = (
coupon_program_id.email_template_id
or self.env.ref(
'sol_don_website.mail_template_distribution_tracking',
raise_if_not_found=True
)
)
email_values = {
'email_to': self.partner_id.email_formatted,
'email_from': self.company_id.email_formatted,
'author_id': self.env.user.partner_id.id,
'subject': _('Distribution condition %s') % (self.name,),
'body_html': template_id._render_field(
'body_html',
[self.id],
compute_lang=True,
post_process=True
)[self.id],
'recipient_ids': self.message_follower_ids.mapped('partner_id')
+ self.partner_invoice_id
}
return email_values
Coupon program model
class CouponProgram(models.Model):
_inherit = "coupon.program"
promo_code_usage = fields.Selection(
selection_add=[('distribution', 'Distribution condition')]
)
distribution_msg = fields.Text('Distribution condition body')
email_template_id = fields.Many2one(
'mail.template',
'Mail template',
domain=[('model_id', '=', 'sale.order')]
)
def get_the_right_one(self, product_tmpl_ids):
product_ids = product_tmpl_ids.mapped('id')
for program in self:
domain = ast.literal_eval(
program.rule_products_domain
) if program.rule_products_domain else []
if any(
i['id'] in product_ids
for i in product_tmpl_ids.search_read(domain, ['id'])
if i
):
return program
return self - self
** Extract of the Mail template**
<t t-foreach="
object.order_line.filtered(
lambda r: r.product_id.product_tmpl_id.is_for_distribution
)
" t-as="so_line_id">
<tr>
<td>
<span t-field="so_line_id.product_id.default_code"/>
</td>
<td>
<span t-field="so_line_id.name"/>
</td>
<td>
<span t-field="so_line_id.price_subtotal"/>
</td>
</tr>
</t>
Observed issue
When:
A sale order contains products matching multiple coupon programs
Each coupon program has its own mail template
Multiple emails are generated during the same confirmation
Then:
All emails are sent successfully
-
But the rendered order lines are incorrect:
- Only one order line is displayed
- Usually the last added line
- Lines appear in templates where they should not belong
There are:
No errors
No tracebacks
_get_mail_values() is called correctly
_render_field() returns HTML
But the final email content is wrong
Question
Is this a known behavior or limitation in Odoo 15 mail.template rendering when:
Sending multiple emails
Same model (sale.order)
Same res_id
Different templates
Same HTTP request / transaction
What is the recommended approach to isolate data per email in this case?
Thanks in advance for any insight. You can also see this post in the Odoo forum here: Odoo 15 – Multiple mails sent on order confirmation but wrong order lines rendered in templates. Unfortunately the odoo forum is unavailable but you can still view it when you are logged in
Top comments (0)