Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions website_sale_partner_sale_contact/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=================================
Website Sale Partner Sale Contact
=================================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:a97afabdba1c7de2fd5a2a49bbb947ca1b9727d576350567212ad381754b8ce3
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-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_partner_sale_contact
: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_partner_sale_contact
: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|

When an order is placed from the website, the logged-in user is usually
a child contact of a company. Standard ``website_sale`` sets that
contact as the order customer (``partner_id``).

This module mirrors the backend ``sale_partner_sale_contact`` behaviour
on the website: the **parent company** becomes the order customer and
the **contact** is stored in the **Sale Contact** field
(``sale_contact_partner_id``). Billing and shipping addresses are left
untouched.

**Table of contents**

.. contents::
:local:

Usage
=====

This module is an auto-installed bridge: it activates automatically when
both ``website_sale`` and ``sale_partner_sale_contact`` are installed.
No configuration is required.

When a contact places an order from the website (cart creation, login,
or the guest checkout flow), the order's customer is set to the parent
company and the contact is recorded in the **Sale Contact** field.

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_partner_sale_contact%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
-------

* ForgeFlow

Contributors
------------

- `ForgeFlow <https://www.forgeflow.com>`__:

- Jasmin Solanki <jasmin.solanki@forgeflow.com>

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_partner_sale_contact>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions website_sale_partner_sale_contact/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
20 changes: 20 additions & 0 deletions website_sale_partner_sale_contact/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2026 ForgeFlow S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).

{
"name": "Website Sale Partner Sale Contact",
"summary": "Set the parent company as customer and the contact as sale "
"contact on website orders",
"version": "19.0.1.0.0",
"category": "Website",
"website": "https://github.com/OCA/e-commerce",
"author": "ForgeFlow, Odoo Community Association (OCA)",
"license": "LGPL-3",
"application": False,
"installable": True,
"auto_install": True,
"depends": [
"website_sale",
"sale_partner_sale_contact",
],
}
3 changes: 3 additions & 0 deletions website_sale_partner_sale_contact/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import res_partner
from . import website
from . import sale_order
32 changes: 32 additions & 0 deletions website_sale_partner_sale_contact/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2026 ForgeFlow S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).

from odoo import models


class ResPartner(models.Model):
_inherit = "res.partner"

def _get_sale_contact_company(self):
"""Return the company to use as customer for this website partner.

- Child contact of a company: the commercial (root) company.
- Individual with a typed ``company_name`` but no company parent: find
(by name) or create that company and link this contact under it.
- Otherwise: an empty recordset (no split needed).
"""
self.ensure_one()
commercial = self.commercial_partner_id
if commercial and commercial != self:
return commercial
if not self.is_company and self.company_name:
company = self.search(
[("is_company", "=", True), ("name", "=", self.company_name)],
limit=1,
)
if not company:
company = self.create({"name": self.company_name, "is_company": True})
if self.parent_id != company:
self.parent_id = company
Comment on lines +29 to +30

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if-condition seems pointless. We've just created company so it's safe to assume it's not the contact's parent

Suggested change
if self.parent_id != company:
self.parent_id = company
self.parent_id = company

return company
return self.browse()
23 changes: 23 additions & 0 deletions website_sale_partner_sale_contact/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2026 ForgeFlow S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).

from odoo import models


class SaleOrder(models.Model):
_inherit = "sale.order"

def _update_address(self, partner_id, fnames=None):
"""Remap only the customer to the company; keep entered addresses."""
if fnames and "partner_id" in fnames:
partner = self.env["res.partner"].browse(partner_id)
company = partner._get_sale_contact_company()
if company:
address_fnames = [name for name in fnames if name != "partner_id"]
res = super()._update_address(company.id, ["partner_id"])
if address_fnames:
# Re-apply entered addresses; the customer change reset them.
res = super()._update_address(partner_id, address_fnames)
self.sale_contact_partner_id = partner
return res
return super()._update_address(partner_id, fnames)
17 changes: 17 additions & 0 deletions website_sale_partner_sale_contact/models/website.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2026 ForgeFlow S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).

from odoo import models


class Website(models.Model):
_inherit = "website"

def _prepare_sale_order_values(self, partner_sudo):
"""Set the company as customer and the contact as sale contact."""
values = super()._prepare_sale_order_values(partner_sudo)
company_sudo = partner_sudo._get_sale_contact_company()
if company_sudo:
values["partner_id"] = company_sudo.id
values["sale_contact_partner_id"] = partner_sudo.id
return values
3 changes: 3 additions & 0 deletions website_sale_partner_sale_contact/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
2 changes: 2 additions & 0 deletions website_sale_partner_sale_contact/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- [ForgeFlow](https://www.forgeflow.com):
- Jasmin Solanki \<jasmin.solanki@forgeflow.com\>
8 changes: 8 additions & 0 deletions website_sale_partner_sale_contact/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
When an order is placed from the website, the logged-in user is usually a
child contact of a company. Standard `website_sale` sets that contact as the
order customer (`partner_id`).

This module mirrors the backend `sale_partner_sale_contact` behaviour on the
website: the **parent company** becomes the order customer and the **contact**
is stored in the **Sale Contact** field (`sale_contact_partner_id`). Billing
and shipping addresses are left untouched.
7 changes: 7 additions & 0 deletions website_sale_partner_sale_contact/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This module is an auto-installed bridge: it activates automatically when both
`website_sale` and `sale_partner_sale_contact` are installed. No configuration
is required.

When a contact places an order from the website (cart creation, login, or the
guest checkout flow), the order's customer is set to the parent company and the
contact is recorded in the **Sale Contact** field.
Loading
Loading