diff --git a/website_sale_checkout_address_no_save/README.rst b/website_sale_checkout_address_no_save/README.rst new file mode 100644 index 0000000000..5bb107b99c --- /dev/null +++ b/website_sale_checkout_address_no_save/README.rst @@ -0,0 +1,87 @@ +============================= +Website Sale Not Save Address +============================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:4380ced474aeae5a2124595137ce3a229165290e5bc38877415760efcc0490a3 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fe--commerce-lightgray.png?logo=github + :target: https://github.com/OCA/e-commerce/tree/18.0/website_sale_checkout_address_no_save + :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-18-0/e-commerce-18-0-website_sale_checkout_address_no_save + :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=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Adds a checkbox in /shop/address to avoid having to many address in +/shop/checkout. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Once module is install you have to go to website edit, an enable +'Archive Address after checkout'. After that, a heckbox will appear on +/shop/address. On the checkout if the payment transaction is valid it +will archive the conctact. + +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 `__: + + - Eduardo Ezerouali + +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_checkout_address_no_save/__init__.py b/website_sale_checkout_address_no_save/__init__.py new file mode 100644 index 0000000000..df5391741a --- /dev/null +++ b/website_sale_checkout_address_no_save/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2026 Tecnativa - Eduardo Ezerouali +# License AGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). +from . import controllers diff --git a/website_sale_checkout_address_no_save/__manifest__.py b/website_sale_checkout_address_no_save/__manifest__.py new file mode 100644 index 0000000000..a85666f344 --- /dev/null +++ b/website_sale_checkout_address_no_save/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2026 Tecnativa - Eduardo Ezerouali +# License AGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). +{ + "name": "Website Sale Not Save Address", + "summary": "Avoid having to many address as dropshipping customer", + "version": "18.0.1.0.0", + "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": ["views/website_sale_templates.xml"], + "assets": { + "web.assets_tests": [ + "website_sale_checkout_address_no_save/static/tests/tours/*.js", + ], + }, +} diff --git a/website_sale_checkout_address_no_save/controllers/__init__.py b/website_sale_checkout_address_no_save/controllers/__init__.py new file mode 100644 index 0000000000..78c994268a --- /dev/null +++ b/website_sale_checkout_address_no_save/controllers/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2026 Tecnativa - Eduardo Ezerouali +# License AGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). +from . import main diff --git a/website_sale_checkout_address_no_save/controllers/main.py b/website_sale_checkout_address_no_save/controllers/main.py new file mode 100644 index 0000000000..c02c6094b0 --- /dev/null +++ b/website_sale_checkout_address_no_save/controllers/main.py @@ -0,0 +1,74 @@ +# Copyright 2026 Tecnativa - Eduardo Ezerouali +# License AGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo import http +from odoo.http import request, route + +from odoo.addons.payment.controllers import post_processing +from odoo.addons.website_sale.controllers import main + + +class WebsiteSale(main.WebsiteSale): + @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, + ): + order = request.website.sale_get_order() + parent_partner = order.partner_id + Partner = request.env["res.partner"].sudo().with_context(active_test=False) + domain = [ + ("active", "=", False), + ("parent_id", "=", parent_partner.id), + ("type", "=", "other"), + ] + if form_data.get("email"): + domain.append(("email", "=", form_data["email"])) + if form_data.get("phone"): + domain.append(("phone", "=", form_data["phone"])) + if form_data.get("street") and form_data.get("zip"): + domain += [ + ("street", "ilike", form_data.get("street")), + ("zip", "=", form_data.get("zip")), + ] + archived_child = Partner.search(domain, limit=1) + if archived_child: + archived_child.write({"active": True, **form_data}) + partner_id = archived_child.id + if form_data.get("archive_address"): + request.session["archive_address"] = True + return 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, + ) + + +class PaymentPostProcessing(post_processing.PaymentPostProcessing): + @http.route( + "/payment/status", type="http", auth="public", website=True, sitemap=False + ) + def display_status(self, **kwargs): + result = super().display_status(**kwargs) + archive_address = request.session.pop("archive_address", False) + if archive_address: + sale_order_id = request.session.get("sale_last_order_id") + if sale_order_id: + order = request.env["sale.order"].sudo().browse(sale_order_id) + order.partner_shipping_id.active = False + return result diff --git a/website_sale_checkout_address_no_save/i18n/es.po b/website_sale_checkout_address_no_save/i18n/es.po new file mode 100644 index 0000000000..81f1ffef3c --- /dev/null +++ b/website_sale_checkout_address_no_save/i18n/es.po @@ -0,0 +1,21 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_checkout_address_no_save +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-02-25 14:15+0000\n" +"PO-Revision-Date: 2026-02-25 14:15+0000\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_checkout_address_no_save +#: model_terms:ir.ui.view,arch_db:website_sale_checkout_address_no_save.archive_address +msgid "This address will be archive after checkout" +msgstr "Esta dirección se archivará después de finalizar la compra" diff --git a/website_sale_checkout_address_no_save/i18n/website_sale_checkout_address_no_save.pot b/website_sale_checkout_address_no_save/i18n/website_sale_checkout_address_no_save.pot new file mode 100644 index 0000000000..e954cce9fa --- /dev/null +++ b/website_sale_checkout_address_no_save/i18n/website_sale_checkout_address_no_save.pot @@ -0,0 +1,21 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * website_sale_checkout_address_no_save +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-02-25 14:14+0000\n" +"PO-Revision-Date: 2026-02-25 14:14+0000\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_checkout_address_no_save +#: model_terms:ir.ui.view,arch_db:website_sale_checkout_address_no_save.archive_address +msgid "This address will be archive after checkout" +msgstr "" diff --git a/website_sale_checkout_address_no_save/pyproject.toml b/website_sale_checkout_address_no_save/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/website_sale_checkout_address_no_save/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/website_sale_checkout_address_no_save/readme/CONTRIBUTORS.md b/website_sale_checkout_address_no_save/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..abafc9d7f4 --- /dev/null +++ b/website_sale_checkout_address_no_save/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- [Tecnativa](https://www.tecnativa.com): + - Eduardo Ezerouali diff --git a/website_sale_checkout_address_no_save/readme/DESCRIPTION.md b/website_sale_checkout_address_no_save/readme/DESCRIPTION.md new file mode 100644 index 0000000000..1413e318dc --- /dev/null +++ b/website_sale_checkout_address_no_save/readme/DESCRIPTION.md @@ -0,0 +1 @@ +Adds a checkbox in /shop/address to avoid having to many address in /shop/checkout. \ No newline at end of file diff --git a/website_sale_checkout_address_no_save/readme/USAGE.md b/website_sale_checkout_address_no_save/readme/USAGE.md new file mode 100644 index 0000000000..79610dc111 --- /dev/null +++ b/website_sale_checkout_address_no_save/readme/USAGE.md @@ -0,0 +1,2 @@ +Once module is install you have to go to website edit, an enable 'Archive Address after checkout'. After that, a heckbox +will appear on /shop/address. On the checkout if the payment transaction is valid it will archive the conctact. diff --git a/website_sale_checkout_address_no_save/static/description/icon.png b/website_sale_checkout_address_no_save/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/website_sale_checkout_address_no_save/static/description/icon.png differ diff --git a/website_sale_checkout_address_no_save/static/description/index.html b/website_sale_checkout_address_no_save/static/description/index.html new file mode 100644 index 0000000000..82271e1b70 --- /dev/null +++ b/website_sale_checkout_address_no_save/static/description/index.html @@ -0,0 +1,435 @@ + + + + + +Website Sale Not Save Address + + + +
+

Website Sale Not Save Address

+ + +

Beta License: AGPL-3 OCA/e-commerce Translate me on Weblate Try me on Runboat

+

Adds a checkbox in /shop/address to avoid having to many address in +/shop/checkout.

+

Table of contents

+ +
+

Usage

+

Once module is install you have to go to website edit, an enable +‘Archive Address after checkout’. After that, a heckbox will appear on +/shop/address. On the checkout if the payment transaction is valid it +will archive the conctact.

+
+
+

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

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

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_checkout_address_no_save/static/tests/tours/tour.esm.js b/website_sale_checkout_address_no_save/static/tests/tours/tour.esm.js new file mode 100644 index 0000000000..e676d7209a --- /dev/null +++ b/website_sale_checkout_address_no_save/static/tests/tours/tour.esm.js @@ -0,0 +1,184 @@ +/* Copyright 2026 Tecnativa - Eduardo Ezerouali + * 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_checkout_address_no_save", { + url: "/shop", + steps: () => [ + ...tourUtils.searchProduct("Storage Box"), + { + content: "select Storage Box", + trigger: '.oe_product_cart:first a:contains("Storage Box")', + run: "click", + }, + { + content: "click on add to cart", + trigger: '#product_detail form[action^="/shop/cart/update"] #add_to_cart', + run: "click", + }, + tourUtils.goToCart(), + tourUtils.goToCheckout(), + // Fill all required fields except legal terms acceptance + { + content: "Fill delivery address form", + trigger: 'select[name="country_id"]', + run: "selectByLabel United State", + }, + { + content: "Fill delivery address form", + trigger: 'select[name="state_id"]', + run: "selectByLabel Florida", + }, + { + trigger: 'select[name="country_id"]', + run: function () { + $('input[name="phone"]').val("99999999"); + // 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"); + $("#country_id option:eq(1)").attr("selected", true); + }, + }, + { + trigger: ".btn-primary:contains('Save address')", + run: "click", + }, + { + trigger: + "a[href='/shop/address?address_type=delivery&use_delivery_as_billing=True']", + run: "click", + }, + { + content: "Fill delivery address form", + trigger: 'select[name="country_id"]', + run: "selectByLabel United State", + }, + { + content: "Fill delivery address form", + trigger: 'select[name="state_id"]', + run: "selectByLabel Florida", + }, + { + trigger: 'select[name="country_id"]', + run: function () { + $('input[name="name"]').val("John Jones"); + $('input[name="phone"]').val("99999999"); + $('input[name="email"]').val("john@jones.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"); + $("#country_id option:eq(1)").attr("selected", true); + }, + }, + { + trigger: "input[id='archive_address']", + run: "click", + }, + { + trigger: ".btn-primary:contains('Save address')", + run: "click", + }, + { + trigger: "a[href='/shop/confirm_order']", + run: "click", + }, + // If I can proceed to payment, it's because the form validated fine + ...tourUtils.payWithTransfer(true), + ], +}); + +registry + .category("web_tour.tours") + .add("website_sale_checkout_address_no_save_no_pay", { + url: "/shop", + steps: () => [ + ...tourUtils.searchProduct("Storage Box"), + { + content: "select Storage Box", + trigger: '.oe_product_cart:first a:contains("Storage Box")', + run: "click", + }, + { + content: "click on add to cart", + trigger: + '#product_detail form[action^="/shop/cart/update"] #add_to_cart', + run: "click", + }, + tourUtils.goToCart(), + tourUtils.goToCheckout(), + // Fill all required fields except legal terms acceptance + { + content: "Fill delivery address form", + trigger: 'select[name="country_id"]', + run: "selectByLabel United State", + }, + { + content: "Fill delivery address form", + trigger: 'select[name="state_id"]', + run: "selectByLabel Florida", + }, + { + trigger: 'select[name="country_id"]', + run: function () { + $('input[name="phone"]').val("99999999"); + // 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"); + $("#country_id option:eq(1)").attr("selected", true); + }, + }, + { + trigger: ".btn-primary:contains('Save address')", + run: "click", + }, + { + trigger: + "a[href='/shop/address?address_type=delivery&use_delivery_as_billing=True']", + run: "click", + }, + { + content: "Fill delivery address form", + trigger: 'select[name="country_id"]', + run: "selectByLabel United State", + }, + { + content: "Fill delivery address form", + trigger: 'select[name="state_id"]', + run: "selectByLabel Florida", + }, + { + trigger: 'select[name="country_id"]', + run: function () { + $('input[name="name"]').val("John Jones"); + $('input[name="phone"]').val("99999999"); + $('input[name="email"]').val("john@jones.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"); + $("#country_id option:eq(1)").attr("selected", true); + }, + }, + { + trigger: "input[id='archive_address']", + run: "click", + }, + { + trigger: ".btn-primary:contains('Save address')", + run: "click", + }, + { + trigger: "a[href='/shop/confirm_order']", + run: "click", + }, + ], + }); diff --git a/website_sale_checkout_address_no_save/tests/__init__.py b/website_sale_checkout_address_no_save/tests/__init__.py new file mode 100644 index 0000000000..d2f0c087bb --- /dev/null +++ b/website_sale_checkout_address_no_save/tests/__init__.py @@ -0,0 +1 @@ +from . import test_checkout_address_no_save diff --git a/website_sale_checkout_address_no_save/tests/test_checkout_address_no_save.py b/website_sale_checkout_address_no_save/tests/test_checkout_address_no_save.py new file mode 100644 index 0000000000..96d4a428a1 --- /dev/null +++ b/website_sale_checkout_address_no_save/tests/test_checkout_address_no_save.py @@ -0,0 +1,72 @@ +# Copyright 2026 Tecnativa - Eduardo Ezerouali +# License AGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). +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() + 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.viewref( + "website_sale_checkout_address_no_save.archive_address_dropshipping" + ).active = True + self.user = new_test_user( + self.env, + login="super_mario", + groups="base.group_portal", + password="super_mario", + name="Super Mario", + ) + + def test_ui_website(self): + """Test frontend tour.""" + if self.env["ir.module.module"]._get("payment_custom").state != "installed": + self.start_tour( + "/shop", + "website_sale_checkout_address_no_save_no_pay", + stepDelay=100, + login="super_mario", + ) + partner = self.user.partner_id + self.assertTrue(partner.child_ids.active) + else: + transfer_provider = self.env.ref("payment.payment_provider_transfer") + transfer_provider.write( + { + "state": "enabled", + "is_published": True, + } + ) + transfer_provider._transfer_ensure_pending_msg_is_set() + self.start_tour( + "/shop", + "website_sale_checkout_address_no_save", + stepDelay=100, + login="super_mario", + ) + # Assert that the partner have metadata logs + partner = self.user.partner_id + self.assertFalse(partner.child_ids.active) diff --git a/website_sale_checkout_address_no_save/views/website_sale_templates.xml b/website_sale_checkout_address_no_save/views/website_sale_templates.xml new file mode 100644 index 0000000000..ac668508a9 --- /dev/null +++ b/website_sale_checkout_address_no_save/views/website_sale_templates.xml @@ -0,0 +1,26 @@ + + + + + +