diff --git a/README.md b/README.md index f94ea64..28ac08a 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ addon | version | summary --- | --- | --- [contact_search_form](contact_search_form/) | 11.0.1.0.0 | Multiple models can be searched for specified string by DPO [privacy](privacy/) | 11.0.1.0.0 | Provides data privacy and protection features to comply to regulations, such as GDPR. +[privacy_consent](privacy_consent/) | 11.0.1.0.0 | Allow people to explicitly accept or reject inclusion in some activity, GDPR compliant [privacy_partner_report](privacy_partner_report/) | 11.0.1.0.0 | Show the transactions that a specific partner is involved in. [website_contact_extend](website_contact_extend/) | 11.0.1.0.0 | Extended Website Contact View diff --git a/privacy/views/privacy_activity_view.xml b/privacy/views/privacy_activity_view.xml index 50da021..2642a97 100644 --- a/privacy/views/privacy_activity_view.xml +++ b/privacy/views/privacy_activity_view.xml @@ -42,7 +42,7 @@ 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..a9d388b --- /dev/null +++ b/privacy_consent/__manifest__.py @@ -0,0 +1,28 @@ +# 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": "11.0.1.0.0", + "development_status": "Production/Stable", + "category": "Privacy", + "website": "https://github.com/OCA/management-activity", + "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/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..dddb20b --- /dev/null +++ b/privacy_consent/controllers/main.py @@ -0,0 +1,46 @@ +# 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 + +from odoo.addons.web.controllers.main import ensure_db + + +class ConsentController(Controller): + @route("/privacy/consent//" + "/", + type="http", auth="none", website=True) + def consent(self, choice, consent_id, token, *args, **kwargs): + """Process user's consent acceptance or rejection.""" + ensure_db() + try: + # If there's a website, we need a user to render the template + request.uid = request.website.user_id.id + except AttributeError: + # If there's no website, the default is OK + pass + 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..4e7bc4d --- /dev/null +++ b/privacy_consent/data/ir_actions_server.xml @@ -0,0 +1,16 @@ + + + + + + + Update partner's opt out + + + code + records.mapped('partner_id').write({'opt_out': not record.accepted}) + + + diff --git a/privacy_consent/data/ir_cron.xml b/privacy_consent/data/ir_cron.xml new file mode 100644 index 0000000..72acc37 --- /dev/null +++ b/privacy_consent/data/ir_cron.xml @@ -0,0 +1,18 @@ + + + + + + + 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..f4ab84e --- /dev/null +++ b/privacy_consent/data/mail.xml @@ -0,0 +1,158 @@ + + + + + + + + + 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..463d79d --- /dev/null +++ b/privacy_consent/i18n/de.po @@ -0,0 +1,541 @@ +# 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: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_active +msgid "Active" +msgstr "Aktiv" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent_activity_id +#: model: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:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Archived" +msgstr "Archiviert" + +#. module: privacy_consent +#: model: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 +#: 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:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Consent" +msgstr "Einwilligung" + +#. 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.model.fields,field_description:privacy_consent.field_privacy_activity_consent_template_default_body_html +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 +msgid "Consent template default subject" +msgstr "Standardmäßige Einverständniserklärung Betroffener" + +#. 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_count +#: 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_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.ui.view,arch_db:privacy_consent.activity_form +#, fuzzy +#| msgid "Generate and send missing consent requests" +msgid "Generate and enqueue missing consent requests" +msgstr "Erstellung und Versand fehlender Einwilligungsanfragen" + +#. module: privacy_consent +#: model: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:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Group By" +msgstr "Gruppieren nach" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "Hello," +msgstr "Hallo" + +#. module: privacy_consent +#: model: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: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.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___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_last_metadata +msgid "Last metadata" +msgstr "Letzte Metadaten" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Manually" +msgstr "Manuell" + +#. 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:25 +#, 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,name:privacy_consent.model_mail_mail +msgid "Outgoing Mails" +msgstr "Ausgehende Mails" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_res_partner +msgid "Partner" +msgstr "Partner" + +#. 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 +#: code:addons/privacy_consent/models/privacy_activity.py:100 +#, 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: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:92 +#, 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: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.ui.view,arch_db:privacy_consent.form +msgid "Thank you!" +msgstr "Vielen Dank." + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "Thanks for your response." +msgstr "Vielen Dank für Ihre Antwort." + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.activity_form +#, fuzzy +#| msgid "This could send many consent emails, are you sure to proceed?" +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.actions.server,name:privacy_consent.update_opt_out +msgid "Update partner's opt out" +msgstr "" + +#. module: privacy_consent +#: model: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:ir.ui.view,arch_db:privacy_consent.form +msgid "We have recorded this action on your side." +msgstr "" + +#. module: privacy_consent +#: model: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:ir.ui.view,arch_db:privacy_consent.form +msgid "You have accepted such processing." +msgstr "" +"Du hast dieser Verarbeitungstätigkeit zugestimmt." diff --git a/privacy_consent/i18n/es.po b/privacy_consent/i18n/es.po new file mode 100644 index 0000000..5c47d5f --- /dev/null +++ b/privacy_consent/i18n/es.po @@ -0,0 +1,665 @@ +# 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: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_active +msgid "Active" +msgstr "Activo" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent_activity_id +#: model: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:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Archived" +msgstr "Archivado" + +#. module: privacy_consent +#: model: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 +#: 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:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Consent" +msgstr "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.model.fields,field_description:privacy_consent.field_privacy_activity_consent_template_default_body_html +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 +msgid "Consent template default subject" +msgstr "HTML por defecto para el asunto de la plantilla de consentimiento" + +#. 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_count +#: 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_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,name:privacy_consent.model_mail_compose_message +msgid "Email composition wizard" +msgstr "Asistente de redacción 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.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: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:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Group By" +msgstr "Agrupar por" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "Hello," +msgstr "Hola," + +#. module: privacy_consent +#: model: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: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.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___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_last_metadata +msgid "Last metadata" +msgstr "Últimos metadatos" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Manually" +msgstr "Manualmente" + +#. 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:25 +#, 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,name:privacy_consent.model_mail_mail +msgid "Outgoing Mails" +msgstr "Correos electrónicos salientes" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_res_partner +msgid "Partner" +msgstr "Contacto" + +#. 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 +#: code:addons/privacy_consent/models/privacy_activity.py:100 +#, 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:ir.ui.view,arch_db:privacy_consent.form +msgid "Sincerely,
" +msgstr "Atentamente,
" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:92 +#, 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: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.ui.view,arch_db:privacy_consent.form +msgid "Thank you!" +msgstr "¡Gracias!" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "Thanks for your response." +msgstr "Gracias por su respuesta." + +#. module: privacy_consent +#: model: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.actions.server,name:privacy_consent.update_opt_out +msgid "Update partner's opt out" +msgstr "Sincronizar la opción del contacto para recibir o no envíos masivos" + +#. module: privacy_consent +#: model: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: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:ir.ui.view,arch_db:privacy_consent.form +msgid "You have rejected such processing." +msgstr "Ha rechazado dicho tratamiento." + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "You have accepted such processing." +msgstr "Ha aceptado dicho tratamiento." diff --git a/privacy_consent/i18n/fr.po b/privacy_consent/i18n/fr.po new file mode 100644 index 0000000..31c82d9 --- /dev/null +++ b/privacy_consent/i18n/fr.po @@ -0,0 +1,518 @@ +# 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: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_active +msgid "Active" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent_activity_id +#: model: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:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Archived" +msgstr "" + +#. module: privacy_consent +#: model: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 +#: 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:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Consent" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_privacy_consent +msgid "Consent of data processing" +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.actions.act_window,name:privacy_consent.consent_action +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_activity_consent_count +#: 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_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.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate and send missing consent requests" +msgstr "" + +#. module: privacy_consent +#: model: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:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Group By" +msgstr "" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "Hello," +msgstr "" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "I accept this processing of my data" +msgstr "" + +#. module: privacy_consent +#: model: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.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___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_last_metadata +msgid "Last metadata" +msgstr "" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Manually" +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:25 +#, 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,name:privacy_consent.model_mail_mail +msgid "Outgoing Mails" +msgstr "" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_res_partner +msgid "Partner" +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 +#: code:addons/privacy_consent/models/privacy_activity.py:100 +#, 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:ir.ui.view,arch_db:privacy_consent.form +msgid "Sincerely,
" +msgstr "" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:92 +#, 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: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.ui.view,arch_db:privacy_consent.form +msgid "Thank you!" +msgstr "" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "Thanks for your response." +msgstr "" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "This could send many consent emails, are you sure to proceed?" +msgstr "" + +#. module: privacy_consent +#: model:ir.actions.server,name:privacy_consent.update_opt_out +msgid "Update partner's opt out" +msgstr "" + +#. module: privacy_consent +#: model: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:ir.ui.view,arch_db:privacy_consent.form +msgid "We have recorded this action on your side." +msgstr "" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "You have rejected such processing." +msgstr "" + +#. module: privacy_consent +#: model: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..a444d24 --- /dev/null +++ b/privacy_consent/i18n/privacy_consent.pot @@ -0,0 +1,489 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * privacy_consent +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.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: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_active +msgid "Active" +msgstr "" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent_activity_id +#: model: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:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Archived" +msgstr "" + +#. module: privacy_consent +#: model: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 +#: 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: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_count +#: 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,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.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate and enqueue missing consent requests" +msgstr "" + +#. module: privacy_consent +#: model: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:138 +#, python-format +msgid "Generated consents" +msgstr "" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Group By" +msgstr "" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "Hello," +msgstr "" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "I accept this processing of my data" +msgstr "" + +#. module: privacy_consent +#: model: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.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_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 +#: selection:privacy.activity,consent_required:0 +msgid "Manually" +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,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: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: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.ui.view,arch_db:privacy_consent.form +msgid "Thank you!" +msgstr "" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "Thanks for your response." +msgstr "" + +#. module: privacy_consent +#: model: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.actions.server,name:privacy_consent.update_opt_out +msgid "Update partner's opt out" +msgstr "" + +#. module: privacy_consent +#: model: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:ir.ui.view,arch_db:privacy_consent.form +msgid "We have recorded this action on your side." +msgstr "" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "You have rejected such processing." +msgstr "" + +#. module: privacy_consent +#: model: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..83bdd04 --- /dev/null +++ b/privacy_consent/i18n/pt.po @@ -0,0 +1,650 @@ +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: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_active +msgid "Active" +msgstr "Ativo" + +#. module: privacy_consent +#: model:ir.model.fields,field_description:privacy_consent.field_privacy_consent_activity_id +#: model: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:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Archived" +msgstr "Arquivado" + +#. module: privacy_consent +#: model: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 +#: 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:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "Consent" +msgstr "Consentimento" + +#. 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.model.fields,field_description:privacy_consent.field_privacy_activity_consent_template_default_body_html +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 +msgid "Consent template default subject" +msgstr "Modelo predefinido de consentimento do titular" + +#. 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_count +#: 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_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.ui.view,arch_db:privacy_consent.activity_form +msgid "Generate and send missing consent requests" +msgstr "Gerar e enviar pedidos de consentimento em falta" + +#. module: privacy_consent +#: model: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:ir.ui.view,arch_db:privacy_consent.consent_search +msgid "Group By" +msgstr "Agrupar Por" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "Hello," +msgstr "Olá" + +#. module: privacy_consent +#: model: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: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.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___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_last_metadata +msgid "Last metadata" +msgstr "Últimos Metadados" + +#. module: privacy_consent +#: selection:privacy.activity,consent_required:0 +msgid "Manually" +msgstr "Manualmente" + +#. 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:25 +#, 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,name:privacy_consent.model_mail_mail +msgid "Outgoing Mails" +msgstr "Mensagens a Enviar" + +#. module: privacy_consent +#: model:ir.model,name:privacy_consent.model_res_partner +msgid "Partner" +msgstr "Parceiro" + +#. 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 +#: code:addons/privacy_consent/models/privacy_activity.py:100 +#, 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:ir.ui.view,arch_db:privacy_consent.form +msgid "Sincerely,
" +msgstr "Cumprimentos,
" + +#. module: privacy_consent +#: code:addons/privacy_consent/models/privacy_activity.py:92 +#, 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: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.ui.view,arch_db:privacy_consent.form +msgid "Thank you!" +msgstr "Obrigado!" + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "Thanks for your response." +msgstr "Obrigado pela sua resposta." + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.activity_form +msgid "This could send 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.actions.server,name:privacy_consent.update_opt_out +msgid "Update partner's opt out" +msgstr "Atualizar a Auto Exclusão do parceiro" + +#. module: privacy_consent +#: model: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: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:ir.ui.view,arch_db:privacy_consent.form +msgid "You have rejected such processing." +msgstr "Você rejeitou este processamento." + +#. module: privacy_consent +#: model:ir.ui.view,arch_db:privacy_consent.form +msgid "You have accepted such processing." +msgstr "Você aceitou este processamento." + +#~ 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..cdb0a95 --- /dev/null +++ b/privacy_consent/models/mail_mail.py @@ -0,0 +1,53 @@ +# 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, mail_sent=True): + """Write consent status after sending message.""" + if mail_sent: + # Get all mails sent to consents + consent_mails = self.filtered( + lambda one: one.mail_message_id.model == "privacy.consent" + ) + # Get related draft consents + consents = self.env["privacy.consent"].browse( + consent_mails.mapped("mail_message_id.res_id"), + self._prefetch + ).filtered(lambda one: one.state == "draft") + # Set as sent + consents.write({ + "state": "sent", + }) + return super(MailMail, self)._postprocess_sent_message(mail_sent) + + def send_get_mail_body(self, partner=None): + """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_get_mail_body(partner=partner) + # 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) \ + .with_prefetch(self._prefetch) + 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..9ddb38b --- /dev/null +++ b/privacy_consent/models/mail_template.py @@ -0,0 +1,32 @@ +# 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 = [u"//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..3f280b5 --- /dev/null +++ b/privacy_consent/models/privacy_activity.py @@ -0,0 +1,142 @@ +# 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", + 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): + 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], self._prefetch) \ + .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 = self.env["privacy.consent"] + # 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) + # Create missing consent requests + for missing in self.env["res.partner"].search(domain): + consents |= consents.create({ + "partner_id": missing.id, + "accepted": one.default_consent, + "activity_id": one.id, + }) + # Send consent request emails for automatic activitys + 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..f94ee7f --- /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 _track_subtype(self, init_values): + """Return specific subtypes.""" + if self.env.context.get("subject_answering"): + return "privacy_consent.mt_consent_acceptance_changed" + if "activity_id" in init_values or "partner_id" in init_values: + return "privacy_consent.mt_consent_consent_new" + if "state" in init_values: + return "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 + def create(self, vals): + """Run server action on create.""" + result = super(PrivacyConsent, + self.with_context(mail_create_nolog=True)).create(vals) + # Sync the default acceptance status + result.sudo()._run_action() + return result + + def write(self, vals): + """Run server action on update.""" + result = super(PrivacyConsent, self).write(vals) + self._run_action() + return result + + def message_get_suggested_recipients(self): + result = super(PrivacyConsent, self) \ + .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": "mass_mail", + "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..1c894a7 --- /dev/null +++ b/privacy_consent/models/res_partner.py @@ -0,0 +1,31 @@ +# 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.""" + 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], self._prefetch) \ + .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..7e69756 --- /dev/null +++ b/privacy_consent/static/description/index.html @@ -0,0 +1,525 @@ + + + + + + +Privacy - Consent + + + + + + diff --git a/privacy_consent/templates/form.xml b/privacy_consent/templates/form.xml new file mode 100644 index 0000000..b0e260b --- /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..8de1e56 --- /dev/null +++ b/privacy_consent/tests/test_consent.py @@ -0,0 +1,252 @@ +# 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 HttpCase + + +class ActivityCase(HttpCase): + def setUp(self): + super(ActivityCase, self).setUp() + # HACK https://github.com/odoo/odoo/issues/12237 + # TODO Remove hack in v12 + self._oldenv = self.env + self.env = self._oldenv(self.cursor()) + # HACK end + self.cron = self.env.ref("privacy_consent.cron_auto_consent") + self.cron_mail_queue = self.env.ref( + "mail.ir_cron_mail_scheduler_action") + self.update_opt_out = self.env.ref("privacy_consent.update_opt_out") + 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", + "notify_email": "none", + "opt_out": False, + }) + self.partners += self.partners.create({ + "name": "consent-partner-1", + "email": "partner1@example.com", + "notify_email": "always", + "opt_out": True, + }) + self.partners += self.partners.create({ + "name": "consent-partner-2", + "email": "partner2@example.com", + "opt_out": False, + }) + # Partner without email, on purpose + self.partners += self.partners.create({ + "name": "consent-partner-3", + "opt_out": True, + }) + # 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.update_opt_out.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.update_opt_out.id, + }) + + # HACK https://github.com/odoo/odoo/issues/12237 + # TODO Remove hack in v12 + def tearDown(self): + self.env = self._oldenv + super(ActivityCase, self).tearDown() + + # HACK https://github.com/odoo/odoo/issues/12237 + # TODO Remove hack in v12 + @contextmanager + def release_cr(self): + self.env.cr.release() + yield + self.env.cr.acquire() + + 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 + self.cron_mail_queue.method_direct_trigger() + for consent in consents: + self.assertEqual(consent.state, "sent") + messages = consent.message_ids + self.assertEqual(len(messages), 3) + # 2nd message notifies creation + self.assertEqual( + messages[2].subtype_id, + self.mt_consent_consent_new, + ) + # 3rd message notifies subject + # 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 + self.assertFalse(consent._url(True) in messages[1].body) + self.assertFalse(consent._url(False) in messages[1].body) + # 4th message contains the state change + self.assertEqual( + messages[0].subtype_id, + self.mt_consent_state_changed, + ) + # Partner's opt_out should be synced with default consent + self.assertFalse(consent.partner_id.opt_out) + + 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.""" + self.partners.write({"opt_out": False}) + 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"] * 2) + self.assertEqual(consents.mapped("partner_id.opt_out"), [False] * 2) + self.assertEqual(consents.mapped("accepted"), [False] * 2) + self.assertEqual(consents.mapped("last_metadata"), [False] * 2) + # Check sent mails + messages = consents.mapped("message_ids") + self.assertEqual(len(messages), 2) + 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"]).create({}) + composer.onchange_template_id_wrapper() + composer.send_mail() + 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"]) + self.assertEqual(consents.mapped("partner_id.opt_out"), [True, 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 + with self.release_cr(): + 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]) + self.assertTrue(consents[0].last_metadata) + self.assertFalse(consents[0].partner_id.opt_out) + self.assertEqual(consents.mapped("state"), ["answered", "draft"]) + self.assertEqual( + consents[0].message_ids[0].subtype_id, + self.mt_consent_acceptance_changed, + ) + # Visit tokenized reject URL + with self.release_cr(): + 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]) + self.assertTrue(consents[0].last_metadata) + self.assertTrue(consents[0].partner_id.opt_out) + self.assertEqual(consents.mapped("state"), ["answered", "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..ef72275 --- /dev/null +++ b/privacy_consent/views/privacy_activity.xml @@ -0,0 +1,88 @@ + + + + + + + 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..5526a03 --- /dev/null +++ b/privacy_consent/views/privacy_consent.xml @@ -0,0 +1,113 @@ + + + + + + + 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..53d395c --- /dev/null +++ b/privacy_consent/views/res_partner.xml @@ -0,0 +1,34 @@ + + + + + + + Add consent smart button + res.partner + + + +
+ +
+
+
+ +
diff --git a/setup/_metapackage/VERSION.txt b/setup/_metapackage/VERSION.txt index 3b091b2..27c495f 100644 --- a/setup/_metapackage/VERSION.txt +++ b/setup/_metapackage/VERSION.txt @@ -1 +1 @@ -11.0.20190321.0 \ No newline at end of file +11.0.20190705.0 \ No newline at end of file diff --git a/setup/_metapackage/setup.py b/setup/_metapackage/setup.py index becc6b2..16a1025 100644 --- a/setup/_metapackage/setup.py +++ b/setup/_metapackage/setup.py @@ -10,6 +10,7 @@ setuptools.setup( install_requires=[ 'odoo11-addon-contact_search_form', 'odoo11-addon-privacy', + 'odoo11-addon-privacy_consent', 'odoo11-addon-privacy_partner_report', 'odoo11-addon-website_contact_extend', ], 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.cfg b/setup/privacy_consent/setup.cfg new file mode 100644 index 0000000..3c6e79c --- /dev/null +++ b/setup/privacy_consent/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 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, +)