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
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<data>
<record id="activity_form" model="ir.ui.view"> <field name="name">Add consent fields</field> <field name="model">privacy.activity</field> <field name="inherit_id" ref="privacy.activity_form"/> <field name="arch" type="xml"> <div name="button_box" position="inside"> <button attrs='{"invisible": [("consent_required", "=", False)]}' class="oe_stat_button" context='{"search_default_activity_id": active_id}' icon="fa-handshake-o" name="%(consent_action)d" type="action" > <field name="consent_count" widget="statinfo" /> </button> </div>
<notebook name="advanced" position="inside"> <page string="Consent" name="consent"> <group> <label for="consent_required"/> <div> <field name="consent_required" class="oe_inline"/> <button attrs='{"invisible": [("consent_required", "!=", "manual")]}' class="btn-link" icon="fa-user-plus" name="action_new_consents" type="object" string="Generate missing draft consent requests" /> <button attrs='{"invisible": [("consent_required", "!=", "auto")]}' class="btn-link" icon="fa-user-plus" name="action_new_consents" type="object" string="Generate and enqueue missing consent requests" confirm="This could enqueue many consent emails, are you sure to proceed?" /> </div> </group> <group attrs='{"invisible": [("consent_required", "=", False)]}' > <group> <field name="default_consent"/> <field name="server_action_id" groups="base.group_no_one" /> </group> <group> <field name="consent_template_default_body_html" invisible="1" /> <field name="consent_template_default_subject" invisible="1" /> <field name="consent_template_id" attrs='{"required": [("consent_required", "=", "auto")]}' context='{ "default_model": "privacy.consent", "default_body_html": consent_template_default_body_html, "default_subject": consent_template_default_subject, }' /> </group> </group> </page> </notebook> </field> </record>
</data>
|