[FIX] privacy_consent: Separate automated emails send process
Before https://github.com/OCA/data-protection/pull/29 there was a race condition where an email could be sent while the same transaction that created the `privacy.consent` record still wasn't committed, producing a 404 error if the user clicked on "Accept" or "Reject" before all mails were sent.
To avoid that, a raw `cr.commit()` was issued, but this produced another situation where the user had to wait until the full email queue is cleared to get his page loaded. It wasn't an error, but a long queue meant several minutes waiting, and it's ulikely that an average human is so patient.
So, here's the final fix (I hope!). The main problem was that I was looking in the wrong place to send the email. It turns out that the `self.post_message_with_template()` method is absolutely helpless in the case at hand, where these criteria must be met:
* E-mail must be enqueued, no matter if there are less or more than 50 consents to send.
* The template must be processed per record.
* In an ideal world, a `cr.commit()` must be issued after each sent mail.
The metod that was being used:
* Didn't allow to use `auto_commit` mode.
* Only allowed to render the template per record if called with `composition_mode="mass_mail"`.
* Only allowed to enqueue emails if called with `composition_mode="mass_post"`.
Obviously, I cannot set 2 different values for `composition_mode`, so a different strategy had to be used.
I discovered that the `mail.template` model has a helpful method called `send_mail()` that, by default:
* Renders the template per record
* Enqueues the email
* The email queue is cleared in `auto_commit=True` mode.
So, from now on, problems are gone:
* The user click, or the cron run, will just generate the missing `privacy.consent` records and enqueue mails for them.
* The mail queue manager will send them later, in `auto_commit` mode.
* After sending the e-mail, this module will set the `privacy.consent` record as `sent`.
* Thanks to *not* sending the email, the process the user faces when he hits the "generate" button is faster.
* Instructions in the README and text in the "generate" button are updated to reflect this new behavior.
* Thanks to the `auto_commit` feature, if Odoo is rebooted in the middle of a mail queue clearance, the records that were sent remain properly marked as sent, and the missing mails will be sent after the next boot.
* No hardcoded commits.
* No locked transactions.
* BTW I discovered that 2 different emails were created when creating a new consent. I started using `mail_create_nolog=True` to avoid that problem and only log a single creation message.
Note to self: never use again `post_message_with_template()`.
6 years ago |
|
<?xml version="1.0" encoding="utf-8"?> <!-- Copyright 2018 Tecnativa - Jairo Llopis
Copyright 2019 Tecnativa - Cristina Martin R. License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<data>
<!-- Mail templates --> <record id="template_consent" model="mail.template"> <field name="auto_delete" eval="False"/> <field name="name">Personal data processing consent request</field> <field name="subject">Data processing consent request for ${object.activity_id.display_name|safe}</field> <field name="model_id" ref="model_privacy_consent"/> <field name="use_default_to" eval="True"/> <field name="lang">${object.partner_id.lang}</field> <field name="body_html" type="xml"> <div style="background:#F3F5F6;color:#515166;padding:25px 0px;font-family:Arial,Helvetica,sans-serif;font-size:14px;"> <table style="width:600px;margin:5px auto;"> <tbody> <tr> <td> <a href="/"> <img src="/logo" alt="${object.activity_id.controller_id.display_name|safe}" style="vertical-align:baseline;max-width:100px;"/> </a> </td> </tr> </tbody> </table> <table style="width:600px;margin:0px auto;background:white;border:1px solid #e1e1e1;"> <tbody> <tr> <td colspan="2" style="padding:15px 20px 0px 20px; font-size:16px;"> <p> Hello, ${object.partner_id.name|safe} </p> <p> We contacted you to ask you to give us your explicit consent to include your data in a data processing activity called <b>${object.activity_id.display_name|safe}</b>, property of <i>${object.activity_id.controller_id.display_name|safe}</i> </p> ${object.description or ""} <p> % if object.state == "answered": The last time you answered, you % elif object.state == "sent": If you do nothing, we will assume you have % endif
% if object.accepted: <b>accepted</b> % else: <b>rejected</b> % endif such data processing. </p> <p> You can update your preferences below: </p> </td> </tr> <tr> <td style="padding:15px 20px 0px 20px; font-size:16px; text-align:right;"> <a href="/privacy/consent/accept/" style="background-color: #449d44; padding: 12px; font-weight: 12px; text-decoration: none; color: #fff; border-radius: 5px; font-size:16px;"> Accept </a> </td> <td style="padding:15px 20px 0px 20px; font-size:16px; text-align:left;"> <a href="/privacy/consent/reject/" style="background-color: #d9534f; padding: 12px; font-weight: 12px; text-decoration: none; color: #fff; border-radius: 5px; font-size:16px;"> Reject </a> </td> </tr> <tr> <td colspan="2" style="padding:15px 20px 15px 20px; font-size:16px;"> <p> If you need further information, please respond to this email and we will attend your request as soon as possible. </p> <p> Thank you! </p> </td> </tr> </tbody> </table> <table style="width:600px;margin:0px auto;text-align:center;"> <tbody> <tr> <td style="padding-top:10px;font-size: 12px;"> <p> Sent by <a href="/" style="color:#717188;">${object.activity_id.controller_id.display_name|safe}</a>. </p> </td> </tr> </tbody> </table> </div> </field> </record>
<!-- Mail subtypes --> <record id="mt_consent_consent_new" model="mail.message.subtype"> <field name="name">New Consent</field> <field name="description">Privacy consent request created</field> <field name="res_model">privacy.consent</field> <field name="default" eval="False"/> <field name="hidden" eval="False"/> <field name="internal" eval="True"/> </record> <record id="mt_consent_acceptance_changed" model="mail.message.subtype"> <field name="name">Acceptance Changed by Subject</field> <field name="description">Acceptance status updated by subject</field> <field name="res_model">privacy.consent</field> <field name="default" eval="False"/> <field name="hidden" eval="False"/> <field name="internal" eval="True"/> </record> <record id="mt_consent_state_changed" model="mail.message.subtype"> <field name="name">State Changed</field> <field name="description">Privacy consent request state changed</field> <field name="res_model">privacy.consent</field> <field name="default" eval="False"/> <field name="hidden" eval="False"/> <field name="internal" eval="True"/> </record>
<record id="mt_activity_consent_new" model="mail.message.subtype"> <field name="name">New Consent</field> <field name="description">Privacy consent request created</field> <field name="res_model">privacy.activity</field> <field name="default" eval="True"/> <field name="hidden" eval="False"/> <field name="internal" eval="True"/> <field name="parent_id" ref="mt_consent_consent_new"/> <field name="relation_field">activity_id</field> </record> <record id="mt_activity_acceptance_changed" model="mail.message.subtype"> <field name="name">Acceptance Changed</field> <field name="description">Privacy consent request acceptance status changed</field> <field name="res_model">privacy.activity</field> <field name="default" eval="True"/> <field name="hidden" eval="False"/> <field name="internal" eval="True"/> <field name="parent_id" ref="mt_consent_acceptance_changed"/> <field name="relation_field">activity_id</field> </record> <record id="mt_activity_state_changed" model="mail.message.subtype"> <field name="name">State Changed</field> <field name="description">Privacy consent request state changed</field> <field name="res_model">privacy.activity</field> <field name="default" eval="False"/> <field name="hidden" eval="False"/> <field name="internal" eval="True"/> <field name="parent_id" ref="mt_consent_state_changed"/> <field name="relation_field">activity_id</field> </record>
</data>
|