diff --git a/privacy_consent/README.rst b/privacy_consent/README.rst new file mode 100644 index 0000000..1330e8f --- /dev/null +++ b/privacy_consent/README.rst @@ -0,0 +1,178 @@ +================= +Privacy - Consent +================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png + :target: https://odoo-community.org/page/development-status + :alt: Production/Stable +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fdata--protection-lightgray.png?logo=github + :target: https://github.com/OCA/data-protection/tree/13.0/privacy_consent + :alt: OCA/data-protection +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/data-protection-13-0/data-protection-13-0-privacy_consent + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/263/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows the user to define a set of subjects (partners) +affected by any data processing activity, and establish +a process to ask them for consent to include them in that activity. + +For those that need explicit consent as a lawfulness base for personal data +processing, as required by GDPR (article 6.1.a), this module provides the +needed tools to automate it. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +You may want to install, along with this module, one of OCA's +``mail_tracking`` module collection, such as ``mail_tracking_mailgun``, so +you can provide more undeniable proof that some consent request was sent, and +to whom. + +However, the most important proof to provide is the answer itself (more than +the question), and this addon provides enough tooling for that. + +Multi-database instances +~~~~~~~~~~~~~~~~~~~~~~~~ + +To enable multi-database support, you must load this addon as a server-wide +addon. Example command to boot Odoo:: + + odoo-bin --load=web,privacy_consent + +Usage +===== + +New options for data processing activities: + +#. Go to *Privacy > Master Data > Activities* and create one. + +#. Give it a name, such as *Sending mass mailings to customers*. + +#. Go to tab *Consent* and choose one option in *Ask subjects for consent*: + + * *Manual* tells the activity that you will want to create and send the + consent requests manually, and only provides some helpers for you to + be able to batch-generate them. + + * *Automatic* enables this module's full power: send all consent requests + to selected partners automatically, every day and under your demand. + +#. When you do this, all the consent-related options appear. Configure them: + + * A smart button tells you how many consents have been generated, and lets you + access them. + + * Choose one *Email template* to send to subjects. This email itself is what + asks for consent, and it gets recorded, to serve as a proof that it was sent. + The module provides a default template that should be good for most usage + cases; and if you create one directly from that field, some good defaults + are provided for your comfortability. + + * *Subjects filter* defines what partners will be elegible for inclusion in + this data processing activity. + + * You can enable *Accepted by default* if you want to assume subjects + accepted their data processing. You should possibly consult your + lawyer to use this. + + * You can choose a *Server action* (developer mode only) that will + be executed whenever a new non-draft consent request is created, + or when its acceptance status changes. + + This module supplies a server action by default, called + *Update partner's opt out*, that syncs the acceptance status with the + partner's *Elegible for mass mailings* option. + +#. Click on *Generate consent requests* link to create new consent requests. + + * If you chose *Manual* mode, all missing consent request are created as + drafts, and nothing else is done now. + + * If you chose *Automatic* mode, also those request e-mails are enqueued + and, when the mail queue is cleared, they will be set as *Sent*. + +#. You will be presented with the list of just-created consent requests. + See below. + +New options for consent requests: + +#. Access the consent requests by either: + + * Generating new consent requests from a data processing activity. + + * Pressing the *Consents* smart button in a data processing activity. + + * Going to *Privacy > Privacy > Consents*. + +#. A consent will include the partner, the activity, the acceptance status, + and the request state. + +#. You can manually ask for consent by pressing the button labeled as + *Ask for consent*. + +#. All consent requests and responses are recorded in the mail thread below. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Tecnativa +* initOS GmbH + +Contributors +~~~~~~~~~~~~ + +* `Tecnativa `_: + + * Jairo Llopis + +* `initOS GmbH `_: + + * Florian Kantelberg + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/data-protection `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/privacy_consent/__init__.py b/privacy_consent/__init__.py new file mode 100644 index 0000000..91c5580 --- /dev/null +++ b/privacy_consent/__init__.py @@ -0,0 +1,2 @@ +from . import controllers +from . import models diff --git a/privacy_consent/__manifest__.py b/privacy_consent/__manifest__.py new file mode 100644 index 0000000..f49ac16 --- /dev/null +++ b/privacy_consent/__manifest__.py @@ -0,0 +1,27 @@ +# Copyright 2018 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Privacy - Consent", + "summary": "Allow people to explicitly accept or reject inclusion " + "in some activity, GDPR compliant", + "version": "14.0.1.0.0", + "development_status": "Production/Stable", + "category": "Privacy", + "website": "https://github.com/OCA/data-protection", + "author": "Tecnativa, initOS GmbH, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["privacy"], + "data": [ + "security/ir.model.access.csv", + "data/ir_actions_server.xml", + "data/ir_cron.xml", + "data/mail.xml", + "templates/assets.xml", + "templates/form.xml", + "views/privacy_consent.xml", + "views/privacy_activity.xml", + "views/res_partner.xml", + ], +} diff --git a/privacy_consent/controllers/__init__.py b/privacy_consent/controllers/__init__.py new file mode 100644 index 0000000..12a7e52 --- /dev/null +++ b/privacy_consent/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/privacy_consent/controllers/main.py b/privacy_consent/controllers/main.py new file mode 100644 index 0000000..1fee3be --- /dev/null +++ b/privacy_consent/controllers/main.py @@ -0,0 +1,43 @@ +# Copyright 2018 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from datetime import datetime + +from werkzeug.exceptions import NotFound + +from odoo.http import Controller, request, route + + +class ConsentController(Controller): + @route( + "/privacy/consent///", + type="http", + auth="public", + website=True, + ) + def consent(self, choice, consent_id, token, *args, **kwargs): + """Process user's consent acceptance or rejection.""" + consent = ( + request.env["privacy.consent"] + .with_context(subject_answering=True) + .sudo() + .browse(consent_id) + ) + if not (consent.exists() and consent._token() == token): + raise NotFound + if consent.partner_id.lang: + consent = consent.with_context(lang=consent.partner_id.lang) + request.context = consent.env.context + consent.action_answer(choice == "accept", self._metadata()) + return request.render("privacy_consent.form", {"consent": consent}) + + def _metadata(self): + return ( + u"User agent: {}\n" + u"Remote IP: {}\n" + u"Date and time: {:%Y-%m-%d %H:%M:%S}" + ).format( + request.httprequest.environ.get("HTTP_USER_AGENT"), + request.httprequest.environ.get("REMOTE_ADDRESS"), + datetime.now(), + ) diff --git a/privacy_consent/data/ir_actions_server.xml b/privacy_consent/data/ir_actions_server.xml new file mode 100644 index 0000000..149cbfa --- /dev/null +++ b/privacy_consent/data/ir_actions_server.xml @@ -0,0 +1,26 @@ + + + + + Sync partner's email blacklist status + + + code + + for consent in records: + email = consent.partner_id.email + # Skip records without email, although highly improbable + if not email: + continue + # Choose method to sync acceptance and blacklisting + if consent.accepted: + method = env["mail.blacklist"]._remove + else: + method = env["mail.blacklist"]._add + # Apply user desire + method(email) + + + diff --git a/privacy_consent/data/ir_cron.xml b/privacy_consent/data/ir_cron.xml new file mode 100644 index 0000000..d008b86 --- /dev/null +++ b/privacy_consent/data/ir_cron.xml @@ -0,0 +1,15 @@ + + + + + Request automatic data processing consents + + code + model._cron_new_consents() + 1 + days + -1 + + diff --git a/privacy_consent/data/mail.xml b/privacy_consent/data/mail.xml new file mode 100644 index 0000000..a485970 --- /dev/null +++ b/privacy_consent/data/mail.xml @@ -0,0 +1,186 @@ + + + + + + + Personal data processing consent request + Data processing consent request for ${object.activity_id.display_name|safe} + + + ${object.partner_id.lang} + +
+ + + + + + +
+ + ${object.activity_id.controller_id.display_name|safe} + +
+ + + + + + + + + + + + + +
+

+ Hello, ${object.partner_id.name|safe} +

+

+ We contacted you to ask you to give us your explicit consent to include your data in a data processing activity called + ${object.activity_id.display_name|safe}, property of + ${object.activity_id.controller_id.display_name|safe} +

+ ${object.description or ""} +

+ % 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: + accepted + % else: + rejected + % endif + such data processing. +

+

+ You can update your preferences below: +

+
+ + Accept + + + + Reject + +
+

+ If you need further information, please respond to this email and we will attend your request as soon as possible. +

+

+ Thank you! +

+
+ + + + + + +
+

+ Sent by + ${object.activity_id.controller_id.display_name|safe}. +

+
+
+
+
+ + + New Consent + Privacy consent request created + privacy.consent + + + + + + Acceptance Changed by Subject + Acceptance status updated by subject + privacy.consent + + + + + + State Changed + Privacy consent request state changed + privacy.consent + + + + + + New Consent + Privacy consent request created + privacy.activity + + + + + activity_id + + + Acceptance Changed + Privacy consent request acceptance status changed + privacy.activity + + + + + activity_id + + + State Changed + Privacy consent request state changed + privacy.activity + + + + + activity_id + +
diff --git a/privacy_consent/i18n/de.po b/privacy_consent/i18n/de.po new file mode 100644 index 0000000..f6b68d6 --- /dev/null +++ b/privacy_consent/i18n/de.po @@ -0,0 +1,652 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * privacy_consent +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-05-13 17:04+0000\n" +"PO-Revision-Date: 2019-04-11 11:16+0000\n" +"Last-Translator: dw3gn3r \n" +"Language-Team: none\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.5\n" + +#. module: privacy_consent +#: model:mail.template,body_html:privacy_consent.template_consent +msgid "" +"\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"${object."\n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Hello, ${object.partner_id.name|safe}\n" +"

\n" +"

\n" +" We contacted you to ask you to give us " +"your explicit consent to include your data in a data processing activity " +"called\n" +" ${object.activity_id.display_name|" +"safe}, property of\n" +" ${object.activity_id.controller_id." +"display_name|safe}\n" +"

\n" +" ${object.description or \"\"}\n" +"

\n" +" % if object.state == \"answered\":\n" +" The last time you answered, you\n" +" % elif object.state == \"sent\":\n" +" If you do nothing, we will assume " +"you have\n" +" % endif\n" +"\n" +" % if object.accepted:\n" +" accepted\n" +" % else:\n" +" rejected\n" +" % endif\n" +" such data processing.\n" +"

\n" +"

\n" +" You can update your preferences below:\n" +"

\n" +"
\n" +" \n" +" Accept\n" +" \n" +" \n" +" \n" +" Reject\n" +" \n" +"
\n" +"

\n" +" If you need further information, please " +"respond to this email and we will attend your request as soon as possible.\n" +"

\n" +"

\n" +" Thank you!\n" +"

\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Sent by\n" +" " +"${object.activity_id.controller_id.display_name|safe}.\n" +"

\n" +"
\n" +"
\n" +" " +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_acceptance_changed +msgid "Acceptance Changed" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_consent_acceptance_changed +msgid "Acceptance Changed by Subject" +msgstr "Zustimmung durch den Betroffenen geändert" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_consent_acceptance_changed +msgid "Acceptance status updated by subject" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__accepted +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Accepted" +msgstr "Akzeptiert" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__default_consent +msgid "Accepted by default" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__active +msgid "Active" +msgstr "Aktiv" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__activity_id +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Activity" +msgstr "Aktivität" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Answered" +msgstr "Beantwortet" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Archived" +msgstr "Archiviert" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_form +msgid "Ask for consent" +msgstr "Einwilligung einholen" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_required +msgid "Ask subjects for consent" +msgstr "Einwilligung beim Betroffenen einholen" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Automatically" +msgstr "Automatisch" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Awaiting response" +msgstr "Warten auf Antwort" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Consent" +msgstr "Einwilligung" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_default_body_html +#, fuzzy +msgid "Consent Template Default Body Html" +msgstr "Einverständniserklärung Standardtext html" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_default_subject +#, fuzzy +msgid "Consent Template Default Subject" +msgstr "Standardmäßige Einverständniserklärung Betroffener" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_consent +msgid "Consent of data processing" +msgstr "Einwilligung in die Datenverarbeitung" + +#. module: privacy_consent +#: model:ir.actions.act_window,name:privacy_consent.consent_action +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_ids +#: model:ir.model.fields,field_description:privacy_consent.field_res_partner__privacy_consent_count +#: model:ir.model.fields,field_description:privacy_consent.field_res_users__privacy_consent_count +#: model:ir.ui.menu,name:privacy_consent.menu_privacy_consent +msgid "Consents" +msgstr "Einwilligungen" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_count +#, fuzzy +msgid "Consents count" +msgstr "Einwilligungen" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_res_partner +msgid "Contact" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__create_uid +msgid "Created by" +msgstr "Erstellt von" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__create_date +msgid "Created on" +msgstr "Erstellt am" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_activity +msgid "Data processing activities" +msgstr "Verarbeitungstätigkeiten" + +#. module: privacy_consent +#: model:mail.template,subject:privacy_consent.template_consent +msgid "" +"Data processing consent request for ${object.activity_id.display_name|safe}" +msgstr "Bitte um Erteilung der Einwilligung zur Datenverarbeitung:" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__display_name +msgid "Display Name" +msgstr "Anzeigename" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Draft" +msgstr "Entwurf" + +#. module: privacy_consent +#: sql_constraint:privacy.consent:0 +msgid "Duplicated partner in this data processing activity" +msgstr "Doppelter Partner in dieser Verarbeitungsaktivität" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_mail_template +msgid "Email Templates" +msgstr "E-Mail-Vorlagen" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_id +msgid "Email template" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__consent_template_id +msgid "" +"Email to be sent to subjects to ask for consent. A good template should " +"include details about the current consent request status, how to change it, " +"and where to get more information." +msgstr "" +"E-Mail, die an die Betroffenen geschickt werden soll, um die Einwilligung " +"einzuholen. Eine gute Vorlage sollte Details über den aktuellen Status der " +"Einwilligungsanfrage enthalten, sowie Hinweise darüber, wie man den Status " +"der Einwilligung ändern kann und wo man weitere Informationen erhält." + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__consent_required +msgid "" +"Enable if you need to track any kind of consent from the affected subjects" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_channel_ids +msgid "Followers (Channels)" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +#, fuzzy +msgid "Generate and enqueue missing consent requests" +msgstr "Erstellung und Versand fehlender Einwilligungsanfragen" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate missing draft consent requests" +msgstr "Fehlende Entwürfe von Einwilligungsanfragen erstellen" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:139 +#, python-format +msgid "Generated consents" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Group By" +msgstr "Gruppieren nach" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Hello," +msgstr "Hallo" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "I accept this processing of my data" +msgstr "Ich akzeptiere die Verarbeitung meiner Daten" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "I reject this processing of my data" +msgstr "Ich lehne die Verarbeitung meiner Daten ab" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__id +msgid "ID" +msgstr "Ausweis" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_unread +msgid "If checked new messages require your attention." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "If it was a mistake, you can undo it here:" +msgstr "Wenn es ein Fehler war, können Sie diesen hier rückgängig machen:" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__accepted +msgid "" +"Indicates current acceptance status, which can come from subject's last " +"answer, or from the default specified in the related data processing " +"activity." +msgstr "" +"Zeigt den aktuellen Akzeptanzstatus an, der sich aus der letzten Antwort des " +"Betreffenden oder aus dem in der zugehörigen Datenverarbeitungsaktivität " +"angegebenen Standard ergeben kann." + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__last_metadata +#, fuzzy +msgid "Last Metadata" +msgstr "Letzte Metadaten" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent____last_update +msgid "Last Modified on" +msgstr "Letzte Änderung am" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__write_uid +msgid "Last Updated by" +msgstr "Zuletzt aktualisiert von" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__write_date +msgid "Last Updated on" +msgstr "Zuletzt aktualisiert am" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Manually" +msgstr "Manuell" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_ids +msgid "Messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__last_metadata +msgid "Metadata from the last acceptance or rejection by the subject" +msgstr "Metadaten aus der letzten Annahme oder Ablehnung durch den Betroffenen" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/mail_template.py:24 +#, python-format +msgid "" +"Missing privacy consent link placeholders. You need at least these two " +"links:\n" +"Accept\n" +"Reject" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_consent_new +#: model:mail.message.subtype,name:privacy_consent.mt_consent_consent_new +msgid "New Consent" +msgstr "Neue Einwilligung" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_has_error_counter +msgid "Number of error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_unread_counter +msgid "Number of unread messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_mail_mail +msgid "Outgoing Mails" +msgstr "Ausgehende Mails" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_acceptance_changed +msgid "Privacy consent request acceptance status changed" +msgstr "" +"Der Akzeptanzstatus der Anfrage 'Einwilligung zum Datenschutz' wurde " +"geändert." + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_consent_new +#: model:mail.message.subtype,description:privacy_consent.mt_consent_consent_new +msgid "Privacy consent request created" +msgstr "Anfrage zur Einwilligung erstellt" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_state_changed +#: model:mail.message.subtype,description:privacy_consent.mt_consent_state_changed +msgid "Privacy consent request state changed" +msgstr "Status der Anfrage zur Einwilligung geändert" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_res_partner__privacy_consent_count +#: model:ir.model.fields,help:privacy_consent.field_res_users__privacy_consent_count +msgid "Privacy consent requests amount" +msgstr "Anzahl der Anfragen zur Einwilligung" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_res_partner__privacy_consent_ids +#: model:ir.model.fields,field_description:privacy_consent.field_res_users__privacy_consent_ids +msgid "Privacy consents" +msgstr "Einwilligung zum Datenschutz" + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.cron_auto_consent_ir_actions_server +#: model:ir.cron,cron_name:privacy_consent.cron_auto_consent +#: model:ir.cron,name:privacy_consent.cron_auto_consent +msgid "Request automatic data processing consents" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:99 +#, python-format +msgid "Require consent is available only for subjects in current database." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__server_action_id +msgid "" +"Run this action when a new consent request is created or its acceptance " +"status is updated." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__server_action_id +msgid "Server action" +msgstr "Server-Aktion" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__default_consent +msgid "Should we assume the subject has accepted if we receive no response?" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Sincerely,
" +msgstr "Mit freundlichen Grüßen
" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:91 +#, python-format +msgid "Specify a mail template to ask automated consent." +msgstr "" +"Wählen Sie eine E-Mail-Vorlage aus, um eine automatische Einwilligung " +"einzuholen." + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__state +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "State" +msgstr "Status" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_state_changed +#: model:mail.message.subtype,name:privacy_consent.mt_consent_state_changed +msgid "State Changed" +msgstr "Status geändert" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__partner_id +msgid "Subject" +msgstr "Betroffener" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__partner_id +msgid "Subject asked for consent." +msgstr "" + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.sync_blacklist +msgid "Sync partner's email blacklist status" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Thank you!" +msgstr "Vielen Dank." + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Thanks for your response." +msgstr "Vielen Dank für Ihre Antwort." + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +#, fuzzy +msgid "This could enqueue many consent emails, are you sure to proceed?" +msgstr "" +"Hiermit könnten viele Einwilligungs-E-Mails verschickt werden. Sind Sie " +"sicher, dass Sie fortfahren wollen?" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_unread +msgid "Unread Messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_unread_counter +msgid "Unread Messages Counter" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "" +"We asked you to authorize us to process your data in this data processing " +"activity:" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "We have recorded this action on your side." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "You have rejected such processing." +msgstr "" +"Du hast diese Verarbeitungstätigkeit abgelehnt." + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "You have accepted such processing." +msgstr "" +"Du hast dieser Verarbeitungstätigkeit zugestimmt." + +#~ msgid "Partner" +#~ msgstr "Partner" diff --git a/privacy_consent/i18n/es.po b/privacy_consent/i18n/es.po new file mode 100644 index 0000000..80b9dca --- /dev/null +++ b/privacy_consent/i18n/es.po @@ -0,0 +1,779 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * privacy_consent +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-05-13 17:04+0000\n" +"PO-Revision-Date: 2019-05-13 18:08+0100\n" +"Last-Translator: Jairo Llopis \n" +"Language-Team: \n" +"Language: es_ES\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 2.2.1\n" + +#. module: privacy_consent +#: model:mail.template,body_html:privacy_consent.template_consent +msgid "" +"\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"${object."\n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Hello, ${object.partner_id.name|safe}\n" +"

\n" +"

\n" +" We contacted you to ask you to give us " +"your explicit consent to include your data in a data processing activity " +"called\n" +" ${object.activity_id.display_name|" +"safe}, property of\n" +" ${object.activity_id.controller_id." +"display_name|safe}\n" +"

\n" +" ${object.description or \"\"}\n" +"

\n" +" % if object.state == \"answered\":\n" +" The last time you answered, you\n" +" % elif object.state == \"sent\":\n" +" If you do nothing, we will assume " +"you have\n" +" % endif\n" +"\n" +" % if object.accepted:\n" +" accepted\n" +" % else:\n" +" rejected\n" +" % endif\n" +" such data processing.\n" +"

\n" +"

\n" +" You can update your preferences below:\n" +"

\n" +"
\n" +" \n" +" Accept\n" +" \n" +" \n" +" \n" +" Reject\n" +" \n" +"
\n" +"

\n" +" If you need further information, please " +"respond to this email and we will attend your request as soon as possible.\n" +"

\n" +"

\n" +" Thank you!\n" +"

\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Sent by\n" +" " +"${object.activity_id.controller_id.display_name|safe}.\n" +"

\n" +"
\n" +"
\n" +" " +msgstr "" +"\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"${object."\n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Hola, ${object.partner_id.name|safe}\n" +"

\n" +"

\n" +" Le hemos contactado para pedirle su " +"consentimiento explícito para incluir sus datos en una actividad de " +"tratamiento llamada\n" +" ${object.activity_id.display_name|" +"safe}, propiedad de\n" +" ${object.activity_id.controller_id." +"display_name|safe}\n" +"

\n" +" ${object.description or \"\"}\n" +"

\n" +" % if object.state == \"answered\":\n" +" Según su última respuesta,\n" +" % elif object.state == \"sent\":\n" +" Si no recibimos respuesta, " +"asumiremos que\n" +" % endif\n" +"\n" +" % if object.accepted:\n" +" ha aceptado\n" +" % else:\n" +" ha rechazado\n" +" % endif\n" +" dicho procesamiento de datos.\n" +"

\n" +"

\n" +" Puede cambiar sus preferencias aquí " +"abajo:\n" +"

\n" +"
\n" +" \n" +" Aceptar\n" +" \n" +" \n" +" \n" +" Rechazar\n" +" \n" +"
\n" +"

\n" +" Si necesita más información, por favor " +"responda a este correo electrónico y atenderemos su solicitud a la mayor " +"brevedad posible.\n" +"

\n" +"

\n" +" ¡Gracias!\n" +"

\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Enviado por\n" +" " +"${object.activity_id.controller_id.display_name|safe}.\n" +"

\n" +"
\n" +"
\n" +" " + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_acceptance_changed +msgid "Acceptance Changed" +msgstr "Aceptación cambiada" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_consent_acceptance_changed +msgid "Acceptance Changed by Subject" +msgstr "Aceptación cambiada por el interesado" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_consent_acceptance_changed +msgid "Acceptance status updated by subject" +msgstr "Estado de aceptación modificado por el interesado" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__accepted +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Accepted" +msgstr "Aceptado" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__default_consent +msgid "Accepted by default" +msgstr "Aceptado por defecto" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__active +msgid "Active" +msgstr "Activo" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__activity_id +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Activity" +msgstr "Actividad" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Answered" +msgstr "Respondido" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Archived" +msgstr "Archivado" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_form +msgid "Ask for consent" +msgstr "Solicitar consentimiento" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_required +msgid "Ask subjects for consent" +msgstr "Solicitar consentimiento a los interesados" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Automatically" +msgstr "Automáticamente" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Awaiting response" +msgstr "Esperando respuesta" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Consent" +msgstr "Consentimiento" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_default_body_html +#, fuzzy +msgid "Consent Template Default Body Html" +msgstr "HTML por defecto para el cuerpo de la plantilla de consentimiento" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_default_subject +#, fuzzy +msgid "Consent Template Default Subject" +msgstr "HTML por defecto para el asunto de la plantilla de consentimiento" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_consent +msgid "Consent of data processing" +msgstr "Consentimiento para tratamiento de datos" + +#. module: privacy_consent +#: model:ir.actions.act_window,name:privacy_consent.consent_action +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_ids +#: model:ir.model.fields,field_description:privacy_consent.field_res_partner__privacy_consent_count +#: model:ir.model.fields,field_description:privacy_consent.field_res_users__privacy_consent_count +#: model:ir.ui.menu,name:privacy_consent.menu_privacy_consent +msgid "Consents" +msgstr "Consents" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_count +#, fuzzy +msgid "Consents count" +msgstr "Consents" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_res_partner +msgid "Contact" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_activity +msgid "Data processing activities" +msgstr "Actividades de tratamiento de datos" + +#. module: privacy_consent +#: model:mail.template,subject:privacy_consent.template_consent +msgid "" +"Data processing consent request for ${object.activity_id.display_name|safe}" +msgstr "" +"Solicitud de consentimiento para el tratamiento de datos personales para " +"${object.activity_id.display_name|safe}" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__display_name +msgid "Display Name" +msgstr "Nombre a mostrar" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Draft" +msgstr "Borrador" + +#. module: privacy_consent +#: sql_constraint:privacy.consent:0 +msgid "Duplicated partner in this data processing activity" +msgstr "Contacto duplicado en esta actividad de tratamiento" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_mail_template +msgid "Email Templates" +msgstr "Plantillas de correo electrónico" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_id +msgid "Email template" +msgstr "Plantilla de correo electrónico" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__consent_template_id +msgid "" +"Email to be sent to subjects to ask for consent. A good template should " +"include details about the current consent request status, how to change it, " +"and where to get more information." +msgstr "" +"Correo electrónico a enviar a los interesados para solicitarles el " +"consentimiento. Una buena plantilla debería incluir detalles sobre el estado " +"actual del consentimiento, cómo cambiarlo, y dónde obtener más información." + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__consent_required +msgid "" +"Enable if you need to track any kind of consent from the affected subjects" +msgstr "" +"Actívelo si necesita registrar cualquier tipo de consentimiento de los " +"interesados" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_channel_ids +msgid "Followers (Channels)" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate and enqueue missing consent requests" +msgstr "" +"Generar y colocar en la bandeja de salida las solicitudes de consentimiento " +"que falten" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate missing draft consent requests" +msgstr "Generar borradores de las solicitudes de consentimiento faltantes" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:139 +#, python-format +msgid "Generated consents" +msgstr "Consentimientos generados" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Group By" +msgstr "Agrupar por" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Hello," +msgstr "Hola," + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "I accept this processing of my data" +msgstr "Acepto este tratamiento de mis datos" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "I reject this processing of my data" +msgstr "Rechazo este tratamiento de mis datos" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__id +msgid "ID" +msgstr "ID" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_unread +msgid "If checked new messages require your attention." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "If it was a mistake, you can undo it here:" +msgstr "Si ha sido un error, puede deshacerlo aquí:" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__accepted +msgid "" +"Indicates current acceptance status, which can come from subject's last " +"answer, or from the default specified in the related data processing " +"activity." +msgstr "" +"Indica el estado actual de la aceptación, el cual puede venir de la última " +"respuesta del interesado, o del estado por defecto especificado en la " +"actividad de tratamiento relacionada." + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__last_metadata +#, fuzzy +msgid "Last Metadata" +msgstr "Últimos metadatos" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent____last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__write_date +msgid "Last Updated on" +msgstr "Última actualización el" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Manually" +msgstr "Manualmente" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_ids +msgid "Messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__last_metadata +msgid "Metadata from the last acceptance or rejection by the subject" +msgstr "" +"Metadatos de la última aceptación o denegación por parte del interesado" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/mail_template.py:24 +#, python-format +msgid "" +"Missing privacy consent link placeholders. You need at least these two " +"links:\n" +"Accept\n" +"Reject" +msgstr "" +"Faltan los marcadores de posición de los enlaces para el consentimiento. " +"Necesita al menos estos dos enlaces:\n" +"Aceptar\n" +"Rechazar" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_consent_new +#: model:mail.message.subtype,name:privacy_consent.mt_consent_consent_new +msgid "New Consent" +msgstr "Nuevo consentimiento" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_has_error_counter +msgid "Number of error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_unread_counter +msgid "Number of unread messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_mail_mail +msgid "Outgoing Mails" +msgstr "Correos electrónicos salientes" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_acceptance_changed +msgid "Privacy consent request acceptance status changed" +msgstr "" +"El estado de aceptación de la solicitud de consentimiento para el " +"tratamiento de datos ha cambiado" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_consent_new +#: model:mail.message.subtype,description:privacy_consent.mt_consent_consent_new +msgid "Privacy consent request created" +msgstr "" +"La solicitud de consentimiento para el tratamiento de datos ha sido creada" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_state_changed +#: model:mail.message.subtype,description:privacy_consent.mt_consent_state_changed +msgid "Privacy consent request state changed" +msgstr "" +"El estado de la solicitud de consentimiento para el tratamiento de datos ha " +"cambiado" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_res_partner__privacy_consent_count +#: model:ir.model.fields,help:privacy_consent.field_res_users__privacy_consent_count +msgid "Privacy consent requests amount" +msgstr "Cantidad de solicitudes de consentimiento para el tratamiento de datos" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_res_partner__privacy_consent_ids +#: model:ir.model.fields,field_description:privacy_consent.field_res_users__privacy_consent_ids +msgid "Privacy consents" +msgstr "Consentimientos para el tratamiento de datos" + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.cron_auto_consent_ir_actions_server +#: model:ir.cron,cron_name:privacy_consent.cron_auto_consent +#: model:ir.cron,name:privacy_consent.cron_auto_consent +msgid "Request automatic data processing consents" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:99 +#, python-format +msgid "Require consent is available only for subjects in current database." +msgstr "" +"La opción de exigir consentimiento solo está disponible para interesados que " +"se encuentren en esta misma base de datos." + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__server_action_id +msgid "" +"Run this action when a new consent request is created or its acceptance " +"status is updated." +msgstr "" +"Ejecutar esta acción cuando se cree una nueva solicitud de consentimiento, o " +"cuando su estado de aceptación cambie." + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__server_action_id +msgid "Server action" +msgstr "Acción de servidor" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__default_consent +msgid "Should we assume the subject has accepted if we receive no response?" +msgstr "" +"¿Hay que asumir que el interesado ha aceptado si no recibimos respuesta?" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Sincerely,
" +msgstr "Atentamente,
" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:91 +#, python-format +msgid "Specify a mail template to ask automated consent." +msgstr "" +"Especifique una plantilla de correo electrónico para solicitar " +"automáticamente el consentimiento." + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__state +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "State" +msgstr "Estado" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_state_changed +#: model:mail.message.subtype,name:privacy_consent.mt_consent_state_changed +msgid "State Changed" +msgstr "El estado ha cambiado" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__partner_id +msgid "Subject" +msgstr "Interesado" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__partner_id +msgid "Subject asked for consent." +msgstr "Interesado a quien se le pide el consentimiento." + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.sync_blacklist +msgid "Sync partner's email blacklist status" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Thank you!" +msgstr "¡Gracias!" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Thanks for your response." +msgstr "Gracias por su respuesta." + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "This could enqueue many consent emails, are you sure to proceed?" +msgstr "" +"Esto podría poner en la cola muchos correos electrónicos solicitando " +"consentimiento para el tratamiento de datos, ¿seguro que quiere continuar?" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_unread +msgid "Unread Messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_unread_counter +msgid "Unread Messages Counter" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "" +"We asked you to authorize us to process your data in this data processing " +"activity:" +msgstr "" +"Le hemos solicitado que nos autorice para procesar sus datos personales en " +"esta actividad de tratamiento:" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "We have recorded this action on your side." +msgstr "Hemos registrado esta acción por su parte." + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "You have rejected such processing." +msgstr "Ha rechazado dicho tratamiento." + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "You have accepted such processing." +msgstr "Ha aceptado dicho tratamiento." + +#~ msgid "Email composition wizard" +#~ msgstr "Asistente de redacción de correo electrónico" + +#~ msgid "Partner" +#~ msgstr "Contacto" + +#~ msgid "Update partner's opt out" +#~ msgstr "Sincronizar la opción del contacto para recibir o no envíos masivos" diff --git a/privacy_consent/i18n/fr.po b/privacy_consent/i18n/fr.po new file mode 100644 index 0000000..0c0933e --- /dev/null +++ b/privacy_consent/i18n/fr.po @@ -0,0 +1,624 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * privacy_consent +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" + +#. module: privacy_consent +#: model:mail.template,body_html:privacy_consent.template_consent +msgid "" +"\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"${object."\n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Hello, ${object.partner_id.name|safe}\n" +"

\n" +"

\n" +" We contacted you to ask you to give us " +"your explicit consent to include your data in a data processing activity " +"called\n" +" ${object.activity_id.display_name|" +"safe}, property of\n" +" ${object.activity_id.controller_id." +"display_name|safe}\n" +"

\n" +" ${object.description or \"\"}\n" +"

\n" +" % if object.state == \"answered\":\n" +" The last time you answered, you\n" +" % elif object.state == \"sent\":\n" +" If you do nothing, we will assume " +"you have\n" +" % endif\n" +"\n" +" % if object.accepted:\n" +" accepted\n" +" % else:\n" +" rejected\n" +" % endif\n" +" such data processing.\n" +"

\n" +"

\n" +" You can update your preferences below:\n" +"

\n" +"
\n" +" \n" +" Accept\n" +" \n" +" \n" +" \n" +" Reject\n" +" \n" +"
\n" +"

\n" +" If you need further information, please " +"respond to this email and we will attend your request as soon as possible.\n" +"

\n" +"

\n" +" Thank you!\n" +"

\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Sent by\n" +" " +"${object.activity_id.controller_id.display_name|safe}.\n" +"

\n" +"
\n" +"
\n" +" " +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_acceptance_changed +msgid "Acceptance Changed" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_consent_acceptance_changed +msgid "Acceptance Changed by Subject" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_consent_acceptance_changed +msgid "Acceptance status updated by subject" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__accepted +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Accepted" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__default_consent +msgid "Accepted by default" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__active +msgid "Active" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__activity_id +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Activity" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Answered" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Archived" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_form +msgid "Ask for consent" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_required +msgid "Ask subjects for consent" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Automatically" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Awaiting response" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Consent" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_default_body_html +msgid "Consent Template Default Body Html" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_default_subject +msgid "Consent Template Default Subject" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_consent +msgid "Consent of data processing" +msgstr "" + +#. module: privacy_consent +#: model:ir.actions.act_window,name:privacy_consent.consent_action +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_ids +#: model:ir.model.fields,field_description:privacy_consent.field_res_partner__privacy_consent_count +#: model:ir.model.fields,field_description:privacy_consent.field_res_users__privacy_consent_count +#: model:ir.ui.menu,name:privacy_consent.menu_privacy_consent +msgid "Consents" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_count +msgid "Consents count" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_res_partner +msgid "Contact" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__create_uid +msgid "Created by" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__create_date +msgid "Created on" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_activity +msgid "Data processing activities" +msgstr "" + +#. module: privacy_consent +#: model:mail.template,subject:privacy_consent.template_consent +msgid "" +"Data processing consent request for ${object.activity_id.display_name|safe}" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__display_name +msgid "Display Name" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Draft" +msgstr "" + +#. module: privacy_consent +#: sql_constraint:privacy.consent:0 +msgid "Duplicated partner in this data processing activity" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_mail_template +msgid "Email Templates" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_id +msgid "Email template" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__consent_template_id +msgid "" +"Email to be sent to subjects to ask for consent. A good template should " +"include details about the current consent request status, how to change it, " +"and where to get more information." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__consent_required +msgid "" +"Enable if you need to track any kind of consent from the affected subjects" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_channel_ids +msgid "Followers (Channels)" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate and enqueue missing consent requests" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate missing draft consent requests" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:139 +#, python-format +msgid "Generated consents" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Group By" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Hello," +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "I accept this processing of my data" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "I reject this processing of my data" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__id +msgid "ID" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_unread +msgid "If checked new messages require your attention." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "If it was a mistake, you can undo it here:" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__accepted +msgid "" +"Indicates current acceptance status, which can come from subject's last " +"answer, or from the default specified in the related data processing " +"activity." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__last_metadata +msgid "Last Metadata" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent____last_update +msgid "Last Modified on" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__write_date +msgid "Last Updated on" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Manually" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_ids +msgid "Messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__last_metadata +msgid "Metadata from the last acceptance or rejection by the subject" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/mail_template.py:24 +#, python-format +msgid "" +"Missing privacy consent link placeholders. You need at least these two " +"links:\n" +"Accept\n" +"Reject" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_consent_new +#: model:mail.message.subtype,name:privacy_consent.mt_consent_consent_new +msgid "New Consent" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_has_error_counter +msgid "Number of error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_unread_counter +msgid "Number of unread messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_mail_mail +msgid "Outgoing Mails" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_acceptance_changed +msgid "Privacy consent request acceptance status changed" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_consent_new +#: model:mail.message.subtype,description:privacy_consent.mt_consent_consent_new +msgid "Privacy consent request created" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_state_changed +#: model:mail.message.subtype,description:privacy_consent.mt_consent_state_changed +msgid "Privacy consent request state changed" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_res_partner__privacy_consent_count +#: model:ir.model.fields,help:privacy_consent.field_res_users__privacy_consent_count +msgid "Privacy consent requests amount" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_res_partner__privacy_consent_ids +#: model:ir.model.fields,field_description:privacy_consent.field_res_users__privacy_consent_ids +msgid "Privacy consents" +msgstr "" + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.cron_auto_consent_ir_actions_server +#: model:ir.cron,cron_name:privacy_consent.cron_auto_consent +#: model:ir.cron,name:privacy_consent.cron_auto_consent +msgid "Request automatic data processing consents" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:99 +#, python-format +msgid "Require consent is available only for subjects in current database." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__server_action_id +msgid "" +"Run this action when a new consent request is created or its acceptance " +"status is updated." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__server_action_id +msgid "Server action" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__default_consent +msgid "Should we assume the subject has accepted if we receive no response?" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Sincerely,
" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:91 +#, python-format +msgid "Specify a mail template to ask automated consent." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__state +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "State" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_state_changed +#: model:mail.message.subtype,name:privacy_consent.mt_consent_state_changed +msgid "State Changed" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__partner_id +msgid "Subject" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__partner_id +msgid "Subject asked for consent." +msgstr "" + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.sync_blacklist +msgid "Sync partner's email blacklist status" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Thank you!" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Thanks for your response." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "This could enqueue many consent emails, are you sure to proceed?" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_unread +msgid "Unread Messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_unread_counter +msgid "Unread Messages Counter" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "" +"We asked you to authorize us to process your data in this data processing " +"activity:" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "We have recorded this action on your side." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "You have rejected such processing." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "You have accepted such processing." +msgstr "" diff --git a/privacy_consent/i18n/privacy_consent.pot b/privacy_consent/i18n/privacy_consent.pot new file mode 100644 index 0000000..b87f2e5 --- /dev/null +++ b/privacy_consent/i18n/privacy_consent.pot @@ -0,0 +1,588 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * privacy_consent +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: privacy_consent +#: model:mail.template,body_html:privacy_consent.template_consent +msgid "\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"${object.activity_id.controller_id.display_name|safe}\"\n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Hello, ${object.partner_id.name|safe}\n" +"

\n" +"

\n" +" We contacted you to ask you to give us your explicit consent to include your data in a data processing activity called\n" +" ${object.activity_id.display_name|safe}, property of\n" +" ${object.activity_id.controller_id.display_name|safe}\n" +"

\n" +" ${object.description or \"\"}\n" +"

\n" +" % if object.state == \"answered\":\n" +" The last time you answered, you\n" +" % elif object.state == \"sent\":\n" +" If you do nothing, we will assume you have\n" +" % endif\n" +"\n" +" % if object.accepted:\n" +" accepted\n" +" % else:\n" +" rejected\n" +" % endif\n" +" such data processing.\n" +"

\n" +"

\n" +" You can update your preferences below:\n" +"

\n" +"
\n" +" \n" +" Accept\n" +" \n" +" \n" +" \n" +" Reject\n" +" \n" +"
\n" +"

\n" +" If you need further information, please respond to this email and we will attend your request as soon as possible.\n" +"

\n" +"

\n" +" Thank you!\n" +"

\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Sent by\n" +" ${object.activity_id.controller_id.display_name|safe}.\n" +"

\n" +"
\n" +"
\n" +" " +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_acceptance_changed +msgid "Acceptance Changed" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_consent_acceptance_changed +msgid "Acceptance Changed by Subject" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_consent_acceptance_changed +msgid "Acceptance status updated by subject" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__accepted +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Accepted" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__default_consent +msgid "Accepted by default" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__active +msgid "Active" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__activity_id +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Activity" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Answered" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Archived" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_form +msgid "Ask for consent" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_required +msgid "Ask subjects for consent" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Automatically" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Awaiting response" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Consent" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_default_body_html +msgid "Consent Template Default Body Html" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_default_subject +msgid "Consent Template Default Subject" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_consent +msgid "Consent of data processing" +msgstr "" + +#. module: privacy_consent +#: model:ir.actions.act_window,name:privacy_consent.consent_action +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_ids +#: model:ir.model.fields,field_description:privacy_consent.field_res_partner__privacy_consent_count +#: model:ir.model.fields,field_description:privacy_consent.field_res_users__privacy_consent_count +#: model:ir.ui.menu,name:privacy_consent.menu_privacy_consent +msgid "Consents" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_count +msgid "Consents count" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_res_partner +msgid "Contact" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__create_uid +msgid "Created by" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__create_date +msgid "Created on" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_activity +msgid "Data processing activities" +msgstr "" + +#. module: privacy_consent +#: model:mail.template,subject:privacy_consent.template_consent +msgid "Data processing consent request for ${object.activity_id.display_name|safe}" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__display_name +msgid "Display Name" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Draft" +msgstr "" + +#. module: privacy_consent +#: sql_constraint:privacy.consent:0 +msgid "Duplicated partner in this data processing activity" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_mail_template +msgid "Email Templates" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_id +msgid "Email template" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__consent_template_id +msgid "Email to be sent to subjects to ask for consent. A good template should include details about the current consent request status, how to change it, and where to get more information." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__consent_required +msgid "Enable if you need to track any kind of consent from the affected subjects" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_channel_ids +msgid "Followers (Channels)" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate and enqueue missing consent requests" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate missing draft consent requests" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:139 +#, python-format +msgid "Generated consents" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Group By" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Hello," +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "I accept this processing of my data" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "I reject this processing of my data" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__id +msgid "ID" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_unread +msgid "If checked new messages require your attention." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "If it was a mistake, you can undo it here:" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__accepted +msgid "Indicates current acceptance status, which can come from subject's last answer, or from the default specified in the related data processing activity." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__last_metadata +msgid "Last Metadata" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent____last_update +msgid "Last Modified on" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__write_date +msgid "Last Updated on" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Manually" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_ids +msgid "Messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__last_metadata +msgid "Metadata from the last acceptance or rejection by the subject" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/mail_template.py:24 +#, python-format +msgid "Missing privacy consent link placeholders. You need at least these two links:\n" +"Accept\n" +"Reject" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_consent_new +#: model:mail.message.subtype,name:privacy_consent.mt_consent_consent_new +msgid "New Consent" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_has_error_counter +msgid "Number of error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_unread_counter +msgid "Number of unread messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_mail_mail +msgid "Outgoing Mails" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_acceptance_changed +msgid "Privacy consent request acceptance status changed" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_consent_new +#: model:mail.message.subtype,description:privacy_consent.mt_consent_consent_new +msgid "Privacy consent request created" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_state_changed +#: model:mail.message.subtype,description:privacy_consent.mt_consent_state_changed +msgid "Privacy consent request state changed" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_res_partner__privacy_consent_count +#: model:ir.model.fields,help:privacy_consent.field_res_users__privacy_consent_count +msgid "Privacy consent requests amount" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_res_partner__privacy_consent_ids +#: model:ir.model.fields,field_description:privacy_consent.field_res_users__privacy_consent_ids +msgid "Privacy consents" +msgstr "" + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.cron_auto_consent_ir_actions_server +#: model:ir.cron,cron_name:privacy_consent.cron_auto_consent +#: model:ir.cron,name:privacy_consent.cron_auto_consent +msgid "Request automatic data processing consents" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:99 +#, python-format +msgid "Require consent is available only for subjects in current database." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__server_action_id +msgid "Run this action when a new consent request is created or its acceptance status is updated." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__server_action_id +msgid "Server action" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__default_consent +msgid "Should we assume the subject has accepted if we receive no response?" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Sincerely,
" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:91 +#, python-format +msgid "Specify a mail template to ask automated consent." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__state +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "State" +msgstr "" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_state_changed +#: model:mail.message.subtype,name:privacy_consent.mt_consent_state_changed +msgid "State Changed" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__partner_id +msgid "Subject" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__partner_id +msgid "Subject asked for consent." +msgstr "" + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.sync_blacklist +msgid "Sync partner's email blacklist status" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Thank you!" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Thanks for your response." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "This could enqueue many consent emails, are you sure to proceed?" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_unread +msgid "Unread Messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_unread_counter +msgid "Unread Messages Counter" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "We asked you to authorize us to process your data in this data processing activity:" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "We have recorded this action on your side." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "You have rejected such processing." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "You have accepted such processing." +msgstr "" + diff --git a/privacy_consent/i18n/pt.po b/privacy_consent/i18n/pt.po new file mode 100644 index 0000000..f3cff8d --- /dev/null +++ b/privacy_consent/i18n/pt.po @@ -0,0 +1,768 @@ +msgid "" +msgstr "" +"Project-Id-Version: Portuguese (data-protection-10.0)\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2018-12-15 21:58+0000\n" +"Last-Translator: alvarorib \n" +"Language-Team: Portuguese \n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.3\n" + +#. module: privacy_consent +#: model:mail.template,body_html:privacy_consent.template_consent +msgid "" +"\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"${object."\n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Hello, ${object.partner_id.name|safe}\n" +"

\n" +"

\n" +" We contacted you to ask you to give us " +"your explicit consent to include your data in a data processing activity " +"called\n" +" ${object.activity_id.display_name|" +"safe}, property of\n" +" ${object.activity_id.controller_id." +"display_name|safe}\n" +"

\n" +" ${object.description or \"\"}\n" +"

\n" +" % if object.state == \"answered\":\n" +" The last time you answered, you\n" +" % elif object.state == \"sent\":\n" +" If you do nothing, we will assume " +"you have\n" +" % endif\n" +"\n" +" % if object.accepted:\n" +" accepted\n" +" % else:\n" +" rejected\n" +" % endif\n" +" such data processing.\n" +"

\n" +"

\n" +" You can update your preferences below:\n" +"

\n" +"
\n" +" \n" +" Accept\n" +" \n" +" \n" +" \n" +" Reject\n" +" \n" +"
\n" +"

\n" +" If you need further information, please " +"respond to this email and we will attend your request as soon as possible.\n" +"

\n" +"

\n" +" Thank you!\n" +"

\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Sent by\n" +" " +"${object.activity_id.controller_id.display_name|safe}.\n" +"

\n" +"
\n" +"
\n" +" " +msgstr "" +"\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +" \n" +" \"${object."\n" +" \n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Olá, ${object.partner_id.name|safe}\n" +"

\n" +"

\n" +" Contactámos, para solicitar o seu " +"consentimento explícito, à inclusão dos seus dados numa atividade de " +"processamento de dados, chamada\n" +" ${object.activity_id.display_name|" +"safe}, propriedade de\n" +" ${object.activity_id.controller_id." +"display_name|safe}\n" +"

\n" +" ${object.description or \"\"}\n" +"

\n" +" % if object.state == \"answered\":\n" +" A última vez que nos respondeu, " +"você\n" +" % elif object.state == \"sent\":\n" +" Se nada fizer, assumimos que você\n" +" % endif\n" +"\n" +" % if object.accepted:\n" +" aceitou\n" +" % else:\n" +" rejeitou\n" +" % endif\n" +" esse processamento de dados.\n" +"

\n" +"

\n" +" Pode atualizar as suas preferências " +"abaixo:\n" +"

\n" +"
\n" +" \n" +" Aceito\n" +" \n" +" \n" +" \n" +" Rejeito\n" +" \n" +"
\n" +"

\n" +" Se necessitar de mais informação, por " +"favor responda a este email e nós trataremos de esclarecer assim que " +"possível.\n" +"

\n" +"

\n" +" Obrigado!\n" +"

\n" +"
\n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +"
\n" +"

\n" +" Enviado por\n" +" " +"${object.activity_id.controller_id.display_name|safe}.\n" +"

\n" +"
\n" +"
\n" +" " + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_acceptance_changed +msgid "Acceptance Changed" +msgstr "Aceitação Alterada" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_consent_acceptance_changed +msgid "Acceptance Changed by Subject" +msgstr "Aceitação Alterada por Titular" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_consent_acceptance_changed +msgid "Acceptance status updated by subject" +msgstr "Estado da aceitação atualizado por titular" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__accepted +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Accepted" +msgstr "Aceite" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__default_consent +msgid "Accepted by default" +msgstr "Aceite por defeito" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__active +msgid "Active" +msgstr "Ativo" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__activity_id +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Activity" +msgstr "Atividade" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Answered" +msgstr "Respondido" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Archived" +msgstr "Arquivado" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_form +msgid "Ask for consent" +msgstr "Pedir consentimento" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_required +msgid "Ask subjects for consent" +msgstr "Solicitar consentimento aos titulares" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Automatically" +msgstr "Automaticamente" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Awaiting response" +msgstr "À espera de resposta" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Consent" +msgstr "Consentimento" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_default_body_html +#, fuzzy +msgid "Consent Template Default Body Html" +msgstr "Corpo predefinido HTML do modelo de consentimento" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_default_subject +#, fuzzy +msgid "Consent Template Default Subject" +msgstr "Modelo predefinido de consentimento do titular" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_consent +msgid "Consent of data processing" +msgstr "Consentimento de processamento de dados" + +#. module: privacy_consent +#: model:ir.actions.act_window,name:privacy_consent.consent_action +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_ids +#: model:ir.model.fields,field_description:privacy_consent.field_res_partner__privacy_consent_count +#: model:ir.model.fields,field_description:privacy_consent.field_res_users__privacy_consent_count +#: model:ir.ui.menu,name:privacy_consent.menu_privacy_consent +msgid "Consents" +msgstr "Consentimentos" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_count +#, fuzzy +msgid "Consents count" +msgstr "Consentimentos" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_res_partner +msgid "Contact" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__create_uid +msgid "Created by" +msgstr "Criado por" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__create_date +msgid "Created on" +msgstr "Criado em" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_activity +msgid "Data processing activities" +msgstr "Atividades de processamento de dados" + +#. module: privacy_consent +#: model:mail.template,subject:privacy_consent.template_consent +msgid "" +"Data processing consent request for ${object.activity_id.display_name|safe}" +msgstr "" +"Processamento de dados de pedidos de consentimento para ${object.activity_id." +"display_name|safe}" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__display_name +msgid "Display Name" +msgstr "Nome a Exibir" + +#. module: privacy_consent +#: selection:privacy.consent,state:0 +msgid "Draft" +msgstr "Rascunho" + +#. module: privacy_consent +#: sql_constraint:privacy.consent:0 +msgid "Duplicated partner in this data processing activity" +msgstr "Parceiro duplicado nesta atividade de processamento de dados" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_mail_template +msgid "Email Templates" +msgstr "Modelos de E-mail" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__consent_template_id +msgid "Email template" +msgstr "Modelo de Email" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__consent_template_id +msgid "" +"Email to be sent to subjects to ask for consent. A good template should " +"include details about the current consent request status, how to change it, " +"and where to get more information." +msgstr "" +"Email a ser enviado para os titulares a pedir o consentimento. Um bom modelo " +"deve incluir detalhes sobre o estado atual do pedido de consentimento, como " +"alterá-lo, e onde obter ais informação." + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__consent_required +msgid "" +"Enable if you need to track any kind of consent from the affected subjects" +msgstr "" +"Ativar se necessita seguir qualquer espécie de consentimento dos titulares " +"afetados" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_channel_ids +msgid "Followers (Channels)" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +#, fuzzy +msgid "Generate and enqueue missing consent requests" +msgstr "Gerar e enviar pedidos de consentimento em falta" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate missing draft consent requests" +msgstr "Gerar pedidos de consentimento em rascunho em falta" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:139 +#, python-format +msgid "Generated consents" +msgstr "Consentimentos gerados" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Group By" +msgstr "Agrupar Por" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Hello," +msgstr "Olá" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "I accept this processing of my data" +msgstr "Eu aceito este processamento dos meus dados" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "I reject this processing of my data" +msgstr "Eu rejeito este processamento dos meus dados" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__id +msgid "ID" +msgstr "ID" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_unread +msgid "If checked new messages require your attention." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "If it was a mistake, you can undo it here:" +msgstr "Se foi um lapso, pode revertê-lo aqui:" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__accepted +msgid "" +"Indicates current acceptance status, which can come from subject's last " +"answer, or from the default specified in the related data processing " +"activity." +msgstr "" +"Indica o estado atual da aceitação, que pode derivar da última resposta do " +"titular, ou estar predefinida nos dados relacionados contidos na atividade " +"em processamento." + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__last_metadata +#, fuzzy +msgid "Last Metadata" +msgstr "Últimos Metadados" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent____last_update +msgid "Last Modified on" +msgstr "Última Modificação em" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__write_uid +msgid "Last Updated by" +msgstr "Última Atualização por" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__write_date +msgid "Last Updated on" +msgstr "Última Atualização em" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Manually" +msgstr "Manualmente" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_ids +msgid "Messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__last_metadata +msgid "Metadata from the last acceptance or rejection by the subject" +msgstr "Metadados da última aceitação ou rejeição pelo titular" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/mail_template.py:24 +#, python-format +msgid "" +"Missing privacy consent link placeholders. You need at least these two " +"links:\n" +"Accept\n" +"Reject" +msgstr "" +"Espaços reservados aos links de consentimento de privacidade em falta. " +"Necessita pelo menos destes dois links:\n" +"Aceito\n" +"Rejeito" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_consent_new +#: model:mail.message.subtype,name:privacy_consent.mt_consent_consent_new +msgid "New Consent" +msgstr "Novo Consentimento" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_has_error_counter +msgid "Number of error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_needaction_counter +msgid "Number of messages which requires an action" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__message_unread_counter +msgid "Number of unread messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_mail_mail +msgid "Outgoing Mails" +msgstr "Mensagens a Enviar" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_acceptance_changed +msgid "Privacy consent request acceptance status changed" +msgstr "Estado de aceitação do pedido de consentimento de privacidade alterado" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_consent_new +#: model:mail.message.subtype,description:privacy_consent.mt_consent_consent_new +msgid "Privacy consent request created" +msgstr "Pedido de consentimento de privacidade criado" + +#. module: privacy_consent +#: model:mail.message.subtype,description:privacy_consent.mt_activity_state_changed +#: model:mail.message.subtype,description:privacy_consent.mt_consent_state_changed +msgid "Privacy consent request state changed" +msgstr "Estado do pedido de consentimento de privacidade alterado" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_res_partner__privacy_consent_count +#: model:ir.model.fields,help:privacy_consent.field_res_users__privacy_consent_count +msgid "Privacy consent requests amount" +msgstr "Número de pedidos de consentimento de privacidade" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_res_partner__privacy_consent_ids +#: model:ir.model.fields,field_description:privacy_consent.field_res_users__privacy_consent_ids +msgid "Privacy consents" +msgstr "Consentimentos de privacidade" + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.cron_auto_consent_ir_actions_server +#: model:ir.cron,cron_name:privacy_consent.cron_auto_consent +#: model:ir.cron,name:privacy_consent.cron_auto_consent +msgid "Request automatic data processing consents" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:99 +#, python-format +msgid "Require consent is available only for subjects in current database." +msgstr "" +"Requerer consentimento, só está disponível para titulares da base de dados " +"atual." + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__server_action_id +msgid "" +"Run this action when a new consent request is created or its acceptance " +"status is updated." +msgstr "" +"Execute esta ação quando um novo pedido de consentimento for criado ou seu " +"estado de aceitação for atualizado." + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity__server_action_id +msgid "Server action" +msgstr "Ação do servidor" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_activity__default_consent +msgid "Should we assume the subject has accepted if we receive no response?" +msgstr "" +"Devemos assumir que o titular dos dados aceitou, se não houver resposta?" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Sincerely,
" +msgstr "Cumprimentos,
" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:91 +#, python-format +msgid "Specify a mail template to ask automated consent." +msgstr "" +"Especifique um modelo de email para pedido automático de consentimento." + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__state +#: model_terms:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "State" +msgstr "Estado" + +#. module: privacy_consent +#: model:mail.message.subtype,name:privacy_consent.mt_activity_state_changed +#: model:mail.message.subtype,name:privacy_consent.mt_consent_state_changed +msgid "State Changed" +msgstr "Estado Alterado" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__partner_id +msgid "Subject" +msgstr "Titular dos dados" + +#. module: privacy_consent +#: model:ir.model.fields,help:privacy_consent.field_privacy_consent__partner_id +msgid "Subject asked for consent." +msgstr "Foi pedido consentimento ao titular." + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.sync_blacklist +msgid "Sync partner's email blacklist status" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Thank you!" +msgstr "Obrigado!" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "Thanks for your response." +msgstr "Obrigado pela sua resposta." + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.activity_form +#, fuzzy +msgid "This could enqueue many consent emails, are you sure to proceed?" +msgstr "" +"Atenção, esta operação pode enviar múltiplo emails de consentimento pretende " +"prosseguir?" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_unread +msgid "Unread Messages" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent__message_unread_counter +msgid "Unread Messages Counter" +msgstr "" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "" +"We asked you to authorize us to process your data in this data processing " +"activity:" +msgstr "" +"Pedimos-lhe que nos desse autorização para processarmos os seus dados nesta " +"atividade de processamento:" + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "We have recorded this action on your side." +msgstr "Registámos esta ação com seu conhecimento." + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "You have rejected such processing." +msgstr "Você rejeitou este processamento." + +#. module: privacy_consent +#: model_terms:ir.ui.view,arch_db:privacy_consent.form +msgid "You have accepted such processing." +msgstr "Você aceitou este processamento." + +#~ msgid "Partner" +#~ msgstr "Parceiro" + +#~ msgid "Update partner's opt out" +#~ msgstr "Atualizar a Auto Exclusão do parceiro" + +#~ msgid "Email composition wizard" +#~ msgstr "Assistente de criação de email" diff --git a/privacy_consent/models/__init__.py b/privacy_consent/models/__init__.py new file mode 100644 index 0000000..e776de3 --- /dev/null +++ b/privacy_consent/models/__init__.py @@ -0,0 +1,5 @@ +from . import mail_mail +from . import mail_template +from . import privacy_activity +from . import privacy_consent +from . import res_partner diff --git a/privacy_consent/models/mail_mail.py b/privacy_consent/models/mail_mail.py new file mode 100644 index 0000000..6b49211 --- /dev/null +++ b/privacy_consent/models/mail_mail.py @@ -0,0 +1,62 @@ +# Copyright 2018 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class MailMail(models.Model): + _inherit = "mail.mail" + + def _postprocess_sent_message( + self, success_pids, failure_reason=False, failure_type=None + ): + """Write consent status after sending message.""" + # Know if mail was successfully sent to a privacy consent + res_ids = [] + for mail in self: + if ( + mail.mail_message_id.model == "privacy.consent" + and mail.state == "sent" + and success_pids + and not failure_reason + and not failure_type + ): + res_ids.append(mail.mail_message_id.res_id) + consents = self.env["privacy.consent"].search( + [ + ("id", "in", res_ids), + ("state", "=", "draft"), + ("partner_id", "in", [par.id for par in success_pids]), + ] + ) + consents.write({"state": "sent"}) + return super()._postprocess_sent_message( + success_pids=success_pids, + failure_reason=failure_reason, + failure_type=failure_type, + ) + + def _send_prepare_body(self): + """Replace privacy consent magic links. + + This replacement is done here instead of directly writing it into + the ``mail.template`` to avoid writing the tokeinzed URL + in the mail thread for the ``privacy.consent`` record, + which would enable any reader of such thread to impersonate the + subject and choose in its behalf. + """ + result = super(MailMail, self)._send_prepare_body() + # Avoid polluting other model mails + if self.model != "privacy.consent": + return result + # Tokenize consent links + consent = self.env["privacy.consent"].browse(self.mail_message_id.res_id) + result = result.replace( + "/privacy/consent/accept/", + consent._url(True), + ) + result = result.replace( + "/privacy/consent/reject/", + consent._url(False), + ) + return result diff --git a/privacy_consent/models/mail_template.py b/privacy_consent/models/mail_template.py new file mode 100644 index 0000000..fa1d704 --- /dev/null +++ b/privacy_consent/models/mail_template.py @@ -0,0 +1,37 @@ +# Copyright 2018 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from lxml import html + +from odoo import _, api, models +from odoo.exceptions import ValidationError + + +class MailTemplate(models.Model): + _inherit = "mail.template" + + @api.constrains("body_html", "model") + def _check_consent_links_in_body_html(self): + """Body for ``privacy.consent`` templates needs placeholder links.""" + links = [ + "//a[@href='/privacy/consent/{}/']".format(action) + for action in ("accept", "reject") + ] + for one in self: + if one.model != "privacy.consent": + continue + doc = html.document_fromstring(one.body_html) + for link in links: + if not doc.xpath(link): + raise ValidationError( + _( + "Missing privacy consent link placeholders. " + "You need at least these two links:\n" + 'Accept\n' + 'Reject' + ) + % ( + "/privacy/consent/accept/", + "/privacy/consent/reject/", + ) + ) diff --git a/privacy_consent/models/privacy_activity.py b/privacy_consent/models/privacy_activity.py new file mode 100644 index 0000000..ea79f7b --- /dev/null +++ b/privacy_consent/models/privacy_activity.py @@ -0,0 +1,145 @@ +# Copyright 2018 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError +from odoo.tools.safe_eval import safe_eval + + +class PrivacyActivity(models.Model): + _inherit = "privacy.activity" + + server_action_id = fields.Many2one( + "ir.actions.server", + "Server action", + domain=[("model_id.model", "=", "privacy.consent")], + help="Run this action when a new consent request is created or its " + "acceptance status is updated.", + ) + consent_ids = fields.One2many( + "privacy.consent", + "activity_id", + "Consents", + ) + consent_count = fields.Integer( + "Consents count", + compute="_compute_consent_count", + ) + consent_required = fields.Selection( + [("auto", "Automatically"), ("manual", "Manually")], + "Ask subjects for consent", + help="Enable if you need to track any kind of consent " + "from the affected subjects", + ) + consent_template_id = fields.Many2one( + "mail.template", + "Email template", + default=lambda self: self._default_consent_template_id(), + domain=[("model", "=", "privacy.consent")], + help="Email to be sent to subjects to ask for consent. " + "A good template should include details about the current " + "consent request status, how to change it, and where to " + "get more information.", + ) + default_consent = fields.Boolean( + "Accepted by default", + help="Should we assume the subject has accepted if we receive no " "response?", + ) + + # Hidden helpers help user design new templates + consent_template_default_body_html = fields.Text( + compute="_compute_consent_template_defaults", + ) + consent_template_default_subject = fields.Char( + compute="_compute_consent_template_defaults", + ) + + @api.model + def _default_consent_template_id(self): + return self.env.ref("privacy_consent.template_consent", False) + + @api.depends("consent_ids") + def _compute_consent_count(self): + self.consent_count = 0 + groups = self.env["privacy.consent"].read_group( + [("activity_id", "in", self.ids)], + ["activity_id"], + ["activity_id"], + ) + for group in groups: + self.browse(group["activity_id"][0]).consent_count = group[ + "activity_id_count" + ] + + def _compute_consent_template_defaults(self): + """Used in context values, to help users design new templates.""" + template = self._default_consent_template_id() + if template: + self.update( + { + "consent_template_default_body_html": template.body_html, + "consent_template_default_subject": template.subject, + } + ) + + @api.constrains("consent_required", "consent_template_id") + def _check_auto_consent_has_template(self): + """Require a mail template to automate consent requests.""" + for one in self: + if one.consent_required == "auto" and not one.consent_template_id: + raise ValidationError( + _("Specify a mail template to ask automated consent.") + ) + + @api.constrains("consent_required", "subject_find") + def _check_consent_required_subject_find(self): + for one in self: + if one.consent_required and not one.subject_find: + raise ValidationError( + _( + "Require consent is available only for subjects " + "in current database." + ) + ) + + @api.model + def _cron_new_consents(self): + """Ask all missing automatic consent requests.""" + automatic = self.search([("consent_required", "=", "auto")]) + automatic.action_new_consents() + + @api.onchange("consent_required") + def _onchange_consent_required_subject_find(self): + """Find subjects automatically if we require their consent.""" + if self.consent_required: + self.subject_find = True + + def action_new_consents(self): + """Generate new consent requests.""" + consents_vals = [] + # Skip activitys where consent is not required + for one in self.with_context(active_test=False).filtered("consent_required"): + domain = [ + ("id", "not in", one.mapped("consent_ids.partner_id").ids), + ("email", "!=", False), + ] + safe_eval(one.subject_domain) + # Store values for creating missing consent requests + for missing in self.env["res.partner"].search(domain): + consents_vals.append( + { + "partner_id": missing.id, + "accepted": one.default_consent, + "activity_id": one.id, + } + ) + # Create and send consent request emails for automatic activitys + consents = self.env["privacy.consent"].create(consents_vals) + consents.action_auto_ask() + # Redirect user to new consent requests generated + return { + "domain": [("id", "in", consents.ids)], + "name": _("Generated consents"), + "res_model": consents._name, + "type": "ir.actions.act_window", + "view_mode": "tree,form", + } diff --git a/privacy_consent/models/privacy_consent.py b/privacy_consent/models/privacy_consent.py new file mode 100644 index 0000000..0311554 --- /dev/null +++ b/privacy_consent/models/privacy_consent.py @@ -0,0 +1,186 @@ +# Copyright 2018 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import hashlib +import hmac + +from odoo import api, fields, models + + +class PrivacyConsent(models.Model): + _name = "privacy.consent" + _description = "Consent of data processing" + _inherit = "mail.thread" + _rec_name = "partner_id" + _sql_constraints = [ + ( + "unique_partner_activity", + "UNIQUE(partner_id, activity_id)", + "Duplicated partner in this data processing activity", + ), + ] + + active = fields.Boolean( + default=True, + index=True, + ) + accepted = fields.Boolean( + track_visibility="onchange", + help="Indicates current acceptance status, which can come from " + "subject's last answer, or from the default specified in the " + "related data processing activity.", + ) + last_metadata = fields.Text( + readonly=True, + track_visibility="onchange", + help="Metadata from the last acceptance or rejection by the subject", + ) + partner_id = fields.Many2one( + "res.partner", + "Subject", + required=True, + readonly=True, + track_visibility="onchange", + help="Subject asked for consent.", + ) + activity_id = fields.Many2one( + "privacy.activity", + "Activity", + readonly=True, + required=True, + track_visibility="onchange", + ) + state = fields.Selection( + selection=[ + ("draft", "Draft"), + ("sent", "Awaiting response"), + ("answered", "Answered"), + ], + default="draft", + readonly=True, + required=True, + track_visibility="onchange", + ) + + def _creation_subtype(self): + return self.env.ref("privacy_consent.mt_consent_consent_new") + + def _track_subtype(self, init_values): + """Return specific subtypes.""" + if self.env.context.get("subject_answering"): + return self.env.ref("privacy_consent.mt_consent_acceptance_changed") + if "state" in init_values: + return self.env.ref("privacy_consent.mt_consent_state_changed") + return super(PrivacyConsent, self)._track_subtype(init_values) + + def _token(self): + """Secret token to publicly authenticate this record.""" + secret = self.env["ir.config_parameter"].sudo().get_param("database.secret") + params = "{}-{}-{}-{}".format( + self.env.cr.dbname, + self.id, + self.partner_id.id, + self.activity_id.id, + ) + return hmac.new( + secret.encode("utf-8"), + params.encode("utf-8"), + hashlib.sha512, + ).hexdigest() + + def _url(self, accept): + """Tokenized URL to let subject decide consent. + + :param bool accept: + Indicates if you want the acceptance URL, or the rejection one. + """ + return "/privacy/consent/{}/{}/{}?db={}".format( + "accept" if accept else "reject", + self.id, + self._token(), + self.env.cr.dbname, + ) + + def _send_consent_notification(self): + """Send email notification to subject.""" + for one in self.with_context( + tpl_force_default_to=True, + mail_notify_user_signature=False, + mail_auto_subscribe_no_notify=True, + ): + one.activity_id.consent_template_id.send_mail(one.id) + + def _run_action(self): + """Execute server action defined in data processing activity.""" + for one in self: + # Always skip draft consents + if one.state == "draft": + continue + action = one.activity_id.server_action_id.with_context( + active_id=one.id, + active_ids=one.ids, + active_model=one._name, + ) + action.run() + + @api.model_create_multi + def create(self, vals_list): + """Run server action on create.""" + results = super().create(vals_list) + # Sync the default acceptance status + results._run_action() + return results + + def write(self, vals): + """Run server action on update.""" + result = super().write(vals) + self._run_action() + return result + + def message_get_suggested_recipients(self): + result = super().message_get_suggested_recipients() + reason = self._fields["partner_id"].string + for one in self: + one._message_add_suggested_recipient( + result, + partner=one.partner_id, + reason=reason, + ) + return result + + def action_manual_ask(self): + """Let user manually ask for consent.""" + return { + "context": { + "default_composition_mode": "comment", + "default_model": self._name, + "default_res_id": self.id, + "default_template_id": self.activity_id.consent_template_id.id, + "default_use_template": True, + "tpl_force_default_to": True, + }, + "force_email": True, + "res_model": "mail.compose.message", + "target": "new", + "type": "ir.actions.act_window", + "view_mode": "form", + } + + def action_auto_ask(self): + """Automatically ask for consent.""" + templated = self.filtered("activity_id.consent_template_id") + automated = templated.filtered( + lambda one: one.activity_id.consent_required == "auto" + ) + automated._send_consent_notification() + + def action_answer(self, answer, metadata=False): + """Process answer. + + :param bool answer: + Did the subject accept? + + :param str metadata: + Metadata from last user acceptance or rejection request. + """ + self.write({"state": "answered", "accepted": answer, "last_metadata": metadata}) diff --git a/privacy_consent/models/res_partner.py b/privacy_consent/models/res_partner.py new file mode 100644 index 0000000..162b8a3 --- /dev/null +++ b/privacy_consent/models/res_partner.py @@ -0,0 +1,33 @@ +# Copyright 2018 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + privacy_consent_ids = fields.One2many( + "privacy.consent", + "partner_id", + "Privacy consents", + ) + privacy_consent_count = fields.Integer( + "Consents", + compute="_compute_privacy_consent_count", + help="Privacy consent requests amount", + ) + + @api.depends("privacy_consent_ids") + def _compute_privacy_consent_count(self): + """Count consent requests.""" + self.privacy_consent_count = 0 + groups = self.env["privacy.consent"].read_group( + [("partner_id", "in", self.ids)], + ["partner_id"], + ["partner_id"], + ) + for group in groups: + self.browse(group["partner_id"][0]).privacy_consent_count = group[ + "partner_id_count" + ] diff --git a/privacy_consent/readme/CONTRIBUTORS.rst b/privacy_consent/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..289406f --- /dev/null +++ b/privacy_consent/readme/CONTRIBUTORS.rst @@ -0,0 +1,7 @@ +* `Tecnativa `_: + + * Jairo Llopis + +* `initOS GmbH `_: + + * Florian Kantelberg diff --git a/privacy_consent/readme/DESCRIPTION.rst b/privacy_consent/readme/DESCRIPTION.rst new file mode 100644 index 0000000..dfce06f --- /dev/null +++ b/privacy_consent/readme/DESCRIPTION.rst @@ -0,0 +1,7 @@ +This module allows the user to define a set of subjects (partners) +affected by any data processing activity, and establish +a process to ask them for consent to include them in that activity. + +For those that need explicit consent as a lawfulness base for personal data +processing, as required by GDPR (article 6.1.a), this module provides the +needed tools to automate it. diff --git a/privacy_consent/readme/INSTALL.rst b/privacy_consent/readme/INSTALL.rst new file mode 100644 index 0000000..dabd03d --- /dev/null +++ b/privacy_consent/readme/INSTALL.rst @@ -0,0 +1,15 @@ +You may want to install, along with this module, one of OCA's +``mail_tracking`` module collection, such as ``mail_tracking_mailgun``, so +you can provide more undeniable proof that some consent request was sent, and +to whom. + +However, the most important proof to provide is the answer itself (more than +the question), and this addon provides enough tooling for that. + +Multi-database instances +~~~~~~~~~~~~~~~~~~~~~~~~ + +To enable multi-database support, you must load this addon as a server-wide +addon. Example command to boot Odoo:: + + odoo-bin --load=web,privacy_consent diff --git a/privacy_consent/readme/USAGE.rst b/privacy_consent/readme/USAGE.rst new file mode 100644 index 0000000..e621578 --- /dev/null +++ b/privacy_consent/readme/USAGE.rst @@ -0,0 +1,69 @@ +New options for data processing activities: + +#. Go to *Privacy > Master Data > Activities* and create one. + +#. Give it a name, such as *Sending mass mailings to customers*. + +#. Go to tab *Consent* and choose one option in *Ask subjects for consent*: + + * *Manual* tells the activity that you will want to create and send the + consent requests manually, and only provides some helpers for you to + be able to batch-generate them. + + * *Automatic* enables this module's full power: send all consent requests + to selected partners automatically, every day and under your demand. + +#. When you do this, all the consent-related options appear. Configure them: + + * A smart button tells you how many consents have been generated, and lets you + access them. + + * Choose one *Email template* to send to subjects. This email itself is what + asks for consent, and it gets recorded, to serve as a proof that it was sent. + The module provides a default template that should be good for most usage + cases; and if you create one directly from that field, some good defaults + are provided for your comfortability. + + * *Subjects filter* defines what partners will be elegible for inclusion in + this data processing activity. + + * You can enable *Accepted by default* if you want to assume subjects + accepted their data processing. You should possibly consult your + lawyer to use this. + + * You can choose a *Server action* (developer mode only) that will + be executed whenever a new non-draft consent request is created, + or when its acceptance status changes. + + This module supplies a server action by default, called + *Update partner's opt out*, that syncs the acceptance status with the + partner's *Elegible for mass mailings* option. + +#. Click on *Generate consent requests* link to create new consent requests. + + * If you chose *Manual* mode, all missing consent request are created as + drafts, and nothing else is done now. + + * If you chose *Automatic* mode, also those request e-mails are enqueued + and, when the mail queue is cleared, they will be set as *Sent*. + +#. You will be presented with the list of just-created consent requests. + See below. + +New options for consent requests: + +#. Access the consent requests by either: + + * Generating new consent requests from a data processing activity. + + * Pressing the *Consents* smart button in a data processing activity. + + * Going to *Privacy > Privacy > Consents*. + +#. A consent will include the partner, the activity, the acceptance status, + and the request state. + +#. You can manually ask for consent by pressing the button labeled as + *Ask for consent*. + +#. All consent requests and responses are recorded in the mail thread below. diff --git a/privacy_consent/security/ir.model.access.csv b/privacy_consent/security/ir.model.access.csv new file mode 100644 index 0000000..28285e4 --- /dev/null +++ b/privacy_consent/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +privacy_consent_read,Permission to read consents,model_privacy_consent,privacy.group_data_protection_user,1,0,0,0 +privacy_consent_write,Permission to write consents,model_privacy_consent,privacy.group_data_protection_manager,1,1,1,1 diff --git a/privacy_consent/static/description/icon.png b/privacy_consent/static/description/icon.png new file mode 100644 index 0000000..3a0328b Binary files /dev/null and b/privacy_consent/static/description/icon.png differ diff --git a/privacy_consent/static/description/index.html b/privacy_consent/static/description/index.html new file mode 100644 index 0000000..4515480 --- /dev/null +++ b/privacy_consent/static/description/index.html @@ -0,0 +1,525 @@ + + + + + + +Privacy - Consent + + + + + + diff --git a/privacy_consent/static/src/css/privacy_consent.scss b/privacy_consent/static/src/css/privacy_consent.scss new file mode 100644 index 0000000..605268a --- /dev/null +++ b/privacy_consent/static/src/css/privacy_consent.scss @@ -0,0 +1,7 @@ +/* Copyright 2020 Tecnativa - Jairo Llopis + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */ + +.o_consent_form { + // Need !important to override an inline style of max-width: 300px + max-width: 100% !important; +} diff --git a/privacy_consent/templates/assets.xml b/privacy_consent/templates/assets.xml new file mode 100644 index 0000000..de1c77f --- /dev/null +++ b/privacy_consent/templates/assets.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/privacy_consent/templates/form.xml b/privacy_consent/templates/form.xml new file mode 100644 index 0000000..9bacb35 --- /dev/null +++ b/privacy_consent/templates/form.xml @@ -0,0 +1,63 @@ + + + + + diff --git a/privacy_consent/tests/__init__.py b/privacy_consent/tests/__init__.py new file mode 100644 index 0000000..42ba786 --- /dev/null +++ b/privacy_consent/tests/__init__.py @@ -0,0 +1 @@ +from . import test_consent diff --git a/privacy_consent/tests/test_consent.py b/privacy_consent/tests/test_consent.py new file mode 100644 index 0000000..1db8ecf --- /dev/null +++ b/privacy_consent/tests/test_consent.py @@ -0,0 +1,291 @@ +# Copyright 2018 Tecnativa - Jairo Llopis +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from contextlib import contextmanager + +from odoo.exceptions import ValidationError +from odoo.tests.common import Form, HttpCase + + +class ActivityCase(HttpCase): + def setUp(self): + super(ActivityCase, self).setUp() + self.cron = self.env.ref("privacy_consent.cron_auto_consent") + self.cron_mail_queue = self.env.ref("mail.ir_cron_mail_scheduler_action") + self.sync_blacklist = self.env.ref("privacy_consent.sync_blacklist") + self.mt_consent_consent_new = self.env.ref( + "privacy_consent.mt_consent_consent_new" + ) + self.mt_consent_acceptance_changed = self.env.ref( + "privacy_consent.mt_consent_acceptance_changed" + ) + self.mt_consent_state_changed = self.env.ref( + "privacy_consent.mt_consent_state_changed" + ) + # Some partners to ask for consent + self.partners = self.env["res.partner"] + self.partners += self.partners.create( + {"name": "consent-partner-0", "email": "partner0@example.com"} + ) + self.partners += self.partners.create( + {"name": "consent-partner-1", "email": "partner1@example.com"} + ) + self.partners += self.partners.create( + {"name": "consent-partner-2", "email": "partner2@example.com"} + ) + # Partner without email, on purpose + self.partners += self.partners.create({"name": "consent-partner-3"}) + # Partner with wrong email, on purpose + self.partners += self.partners.create( + {"name": "consent-partner-4", "email": "wrong-mail"} + ) + # Blacklist some partners + self.blacklists = self.env["mail.blacklist"] + self.blacklists += self.blacklists._add("partner1@example.com") + # Activity without consent + self.activity_noconsent = self.env["privacy.activity"].create( + {"name": "activity_noconsent", "description": "I'm activity 1"} + ) + # Activity with auto consent, for all partners + self.activity_auto = self.env["privacy.activity"].create( + { + "name": "activity_auto", + "description": "I'm activity auto", + "subject_find": True, + "subject_domain": repr([("id", "in", self.partners.ids)]), + "consent_required": "auto", + "default_consent": True, + "server_action_id": self.sync_blacklist.id, + } + ) + # Activity with manual consent, skipping partner 0 + self.activity_manual = self.env["privacy.activity"].create( + { + "name": "activity_manual", + "description": "I'm activity 3", + "subject_find": True, + "subject_domain": repr([("id", "in", self.partners[1:].ids)]), + "consent_required": "manual", + "default_consent": False, + "server_action_id": self.sync_blacklist.id, + } + ) + + @contextmanager + def _patch_build(self): + self._built_messages = [] + IMS = self.env["ir.mail_server"] + + def _build_email(_self, email_from, email_to, subject, body, *args, **kwargs): + self._built_messages.append(body) + return _build_email.origin( + _self, + email_from, + email_to, + subject, + body, + *args, + **kwargs, + ) + + try: + IMS._patch_method("build_email", _build_email) + yield + finally: + IMS._revert_method("build_email") + + def check_activity_auto_properly_sent(self): + """Check emails sent by ``self.activity_auto``.""" + consents = self.env["privacy.consent"].search( + [("activity_id", "=", self.activity_auto.id)] + ) + # Check pending mails + for consent in consents: + self.assertEqual(consent.state, "draft") + messages = consent.message_ids + self.assertEqual(len(messages), 2) + # Check sent mails + with self._patch_build(): + self.cron_mail_queue.method_direct_trigger() + for consent in consents: + good_email = "@" in (consent.partner_id.email or "") + expected_messages = 3 if good_email else 2 + self.assertEqual( + consent.state, + "sent" if good_email else "draft", + ) + messages = consent.message_ids + self.assertEqual(len(messages), expected_messages) + # 2nd message notifies creation + self.assertEqual( + messages[expected_messages - 1].subtype_id, + self.mt_consent_consent_new, + ) + # 3rd message notifies subject + # Placeholder links should be logged + self.assertIn( + "/privacy/consent/accept/", messages[expected_messages - 2].body + ) + self.assertIn( + "/privacy/consent/reject/", messages[expected_messages - 2].body + ) + # Tokenized links shouldn't be logged + self.assertNotIn(consent._url(True), messages[expected_messages - 2].body) + self.assertNotIn(consent._url(False), messages[expected_messages - 2].body) + # 4th message contains the state change + if good_email: + self.assertEqual( + messages[0].subtype_id, + self.mt_consent_state_changed, + ) + # Partner's is_blacklisted should be synced with default consent + self.assertFalse(consent.partner_id.is_blacklisted) + # Check the sent message was built properly tokenized + accept_url, reject_url = map(consent._url, (True, False)) + for body in self._built_messages: + if accept_url in body and reject_url in body: + self._built_messages.remove(body) + break + else: + raise AssertionError("Some message body should have these urls") + + def test_default_template(self): + """We have a good mail template by default.""" + good = self.env.ref("privacy_consent.template_consent") + self.assertEqual( + self.activity_noconsent.consent_template_id, + good, + ) + self.assertEqual( + self.activity_noconsent.consent_template_default_body_html, + good.body_html, + ) + self.assertEqual( + self.activity_noconsent.consent_template_default_subject, + good.subject, + ) + + def test_find_subject_if_consent_required(self): + """If user wants to require consent, it needs subjects.""" + # Test the onchange helper + onchange_activity1 = self.env["privacy.activity"].new( + self.activity_noconsent.copy_data()[0] + ) + self.assertFalse(onchange_activity1.subject_find) + onchange_activity1.consent_required = "auto" + onchange_activity1._onchange_consent_required_subject_find() + self.assertTrue(onchange_activity1.subject_find) + # Test very dumb user that forces an error + with self.assertRaises(ValidationError): + self.activity_noconsent.consent_required = "manual" + + def test_template_required_auto(self): + """Automatic consent activities need a template.""" + self.activity_noconsent.subject_find = True + self.activity_noconsent.consent_template_id = False + self.activity_noconsent.consent_required = "manual" + with self.assertRaises(ValidationError): + self.activity_noconsent.consent_required = "auto" + + def test_generate_manually(self): + """Manually-generated consents work as expected.""" + for partner in self.partners: + if "@" in (partner.email or ""): + self.blacklists._remove(partner.email) + result = self.activity_manual.action_new_consents() + self.assertEqual(result["res_model"], "privacy.consent") + consents = self.env[result["res_model"]].search(result["domain"]) + self.assertEqual(consents.mapped("state"), ["draft"] * 3) + self.assertEqual( + consents.mapped("partner_id.is_blacklisted"), + [False] * 3, + ) + self.assertEqual(consents.mapped("accepted"), [False] * 3) + self.assertEqual(consents.mapped("last_metadata"), [False] * 3) + # Check sent mails + messages = consents.mapped("message_ids") + self.assertEqual(len(messages), 3) + subtypes = messages.mapped("subtype_id") + self.assertTrue(subtypes & self.mt_consent_consent_new) + self.assertFalse(subtypes & self.mt_consent_acceptance_changed) + self.assertFalse(subtypes & self.mt_consent_state_changed) + # Send one manual request + action = consents[0].action_manual_ask() + self.assertEqual(action["res_model"], "mail.compose.message") + Composer = self.env[action["res_model"]].with_context( + active_ids=consents[0].ids, + active_model=consents._name, + **action["context"], + ) + composer_wizard = Form(Composer) + self.assertIn(consents[0].partner_id.name, composer_wizard.body) + composer_record = composer_wizard.save() + with self._patch_build(): + composer_record.send_mail() + # Check the sent message was built properly tokenized + body = self._built_messages[0] + self.assertIn(consents[0]._url(True), body) + self.assertIn(consents[0]._url(False), body) + messages = consents.mapped("message_ids") - messages + self.assertEqual(len(messages), 2) + self.assertEqual(messages[0].subtype_id, self.mt_consent_state_changed) + self.assertEqual(consents.mapped("state"), ["sent", "draft", "draft"]) + self.assertEqual( + consents.mapped("partner_id.is_blacklisted"), + [True, False, False], + ) + # Placeholder links should be logged + self.assertTrue("/privacy/consent/accept/" in messages[1].body) + self.assertTrue("/privacy/consent/reject/" in messages[1].body) + # Tokenized links shouldn't be logged + accept_url = consents[0]._url(True) + reject_url = consents[0]._url(False) + self.assertNotIn(accept_url, messages[1].body) + self.assertNotIn(reject_url, messages[1].body) + # Visit tokenized accept URL + result = self.url_open(accept_url).text + self.assertIn("accepted", result) + self.assertIn(reject_url, result) + self.assertIn(self.activity_manual.name, result) + self.assertIn(self.activity_manual.description, result) + consents.invalidate_cache() + self.assertEqual(consents.mapped("accepted"), [True, False, False]) + self.assertTrue(consents[0].last_metadata) + self.assertFalse(consents[0].partner_id.is_blacklisted) + self.assertEqual(consents.mapped("state"), ["answered", "draft", "draft"]) + self.assertEqual( + consents[0].message_ids[0].subtype_id, + self.mt_consent_acceptance_changed, + ) + # Visit tokenized reject URL + result = self.url_open(reject_url).text + self.assertIn("rejected", result) + self.assertIn(accept_url, result) + self.assertIn(self.activity_manual.name, result) + self.assertIn(self.activity_manual.description, result) + consents.invalidate_cache() + self.assertEqual(consents.mapped("accepted"), [False, False, False]) + self.assertTrue(consents[0].last_metadata) + self.assertTrue(consents[0].partner_id.is_blacklisted) + self.assertEqual(consents.mapped("state"), ["answered", "draft", "draft"]) + self.assertEqual( + consents[0].message_ids[0].subtype_id, + self.mt_consent_acceptance_changed, + ) + self.assertFalse(consents[1].last_metadata) + + def test_generate_automatically(self): + """Automatically-generated consents work as expected.""" + result = self.activity_auto.action_new_consents() + self.assertEqual(result["res_model"], "privacy.consent") + self.check_activity_auto_properly_sent() + + def test_generate_cron(self): + """Cron-generated consents work as expected.""" + self.cron.method_direct_trigger() + self.check_activity_auto_properly_sent() + + def test_mail_template_without_links(self): + """Cannot create mail template without needed links.""" + with self.assertRaises(ValidationError): + self.activity_manual.consent_template_id.body_html = "No links :(" diff --git a/privacy_consent/views/privacy_activity.xml b/privacy_consent/views/privacy_activity.xml new file mode 100644 index 0000000..c16019d --- /dev/null +++ b/privacy_consent/views/privacy_activity.xml @@ -0,0 +1,76 @@ + + + + + Add consent fields + privacy.activity + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+
diff --git a/privacy_consent/views/privacy_consent.xml b/privacy_consent/views/privacy_consent.xml new file mode 100644 index 0000000..8647d98 --- /dev/null +++ b/privacy_consent/views/privacy_consent.xml @@ -0,0 +1,97 @@ + + + + + Privacy Consent Form + privacy.consent + +
+
+
+ +
+ + +
+ + + + + + +
+
+ + +
+
+
+
+ + Privacy Consent Tree + privacy.consent + + + + + + + + + + + Privacy Consent Search + privacy.consent + + + + + + + + + + + + + + + + + + + +
diff --git a/privacy_consent/views/res_partner.xml b/privacy_consent/views/res_partner.xml new file mode 100644 index 0000000..1af520f --- /dev/null +++ b/privacy_consent/views/res_partner.xml @@ -0,0 +1,28 @@ + + + + + Add consent smart button + res.partner + + + +
+ +
+
+
+
diff --git a/setup/privacy_consent/odoo/addons/privacy_consent b/setup/privacy_consent/odoo/addons/privacy_consent new file mode 120000 index 0000000..f558b8c --- /dev/null +++ b/setup/privacy_consent/odoo/addons/privacy_consent @@ -0,0 +1 @@ +../../../../privacy_consent \ No newline at end of file diff --git a/setup/privacy_consent/setup.py b/setup/privacy_consent/setup.py new file mode 100644 index 0000000..28c57bb --- /dev/null +++ b/setup/privacy_consent/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)