diff --git a/website_sale_require_legal/README.rst b/website_sale_require_legal/README.rst new file mode 100644 index 0000000000..b6cb1997d4 --- /dev/null +++ b/website_sale_require_legal/README.rst @@ -0,0 +1,160 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========================================= +Require accepting legal terms to checkout +========================================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:bf2f49e4d24fbef2d4dd56bcaf36b3e38f42f921ff8e864c774f83688a5b1133 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fe--commerce-lightgray.png?logo=github + :target: https://github.com/OCA/e-commerce/tree/19.0/website_sale_require_legal + :alt: OCA/e-commerce +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/e-commerce-19-0/e-commerce-19-0-website_sale_require_legal + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/e-commerce&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends your e-commerce legal compliance options: + +1. Require accepting legal terms before submitting a new address. +2. Log a note in the partner when such terms are accepted. +3. Log a note in the sale order when terms are accepted before payment + (done for every online payment, it is an upstream feature). + +**Table of contents** + +.. contents:: + :local: + +Use Cases / Context +=================== + +This module adds the functionality to require the user to check the +checkbox to accept the legal terms in the address form. Additionally, it +provides a metadata record for both the user when legal terms are +accepted through the address form and for the sales order when legal +terms are accepted during the payment process. + +It's worth noting that this module can be useful even if the acceptance +of legal terms in the address form is not activated, as it stores a +metadata record when the terms and conditions are accepted during the +payment process, even if a new address has not been created. + +Configuration +============= + +To configure this module, you need to: + +1. Install it. + +2. Set up `your legal pages `__. + +3. Go to your e-commerce and make a sample checkout. + +4. Visit `/shop/address `__ and enable in the web editor + *Customize > Require Legal Terms Acceptance*. + + |image1| + + This will require acceptance before recording a new address, and log + visitor's acceptance. + +5. Visit `/shop/payment `__ and enable in the web editor + *Customize > Accept Terms & Conditions* (upstream Odoo feature). + + |image2| + + This will require acceptance before paying the sale order, and log + visitor's acceptance. + +.. |image1| image:: https://raw.githubusercontent.com/OCA/e-commerce/19.0/website_sale_require_legal/static/description/address-enable.png +.. |image2| image:: https://raw.githubusercontent.com/OCA/e-commerce/19.0/website_sale_require_legal/static/description/payment-enable.png + +Usage +===== + +To use this module, you need to: + +- Buy something from your website. + +Known issues / Roadmap +====================== + +- Shopping terms and conditions are accepted only on user registration + or address edition. So if those terms change after the user signed up, + a notification should be made. An implicit acceptance could be printed + in the payment screen to solve this. Maybe that could be a work to + develop in another module. +- If you enable both acceptance views as explained in the configuration + section, first-time buyers will have to accept the legal terms between + 2 and 3 times to buy. + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__: + + - Rafael Blasco + - Jairo Llopis + - Vicent Cubells + - David Vidal + - Ernesto Tejeda + - Cristina Martin R. + - Pilar Vargas + +- `ACSONE `__: + + - Raphaël Vicini + +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/e-commerce `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/website_sale_require_legal/__init__.py b/website_sale_require_legal/__init__.py new file mode 100644 index 0000000000..e34ddee75a --- /dev/null +++ b/website_sale_require_legal/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import controllers diff --git a/website_sale_require_legal/__manifest__.py b/website_sale_require_legal/__manifest__.py new file mode 100644 index 0000000000..0814b9e5e5 --- /dev/null +++ b/website_sale_require_legal/__manifest__.py @@ -0,0 +1,28 @@ +# Copyright 2015, 2017, 2021 Tecnativa - Jairo Llopis +# Copyright 2016 Tecnativa - Vicent Cubells +# Copyright 2019 Tecnativa - Cristina Martin R. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "Require accepting legal terms to checkout", + "summary": "Force the user to accept legal tems to buy in the web shop", + "version": "19.0.1.0.1", + "category": "Website", + "website": "https://github.com/OCA/e-commerce", + "author": "Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["website_sale"], + "data": ["templates/website_sale.xml"], + "assets": { + "web.assets_frontend": [ + "/website_sale_require_legal/static/src/scss/website_sale_require_legal.scss", + ], + "web.assets_tests": [ + "/website_sale_require_legal/static/tests/tours/tour.esm.js", + ], + "website.website_builder_assets": [ + "website_sale_require_legal/static/src/website_builder/address_page_option.xml", + ], + }, +} diff --git a/website_sale_require_legal/controllers/__init__.py b/website_sale_require_legal/controllers/__init__.py new file mode 100644 index 0000000000..1574278ce7 --- /dev/null +++ b/website_sale_require_legal/controllers/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import main diff --git a/website_sale_require_legal/controllers/main.py b/website_sale_require_legal/controllers/main.py new file mode 100644 index 0000000000..e66a632359 --- /dev/null +++ b/website_sale_require_legal/controllers/main.py @@ -0,0 +1,124 @@ +# Copyright 2015-2017 Tecnativa - Jairo Llopis +# Copyright 2016 Tecnativa - Vicent Cubells +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from markupsafe import Markup + +from odoo import http +from odoo.http import request, route + +from odoo.addons.payment.controllers import portal +from odoo.addons.website_sale.controllers import main + + +class WebsiteSale(main.WebsiteSale): + def _validate_address_values( + self, + address_values, + partner_sudo, + address_type, + use_delivery_as_billing, + required_fields, + **_kwargs, + ): + invalid_fields, missing_fields, error_messages = ( + super()._validate_address_values( + address_values, + partner_sudo, + address_type, + use_delivery_as_billing, + required_fields, + **_kwargs, + ) + ) + if ( + not _kwargs.get("accepted_legal_terms") + and request.website.viewref( + "website_sale_require_legal.address_require_legal" + ).active + ): + invalid_fields.add("accepted_legal_terms") + error_messages.append( + request.env._("You must accept the terms & conditions to continue.") + ) + + return invalid_fields, missing_fields, error_messages + + @route( + "/shop/address/submit", + type="http", + methods=["POST"], + auth="public", + website=True, + sitemap=False, + ) + def shop_address_submit( + self, + partner_id=None, + address_type="billing", + use_delivery_as_billing=None, + callback=None, + required_fields=None, + **form_data, + ): + res = super().shop_address_submit( + partner_id=partner_id, + address_type=address_type, + use_delivery_as_billing=use_delivery_as_billing, + callback=callback, + required_fields=required_fields, + **form_data, + ) + if partner_id: + partner = request.env["res.partner"].browse(int(partner_id)) + if form_data.get("accepted_legal_terms"): + self._log_acceptance_metadata(partner) + return res + + def _log_acceptance_metadata(self, record): + """Log legal terms acceptance metadata.""" + environ = request.httprequest.headers.environ + metadata = "
".join( + f"{val}: {environ.get(val)}" + for val in ( + "REMOTE_ADDR", + "HTTP_USER_AGENT", + "HTTP_ACCEPT_LANGUAGE", + ) + ) + message = Markup( + request.env._("Website legal terms acceptance metadata: %s", metadata) + ) + record.sudo().message_post( + body=message, message_type="notification", subtype_xmlid="mail.mt_comment" + ) + + +class PaymentPortal(portal.PaymentPortal): + @http.route() + def shop_payment_transaction(self, order_id, access_token, **kwargs): + """Record sale order payment legal terms acceptance. + + If the "Accept Terms & Conditions" upstream view is enabled in the + website, to get here, user must have accepted legal terms. + """ + result = super().shop_payment_transaction(order_id, access_token, **kwargs) + # If the "Accept Terms & Conditions" view is disabled, we log nothing + if not request.website.viewref( + "website_sale.accept_terms_and_conditions" + ).active: + return result + # Retrieve the sale order + if order_id: + sale_obj = request.env["sale.order"] + domain = [("id", "=", order_id)] + if access_token: + sale_obj = sale_obj.sudo() + domain.append(("access_token", "=", access_token)) + order = sale_obj.search(domain, limit=1) + else: + order = request.website.sale_get_order() + # Log metadata in the sale order + if order: + WebsiteSale._log_acceptance_metadata(self, order) + return result diff --git a/website_sale_require_legal/i18n/de.po b/website_sale_require_legal/i18n/de.po new file mode 100644 index 0000000000..ac2d4cacdf --- /dev/null +++ b/website_sale_require_legal/i18n/de.po @@ -0,0 +1,44 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_require_legal +# +# Translators: +# Rudolf Schnapka , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-05-20 01:42+0000\n" +"PO-Revision-Date: 2026-02-25 07:27+0000\n" +"Last-Translator: Anonymous \n" +"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\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 5.15.2\n" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "I agree to the" +msgstr "" + +#. module: website_sale_require_legal +#. odoo-python +#: code:addons/website_sale_require_legal/controllers/main.py:0 +#, python-format +msgid "Website legal terms acceptance metadata: %s" +msgstr "" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "terms & conditions" +msgstr "" + +#~ msgid "" +#~ "Confirm\n" +#~ " " +#~ msgstr "" +#~ "Bestätigen\n" +#~ " " diff --git a/website_sale_require_legal/i18n/es.po b/website_sale_require_legal/i18n/es.po new file mode 100644 index 0000000000..7781542813 --- /dev/null +++ b/website_sale_require_legal/i18n/es.po @@ -0,0 +1,37 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_require_legal +# +# Translators: +# Pedro M. Baeza , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-01-07 02:00+0000\n" +"PO-Revision-Date: 2026-02-25 07:27+0000\n" +"Last-Translator: Anonymous \n" +"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" +"Language: es\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 5.15.2\n" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "I agree to the" +msgstr "Estoy de acuerdo con el/la" + +#. module: website_sale_require_legal +#. odoo-python +#: code:addons/website_sale_require_legal/controllers/main.py:0 +#, python-format +msgid "Website legal terms acceptance metadata: %s" +msgstr "Metadatos de aceptación de los términos legales del sitio web: %s" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "terms & conditions" +msgstr "términos y plazos; condiciones" diff --git a/website_sale_require_legal/i18n/fi.po b/website_sale_require_legal/i18n/fi.po new file mode 100644 index 0000000000..1f6381f9c6 --- /dev/null +++ b/website_sale_require_legal/i18n/fi.po @@ -0,0 +1,33 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2026-02-25 07:27+0000\n" +"Last-Translator: Anonymous \n" +"Language-Team: none\n" +"Language: fi\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 5.15.2\n" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "I agree to the" +msgstr "" + +#. module: website_sale_require_legal +#. odoo-python +#: code:addons/website_sale_require_legal/controllers/main.py:0 +#, python-format +msgid "Website legal terms acceptance metadata: %s" +msgstr "" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "terms & conditions" +msgstr "" diff --git a/website_sale_require_legal/i18n/hr.po b/website_sale_require_legal/i18n/hr.po new file mode 100644 index 0000000000..233c23b741 --- /dev/null +++ b/website_sale_require_legal/i18n/hr.po @@ -0,0 +1,38 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_require_legal +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: e-commerce (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-09-17 10:15+0000\n" +"PO-Revision-Date: 2026-02-25 07:28+0000\n" +"Last-Translator: Anonymous \n" +"Language-Team: Croatian (http://www.transifex.com/oca/OCA-e-commerce-8-0/" +"language/hr/)\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 5.15.2\n" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "I agree to the" +msgstr "" + +#. module: website_sale_require_legal +#. odoo-python +#: code:addons/website_sale_require_legal/controllers/main.py:0 +#, python-format +msgid "Website legal terms acceptance metadata: %s" +msgstr "" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "terms & conditions" +msgstr "" diff --git a/website_sale_require_legal/i18n/it.po b/website_sale_require_legal/i18n/it.po new file mode 100644 index 0000000000..9bd9c3dc72 --- /dev/null +++ b/website_sale_require_legal/i18n/it.po @@ -0,0 +1,44 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_require_legal +# +# Translators: +# Paolo Valier , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-03-28 02:55+0000\n" +"PO-Revision-Date: 2026-02-25 07:29+0000\n" +"Last-Translator: Anonymous \n" +"Language-Team: Italian (https://www.transifex.com/oca/teams/23907/it/)\n" +"Language: it\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 5.15.2\n" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "I agree to the" +msgstr "Concordo con il" + +#. module: website_sale_require_legal +#. odoo-python +#: code:addons/website_sale_require_legal/controllers/main.py:0 +#, python-format +msgid "Website legal terms acceptance metadata: %s" +msgstr "Metadati accettazione termini legali sito web: %s" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "terms & conditions" +msgstr "termini e condizioni" + +#~ msgid "" +#~ "Confirm\n" +#~ " " +#~ msgstr "" +#~ "Conferma\n" +#~ "" diff --git a/website_sale_require_legal/i18n/sl.po b/website_sale_require_legal/i18n/sl.po new file mode 100644 index 0000000000..00ba7b9c06 --- /dev/null +++ b/website_sale_require_legal/i18n/sl.po @@ -0,0 +1,42 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_require_legal +# +# Translators: +# Matjaž Mozetič , 2016 +msgid "" +msgstr "" +"Project-Id-Version: e-commerce (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-28 00:48+0000\n" +"PO-Revision-Date: 2026-05-31 06:46+0000\n" +"Last-Translator: Matjaz Mozetic \n" +"Language-Team: Slovenian (http://www.transifex.com/oca/OCA-e-commerce-8-0/" +"language/sl/)\n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || " +"n%100==4 ? 2 : 3;\n" +"X-Generator: Weblate 5.15.2\n" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "I agree to the" +msgstr "Strinjam se s" + +#. module: website_sale_require_legal +#. odoo-python +#: code:addons/website_sale_require_legal/controllers/main.py:0 +#, python-format +msgid "Website legal terms acceptance metadata: %s" +msgstr "Metapodatki o sprejetju pravnih pogojev spletnega mesta: %s" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "terms & conditions" +msgstr "Pravila in pogoji" + +#~ msgid "Confirm" +#~ msgstr "Potrjujem" diff --git a/website_sale_require_legal/i18n/website_sale_require_legal.pot b/website_sale_require_legal/i18n/website_sale_require_legal.pot new file mode 100644 index 0000000000..1c41e9abd6 --- /dev/null +++ b/website_sale_require_legal/i18n/website_sale_require_legal.pot @@ -0,0 +1,36 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_require_legal +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.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: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "I agree to the" +msgstr "" + +#. module: website_sale_require_legal +#. odoo-python +#: code:addons/website_sale_require_legal/controllers/main.py:0 +msgid "Website legal terms acceptance metadata: %s" +msgstr "" + +#. module: website_sale_require_legal +#. odoo-python +#: code:addons/website_sale_require_legal/controllers/main.py:0 +msgid "You must accept the terms & conditions to continue." +msgstr "" + +#. module: website_sale_require_legal +#: model_terms:ir.ui.view,arch_db:website_sale_require_legal.accept_input +msgid "terms & conditions" +msgstr "" diff --git a/website_sale_require_legal/pyproject.toml b/website_sale_require_legal/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/website_sale_require_legal/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/website_sale_require_legal/readme/CONFIGURE.md b/website_sale_require_legal/readme/CONFIGURE.md new file mode 100644 index 0000000000..2b471db289 --- /dev/null +++ b/website_sale_require_legal/readme/CONFIGURE.md @@ -0,0 +1,23 @@ +To configure this module, you need to: + +1. Install it. + +2. Set up [your legal pages](/legal). + +3. Go to your e-commerce and make a sample checkout. + +4. Visit [/shop/address](/shop/address) and enable in the web editor *Customize \> + Require Legal Terms Acceptance*. + + ![](../static/description/address-enable.png) + + This will require acceptance before recording a new address, and log + visitor's acceptance. + +5. Visit [/shop/payment](/shop/payment) and enable in the web editor *Customize \> + Accept Terms & Conditions* (upstream Odoo feature). + + ![](../static/description/payment-enable.png) + + This will require acceptance before paying the sale order, and log + visitor's acceptance. diff --git a/website_sale_require_legal/readme/CONTEXT.md b/website_sale_require_legal/readme/CONTEXT.md new file mode 100644 index 0000000000..22e9664f40 --- /dev/null +++ b/website_sale_require_legal/readme/CONTEXT.md @@ -0,0 +1,10 @@ +This module adds the functionality to require the user to check the +checkbox to accept the legal terms in the address form. Additionally, it +provides a metadata record for both the user when legal terms are +accepted through the address form and for the sales order when legal +terms are accepted during the payment process. + +It's worth noting that this module can be useful even if the acceptance +of legal terms in the address form is not activated, as it stores a +metadata record when the terms and conditions are accepted during the +payment process, even if a new address has not been created. diff --git a/website_sale_require_legal/readme/CONTRIBUTORS.md b/website_sale_require_legal/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..2c2a47a7d7 --- /dev/null +++ b/website_sale_require_legal/readme/CONTRIBUTORS.md @@ -0,0 +1,13 @@ +- [Tecnativa](https://www.tecnativa.com): + + > - Rafael Blasco + > - Jairo Llopis + > - Vicent Cubells + > - David Vidal + > - Ernesto Tejeda + > - Cristina Martin R. + > - Pilar Vargas + +- [ACSONE](https://www.acsone.eu/): + + > - Raphaël Vicini diff --git a/website_sale_require_legal/readme/DESCRIPTION.md b/website_sale_require_legal/readme/DESCRIPTION.md new file mode 100644 index 0000000000..80f4d6b7f6 --- /dev/null +++ b/website_sale_require_legal/readme/DESCRIPTION.md @@ -0,0 +1,6 @@ +This module extends your e-commerce legal compliance options: + +1. Require accepting legal terms before submitting a new address. +2. Log a note in the partner when such terms are accepted. +3. Log a note in the sale order when terms are accepted before payment + (done for every online payment, it is an upstream feature). diff --git a/website_sale_require_legal/readme/ROADMAP.md b/website_sale_require_legal/readme/ROADMAP.md new file mode 100644 index 0000000000..5a3f04452b --- /dev/null +++ b/website_sale_require_legal/readme/ROADMAP.md @@ -0,0 +1,8 @@ +- Shopping terms and conditions are accepted only on user registration + or address edition. So if those terms change after the user signed up, + a notification should be made. An implicit acceptance could be printed + in the payment screen to solve this. Maybe that could be a work to + develop in another module. +- If you enable both acceptance views as explained in the configuration + section, first-time buyers will have to accept the legal terms between + 2 and 3 times to buy. diff --git a/website_sale_require_legal/readme/USAGE.md b/website_sale_require_legal/readme/USAGE.md new file mode 100644 index 0000000000..4e687f4f14 --- /dev/null +++ b/website_sale_require_legal/readme/USAGE.md @@ -0,0 +1,3 @@ +To use this module, you need to: + +- Buy something from your website. diff --git a/website_sale_require_legal/static/description/address-enable.png b/website_sale_require_legal/static/description/address-enable.png new file mode 100644 index 0000000000..ef7f5ea24a Binary files /dev/null and b/website_sale_require_legal/static/description/address-enable.png differ diff --git a/website_sale_require_legal/static/description/icon.png b/website_sale_require_legal/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/website_sale_require_legal/static/description/icon.png differ diff --git a/website_sale_require_legal/static/description/index.html b/website_sale_require_legal/static/description/index.html new file mode 100644 index 0000000000..7311f43f17 --- /dev/null +++ b/website_sale_require_legal/static/description/index.html @@ -0,0 +1,514 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + + +
+ + diff --git a/website_sale_require_legal/static/description/payment-enable.png b/website_sale_require_legal/static/description/payment-enable.png new file mode 100644 index 0000000000..ff4238419d Binary files /dev/null and b/website_sale_require_legal/static/description/payment-enable.png differ diff --git a/website_sale_require_legal/static/src/scss/website_sale_require_legal.scss b/website_sale_require_legal/static/src/scss/website_sale_require_legal.scss new file mode 100644 index 0000000000..8df3b1f5f6 --- /dev/null +++ b/website_sale_require_legal/static/src/scss/website_sale_require_legal.scss @@ -0,0 +1,3 @@ +input#accepted_legal_terms.is-invalid ~ .form-check-label a { + color: $red; +} diff --git a/website_sale_require_legal/static/src/website_builder/address_page_option.xml b/website_sale_require_legal/static/src/website_builder/address_page_option.xml new file mode 100644 index 0000000000..353715a5d6 --- /dev/null +++ b/website_sale_require_legal/static/src/website_builder/address_page_option.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/website_sale_require_legal/static/tests/tours/tour.esm.js b/website_sale_require_legal/static/tests/tours/tour.esm.js new file mode 100644 index 0000000000..9d06c7755e --- /dev/null +++ b/website_sale_require_legal/static/tests/tours/tour.esm.js @@ -0,0 +1,140 @@ +/* Copyright 2017 Jairo Llopis + * Copyright 2023 Pilar Vargas + * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */ + +import {registry} from "@web/core/registry"; +import * as tourUtils from "@website_sale/js/tours/tour_utils"; + +registry.category("web_tour.tours").add("website_sale_require_legal_with_payment", { + url: "/shop", + steps: () => [ + ...tourUtils.addToCart({ + productName: "Storage Box", + expectUnloadPage: true, + }), + + tourUtils.goToCart(), + tourUtils.goToCheckout(), + // Fill all required fields except legal terms acceptance + { + content: "edit billing address", + trigger: 'a[href^="/shop/address"][href*="address_type=billing"]:visible', + run: "click", + expectUnloadPage: true, + }, + { + trigger: "#o_country_id", + run: function () { + $('input[name="name"]').val("super_mario"); + $('input[name="phone"]').val("99999999"); + $('input[name="email"]').val("super_mario@mail.com"); + // Required for test compatibility with the website_sale_vat_required module + $('input[name="vat"]').val("BE04774722701"); + $('input[name="street"]').val("Castle St., 1"); + $('input[name="city"]').val("Mushroom Kingdom"); + $('input[name="zip"]').val("10000"); + $("#o_country_id option:eq(1)").attr("selected", true); + }, + }, + // Submit, to prove that it is not possible to continue without accepting the legal terms + { + content: "legal terms checkbox is displayed", + trigger: "#accepted_legal_terms", + }, + { + content: "save address without legal terms", + trigger: 'a[name="website_sale_main_button"]:visible', + run: "click", + }, + + // // Accept legal terms and accept again + { + content: "accept legal terms", + trigger: "#accepted_legal_terms", + run: "click", + }, + { + content: "save address with legal terms", + trigger: 'a[name="website_sale_main_button"]:visible', + run: "click", + expectUnloadPage: true, + }, + { + content: "go to checkout", + trigger: 'a[name="website_sale_main_button"]:visible', + run: "click", + expectUnloadPage: false, + }, + // If I can proceed to payment, it's because the form validated fine + + tourUtils.confirmOrder(), + ...tourUtils.pay({expectUnloadPage: true, waitFinalizeYourPayment: true}), + ], +}); + +registry.category("web_tour.tours").add("website_sale_require_legal", { + url: "/shop", + steps: () => [ + ...tourUtils.addToCart({ + productName: "Storage Box", + expectUnloadPage: true, + }), + tourUtils.goToCart({quantity: 1}), + tourUtils.goToCheckout(), + // Fill all required fields except legal terms acceptance + { + content: "edit delivery address", + trigger: + 'a.js_edit_address[name="card_address_ref"]' + + '[href*="address_type=delivery"]' + + '[href*="use_delivery_as_billing="]:visible', + run: "click", + expectUnloadPage: true, + }, + + { + content: "Fill delivery address form", + trigger: "#o_country_id", + run: "selectByLabel United States", + }, + { + content: "Fill delivery address form", + trigger: "#o_state_id", + run: "selectByLabel Florida", + }, + { + trigger: "#o_country_id", + run: function () { + $('input[name="phone"]').val("99999999"); + // Required for test compatibility with the website_sale_vat_required module + $('input[name="vat"]').val("41511545146"); + $('input[name="street"]').val("Castle St., 1"); + $('input[name="city"]').val("Mushroom Kingdom"); + $('input[name="zip"]').val("10000"); + }, + }, + // Submit, to prove that it is not possible to continue without accepting the legal terms + { + content: "save address without legal terms", + trigger: 'a[name="website_sale_main_button"]:visible', + run: "click", + }, + // // Accept legal terms and accept again + { + content: "accept legal terms", + trigger: "#accepted_legal_terms", + run: "click", + }, + { + content: "save address with legal terms", + trigger: 'a[name="website_sale_main_button"]:visible', + run: "click", + }, + { + content: "confirm checkout", + trigger: 'a[name="website_sale_main_button"]:visible', + run: "click", + expectUnloadPage: true, + }, + ], +}); diff --git a/website_sale_require_legal/templates/website_sale.xml b/website_sale_require_legal/templates/website_sale.xml new file mode 100644 index 0000000000..ec95054a9a --- /dev/null +++ b/website_sale_require_legal/templates/website_sale.xml @@ -0,0 +1,35 @@ + + + + + + diff --git a/website_sale_require_legal/tests/__init__.py b/website_sale_require_legal/tests/__init__.py new file mode 100644 index 0000000000..d3a5656d82 --- /dev/null +++ b/website_sale_require_legal/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import test_ui diff --git a/website_sale_require_legal/tests/test_ui.py b/website_sale_require_legal/tests/test_ui.py new file mode 100644 index 0000000000..265c08c4b1 --- /dev/null +++ b/website_sale_require_legal/tests/test_ui.py @@ -0,0 +1,110 @@ +# Copyright 2017 Jairo Llopis +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo.tests import new_test_user, tagged +from odoo.tests.common import HttpCase + + +@tagged("post_install", "-at_install") +class UICase(HttpCase): + """Test checkout flow with legal terms acceptance required. + + It would be nice to check also that the workflow isn't interrupted when the + acceptance requirement views are disabled, but that's what upstream tests + do, so we don't need to repeat them. We can assume that, if other tests in + the same integrated environment don't fail because of lack of legal terms + acceptance, then the flow is fine. + """ + + def setUp(self): + """Ensure website lang is en_US.""" + super().setUp() + website = self.env["website"].get_current_website() + wire_transfer = self.env["payment.provider"].search( + [ + ("code", "=", "custom"), + ("custom_mode", "=", "wire_transfer"), + ], + limit=1, + ) + wire_transfer.write( + { + "state": "enabled", + "is_published": True, + "company_id": website.company_id.id, + } + ) + en_US = ( + self.env["res.lang"] + .with_context(active_test=False) + .search([("code", "=", "en_US")]) + ) + wiz = self.env["base.language.install"].create({"lang_ids": en_US.ids}) + self.env.flush_all() + wiz.website_ids = website + wiz.lang_install() + website.default_lang_id = self.env.ref("base.lang_en") + # Activate Accept Terms & Conditions views, as explained in CONFIGURE.rst + website.with_context( + website_id=website.id, + ).viewref("website_sale_require_legal.address_require_legal").active = True + website.with_context( + website_id=website.id, + ).viewref("website_sale.accept_terms_and_conditions").active = True + self.user = new_test_user( + self.env, + login="super_mario", + groups="base.group_portal", + password="super_mario", + name="Super Mario", + ) + self.env["product.template"].create( + { + "name": "Storage Box", + "list_price": 100.0, + "sale_ok": True, + "is_published": True, + } + ) + + def test_ui_website(self): + """Test frontend tour.""" + wire_transfer = self.env["payment.provider"].search( + [ + ("code", "=", "custom"), + ("custom_mode", "=", "wire_transfer"), + ], + limit=1, + ) + if not wire_transfer: + self.start_tour( + "/shop", + "website_sale_require_legal", + stepDelay=100, + login="super_mario", + ) + else: + self.start_tour( + "/shop", + "website_sale_require_legal_with_payment", + stepDelay=100, + login="super_mario", + ) + order = self.env["sale.order"].search( + [ + ("partner_id", "ilike", "super_mario"), + ("website_id", "!=", False), + ] + ) + # Assert that the sale order have metadata logs + self.assertTrue( + order.message_ids.filtered( + lambda one: "Website legal terms acceptance metadata" in one.body + ) + ) + # Assert that the partner have metadata logs + partner = self.user.partner_id + self.assertTrue( + partner.message_ids.filtered( + lambda one: "Website legal terms acceptance metadata" in one.body + ) + )