-
-
Notifications
You must be signed in to change notification settings - Fork 564
[19.0][ADD] website_sale_one_time_delivery_address #1245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Ricardoalso
wants to merge
1
commit into
OCA:19.0
Choose a base branch
from
camptocamp:website_sale_one_time_delivery_address
base: 19.0
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| .. image:: https://odoo-community.org/readme-banner-image | ||
| :target: https://odoo-community.org/get-involved?utm_source=readme | ||
| :alt: Odoo Community Association | ||
|
|
||
| ====================================== | ||
| Website Sale One Time Delivery Address | ||
| ====================================== | ||
|
|
||
| .. | ||
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
| !! This file is generated by oca-gen-addon-readme !! | ||
| !! changes will be overwritten. !! | ||
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
| !! source digest: sha256:bbb4c0ac6f4dc68d3f0e8be3ee9aafd262305ea2f1d9c28d935ff8033597fbc5 | ||
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
|
|
||
| .. |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_one_time_delivery_address | ||
| :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_one_time_delivery_address | ||
| :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 the website checkout delivery flow for | ||
| reseller-driven orders. | ||
|
|
||
| When the shopper enables the one-time delivery option during checkout, | ||
| the delivery address entered on the website is stored as a child contact | ||
| of the reseller with type ``one_time_delivery``. | ||
|
|
||
| This allows downstream processes such as EDI to keep a dedicated | ||
| recipient contact on the sale order while preserving the reseller as the | ||
| billing partner. | ||
|
|
||
| Main behavior: | ||
|
|
||
| - adds an *Allow Drop-shipping* flag on the customer that gates the | ||
| whole flow: the one-time delivery option is only shown for customers | ||
| that allow drop-shipping | ||
| - adds a one-time delivery toggle to the checkout page | ||
| - creates checkout delivery contacts with type ``one_time_delivery`` | ||
| - keeps the invoice address on the reseller | ||
| - keeps the shipping address on the temporary end-customer contact | ||
| - makes one-time delivery contacts available in the checkout delivery | ||
| address list | ||
|
|
||
| **Table of contents** | ||
|
|
||
| .. contents:: | ||
| :local: | ||
|
|
||
| Configuration | ||
| ============= | ||
|
|
||
| The one-time delivery flow is only offered to customers that are allowed | ||
| to drop-ship. | ||
|
|
||
| To enable it for a customer: | ||
|
|
||
| 1. Open the customer's contact form. | ||
| 2. Tick *Allow Drop-shipping*. | ||
|
|
||
| The one-time delivery option then appears on the website checkout for | ||
| orders placed by that customer (the flag is read from the customer's | ||
| commercial entity, so it applies to all of its contacts). Customers | ||
| without the flag never see the option. | ||
|
|
||
| Usage | ||
| ===== | ||
|
|
||
| To use this module, you need to: | ||
|
|
||
| 1. Add products to the cart and go to the checkout. | ||
| 2. In the delivery section, enable *One-Time Delivery Address*. | ||
| 3. Enter the final recipient address. | ||
| 4. Submit the delivery address form. | ||
|
|
||
| Result: | ||
|
|
||
| - a child contact is created on the reseller with type | ||
| ``one_time_delivery`` | ||
| - the sale order shipping partner points to that new contact | ||
| - the sale order invoice partner remains the reseller, even if the | ||
| browser submits a delivery-as-billing value | ||
| - the *Same as delivery address* toggle is hidden while the option is | ||
| enabled, so the temporary delivery address can never be reused as the | ||
| billing address | ||
|
|
||
| If the shopper disables the option, the standard website sale delivery | ||
| address behavior is kept and a regular ``delivery`` address is created | ||
| instead. | ||
|
|
||
| Automatic archiving | ||
| ------------------- | ||
|
|
||
| One-time delivery contacts are temporary by nature. As soon as the sale | ||
| order is confirmed, its ``one_time_delivery`` shipping contact is | ||
| automatically archived so it stops cluttering the address book. | ||
| Archiving is reversible and the contact remains readable on the related | ||
| stock pickings and order history. | ||
|
|
||
| Bug Tracker | ||
| =========== | ||
|
|
||
| Bugs are tracked on `GitHub Issues <https://github.com/OCA/e-commerce/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 <https://github.com/OCA/e-commerce/issues/new?body=module:%20website_sale_one_time_delivery_address%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. | ||
|
|
||
| Do not contact contributors directly about support or help with technical issues. | ||
|
|
||
| Credits | ||
| ======= | ||
|
|
||
| Authors | ||
| ------- | ||
|
|
||
| * Camptocamp | ||
|
|
||
| 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 <https://github.com/OCA/e-commerce/tree/19.0/website_sale_one_time_delivery_address>`_ project on GitHub. | ||
|
|
||
| You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| from . import controllers | ||
| from . import models |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Copyright 2026 Camptocamp | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
|
||
| { | ||
| "name": "Website Sale One Time Delivery Address", | ||
| "summary": "Create one-time delivery contacts from checkout delivery addresses", | ||
| "version": "19.0.1.0.0", | ||
| "development_status": "Beta", | ||
| "category": "Website", | ||
| "website": "https://github.com/OCA/e-commerce", | ||
| "author": "Camptocamp, Odoo Community Association (OCA)", | ||
| "license": "AGPL-3", | ||
| "application": False, | ||
| "depends": ["sale_stock", "website_sale"], | ||
| "data": [ | ||
| "views/res_partner_views.xml", | ||
| "views/templates.xml", | ||
| ], | ||
| "assets": { | ||
| "web.assets_frontend": [ | ||
| "website_sale_one_time_delivery_address/static/src/interactions/*.js", | ||
| ], | ||
| }, | ||
| "installable": True, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| from . import main |
125 changes: 125 additions & 0 deletions
125
website_sale_one_time_delivery_address/controllers/main.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| # Copyright 2026 Camptocamp | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
|
||
| from werkzeug.exceptions import Forbidden | ||
|
|
||
| from odoo.http import request, route | ||
|
|
||
| from odoo.addons.website_sale.controllers.main import WebsiteSale | ||
|
|
||
|
|
||
| class WebsiteSaleOneTimeDeliveryAddress(WebsiteSale): | ||
| def _prepare_checkout_page_values(self, order_sudo, **kwargs): | ||
| result = super()._prepare_checkout_page_values(order_sudo, **kwargs) | ||
| result["one_time_delivery"] = order_sudo.one_time_delivery | ||
| return result | ||
|
|
||
| @route("/shop/update_address", type="jsonrpc", auth="public", website=True) | ||
| def shop_update_address(self, partner_id, address_type="billing", **kw): | ||
| """Keep one_time_delivery in sync with the selected delivery partner. | ||
|
|
||
| Selecting a delivery address that is a one_time_delivery contact puts the | ||
| order in one-time mode (billing must stay on the reseller); selecting any | ||
| other delivery address leaves one-time mode. The parent security check | ||
| excludes one_time_delivery contacts from the allowed children, so for | ||
| those we validate ownership and set the shipping partner directly. | ||
| """ | ||
| order_sudo = request.cart | ||
| if order_sudo and address_type == "delivery": | ||
| ResPartner = request.env["res.partner"].sudo() | ||
| partner_sudo = ResPartner.browse(int(partner_id)).exists() | ||
| if partner_sudo.type == "one_time_delivery": | ||
| if ( | ||
| not order_sudo.allow_dropship | ||
| or partner_sudo.commercial_partner_id | ||
| != order_sudo.partner_id.commercial_partner_id | ||
| ): | ||
| raise Forbidden() | ||
| order_sudo.one_time_delivery = True | ||
| if partner_sudo != order_sudo.partner_shipping_id: | ||
| order_sudo._update_address(partner_sudo.id, {"partner_shipping_id"}) | ||
| return | ||
| order_sudo.one_time_delivery = False | ||
| return super().shop_update_address(partner_id, address_type=address_type, **kw) | ||
|
|
||
| @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, | ||
| **form_data, | ||
| ): | ||
| """Override to enforce billing-stays-reseller when one_time_delivery is active. | ||
|
|
||
| When the order has one_time_delivery=True and a delivery address is being | ||
| submitted, we force use_delivery_as_billing=None so that: | ||
| - portal never sets type='other' | ||
| - partner_invoice_id is never updated by the parent logic | ||
| """ | ||
| order_sudo = request.cart | ||
| if order_sudo and order_sudo.one_time_delivery and address_type == "delivery": | ||
| use_delivery_as_billing = None | ||
| return super().shop_address_submit( | ||
| partner_id=partner_id, | ||
| address_type=address_type, | ||
| use_delivery_as_billing=use_delivery_as_billing, | ||
| callback=callback, | ||
| **form_data, | ||
| ) | ||
|
|
||
| def _complete_address_values( | ||
| self, | ||
| address_values, | ||
| address_type, | ||
| use_delivery_as_billing, | ||
| *args, | ||
| order_sudo=False, | ||
| **kwargs, | ||
| ): | ||
| result = super()._complete_address_values( | ||
| address_values, | ||
| address_type, | ||
| use_delivery_as_billing, | ||
| *args, | ||
| order_sudo=order_sudo, | ||
| **kwargs, | ||
| ) | ||
| # After all parent logic has set the type, override it to one_time_delivery | ||
| # when the order is in one-time delivery mode and we are creating | ||
| # a delivery address. use_delivery_as_billing is already stripped | ||
| # to None by shop_address_submit, so | ||
| # this check is safe to run unconditionally for delivery addresses. | ||
| if address_type == "delivery" and order_sudo and order_sudo.one_time_delivery: | ||
| address_values["type"] = "one_time_delivery" | ||
| return result | ||
|
|
||
| @route( | ||
| "/shop/update_one_time_delivery", | ||
| type="jsonrpc", | ||
| auth="public", | ||
| website=True, | ||
| methods=["POST"], | ||
| ) | ||
| def shop_update_one_time_delivery(self, one_time_delivery=False, **kwargs): | ||
| """Toggle one-time delivery mode on the current cart. | ||
|
|
||
| The mode can only be enabled for customers that allow drop-shipping; | ||
| for any other customer the flag is forced to False, regardless of what | ||
| the request asks for. | ||
| """ | ||
| order_sudo = request.cart | ||
| if not order_sudo: | ||
| return {} | ||
| order_sudo.one_time_delivery = ( | ||
| bool(one_time_delivery) and order_sudo.allow_dropship | ||
| ) | ||
| return {} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| from . import res_partner | ||
| from . import sale_order |
37 changes: 37 additions & 0 deletions
37
website_sale_one_time_delivery_address/models/res_partner.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # Copyright 2026 Camptocamp | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
|
||
| from odoo import fields, models | ||
| from odoo.fields import Domain | ||
|
|
||
|
|
||
| class ResPartner(models.Model): | ||
| _inherit = "res.partner" | ||
|
|
||
| type = fields.Selection( | ||
| selection_add=[("one_time_delivery", "One-Time Delivery Address")], | ||
| ondelete={"one_time_delivery": "set default"}, | ||
| ) | ||
| allow_dropship = fields.Boolean( | ||
| string="Allow Drop-shipping", | ||
| help=( | ||
| "When enabled, this customer can use the one-time delivery flow " | ||
| "during the website checkout: the delivery address is stored as a " | ||
| "temporary 'one_time_delivery' contact while billing stays on the " | ||
| "customer. The one-time delivery option is hidden for customers " | ||
| "that do not allow drop-shipping." | ||
| ), | ||
| ) | ||
|
|
||
| def _get_delivery_address_domain(self): | ||
| # Extend the delivery address domain to also list one_time_delivery | ||
| # contacts alongside the standard 'delivery'/'other' addresses. | ||
| res = super()._get_delivery_address_domain() | ||
| if all(partner.allow_dropship for partner in self): | ||
| res |= Domain( | ||
| [ | ||
| ("commercial_partner_id", "in", self.commercial_partner_id.ids), | ||
| ("type", "=", "one_time_delivery"), | ||
| ] | ||
| ) | ||
| return res |
38 changes: 38 additions & 0 deletions
38
website_sale_one_time_delivery_address/models/sale_order.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| # Copyright 2026 Camptocamp | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
|
||
| from odoo import fields, models | ||
|
|
||
|
|
||
| class SaleOrder(models.Model): | ||
| _inherit = "sale.order" | ||
|
|
||
| one_time_delivery = fields.Boolean( | ||
| string="One-Time Delivery Address", | ||
| help=( | ||
| "When enabled, the delivery address created during the website " | ||
| "checkout is stored as a temporary contact with type " | ||
| "'one_time_delivery' instead of the standard 'delivery' type. " | ||
| "This keeps the recipient out of the customer's regular address " | ||
| "book and is useful for reseller orders shipped to an end customer." | ||
| ), | ||
| ) | ||
| allow_dropship = fields.Boolean( | ||
| related="partner_id.commercial_partner_id.allow_dropship", | ||
| ) | ||
|
|
||
| def action_confirm(self): | ||
| """Archive one-time delivery contacts once the order is confirmed. | ||
|
|
||
| A one_time_delivery contact is a temporary recipient that is no longer | ||
| needed for editing once the order is placed. Archiving (not deleting) | ||
| keeps it out of the address book while remaining readable on the | ||
| related pickings and order history. | ||
| """ | ||
| res = super().action_confirm() | ||
| one_time_partners = self.partner_shipping_id.filtered( | ||
| lambda partner: partner.type == "one_time_delivery" | ||
| ) | ||
| if one_time_partners: | ||
| one_time_partners.action_archive() | ||
| return res |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| [build-system] | ||
| requires = ["whool"] | ||
| build-backend = "whool.buildapi" |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.