Skip to content

Commit 0fb37f3

Browse files
committed
[16.0][ADD] sale_partner_sale_contact: Add sale contact to orders and invoices
This module adds the ability to specify a contact person for sale orders and invoices, separate from the main customer. Features: * Add Sale Contact field on sale orders and invoices * Propagate sale contact from sale order to invoice * Display sale contact on PDF reports (configurable) * Configuration option in Settings > Sales to enable/disable display * Domain restriction: only child contacts of the customer can be selected * OnChange logic to clear incompatible contacts when customer changes Technical implementation: * New field sale_contact_partner_id on sale.order and account.move * Company-level configuration field sale_display_contact_on_reports * Report template inheritance for sale orders and invoices * French translations included
1 parent c6ae604 commit 0fb37f3

24 files changed

+1277
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
=========================
2+
Sale Partner Sale Contact
3+
=========================
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:1fe2b540490154ded20492736a3f1e5e47e9ec9ec21be5980a7a6a0767324e6e
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Beta
16+
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
18+
:alt: License: AGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github
20+
:target: https://github.com/OCA/sale-workflow/tree/16.0/sale_partner_sale_contact
21+
:alt: OCA/sale-workflow
22+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
23+
:target: https://translation.odoo-community.org/projects/sale-workflow-16-0/sale-workflow-16-0-sale_partner_sale_contact
24+
:alt: Translate me on Weblate
25+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
26+
:target: https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&target_branch=16.0
27+
:alt: Try me on Runboat
28+
29+
|badge1| |badge2| |badge3| |badge4| |badge5|
30+
31+
This module adds a **Sale Contact** field to quotations, sale orders, and invoices.
32+
33+
The sale contact field allows you to:
34+
35+
* Select a specific contact person for a sale order or quotation
36+
* Automatically propagate the contact from sale order to generated invoices
37+
* Display the contact person on PDF reports (quotations, orders, invoices)
38+
39+
The contact must be a child contact (person) of the selected customer.
40+
41+
**Table of contents**
42+
43+
.. contents::
44+
:local:
45+
46+
Configuration
47+
=============
48+
49+
To configure the module:
50+
51+
#. Go to **Settings > Sales > Quotations & Orders**
52+
#. Enable/disable **Display sale contact on reports**
53+
#. This option is enabled by default
54+
#. When enabled, the sale contact will appear on PDF reports for sale orders and invoices
55+
56+
Usage
57+
=====
58+
59+
To use this module, follow these steps:
60+
61+
#. Go to *Settings > Sales > Quotations & Orders*
62+
#. Enable the **Display sale contact on reports** option to show the sale contact on PDF reports (enabled by default)
63+
#. Go to *Sales > Orders > Quotations* or *Sales > Orders > Orders*
64+
#. Create or open a sale order
65+
#. After selecting a customer, you can select a **Sale Contact** from the customer's child contacts
66+
#. If the configuration option is enabled, the sale contact will appear on the printed quotation/order PDF
67+
#. When you create an invoice from the sale order, the sale contact will be automatically copied to the invoice
68+
#. If the configuration option is enabled, the sale contact will also appear on the printed invoice PDF
69+
70+
**Note**: Only contacts that are people (not companies) and are direct children of the selected customer will be available for selection.
71+
72+
Bug Tracker
73+
===========
74+
75+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/sale-workflow/issues>`_.
76+
In case of trouble, please check there if your issue has already been reported.
77+
If you spotted it first, help us to smash it by providing a detailed and welcomed
78+
`feedback <https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_partner_sale_contact%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
79+
80+
Do not contact contributors directly about support or help with technical issues.
81+
82+
Credits
83+
=======
84+
85+
Authors
86+
~~~~~~~
87+
88+
* OpenStudio SAS
89+
90+
Contributors
91+
~~~~~~~~~~~~
92+
93+
* Simon Maillard (maisim) <[email protected]>
94+
95+
Maintainers
96+
~~~~~~~~~~~
97+
98+
This module is maintained by the OCA.
99+
100+
.. image:: https://odoo-community.org/logo.png
101+
:alt: Odoo Community Association
102+
:target: https://odoo-community.org
103+
104+
OCA, or the Odoo Community Association, is a nonprofit organization whose
105+
mission is to support the collaborative development of Odoo features and
106+
promote its widespread use.
107+
108+
.. |maintainer-maisim| image:: https://github.com/maisim.png?size=40px
109+
:target: https://github.com/maisim
110+
:alt: maisim
111+
112+
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
113+
114+
|maintainer-maisim|
115+
116+
This module is part of the `OCA/sale-workflow <https://github.com/OCA/sale-workflow/tree/16.0/sale_partner_sale_contact>`_ project on GitHub.
117+
118+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright 2025 Odoo Community Association (OCA)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from . import models
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright 2025 Odoo Community Association (OCA)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
{
5+
"name": "Sale Partner Sale Contact",
6+
"summary": "Add sale contact person field to quotations, orders, and invoices",
7+
"version": "16.0.1.0.0",
8+
"category": "Sales Management",
9+
"website": "https://github.com/OCA/sale-workflow",
10+
"author": "OpenStudio SAS, Odoo Community Association (OCA)",
11+
"maintainers": ["maisim"],
12+
"license": "AGPL-3",
13+
"application": False,
14+
"installable": True,
15+
"depends": [
16+
"sale_management",
17+
"account",
18+
],
19+
"data": [
20+
"views/sale_order_views.xml",
21+
"views/account_move_views.xml",
22+
"views/res_config_settings_views.xml",
23+
"reports/sale_order_report_templates.xml",
24+
"reports/account_invoice_report_templates.xml",
25+
],
26+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Translation of Odoo Server.
2+
# This file contains the translation of the following modules:
3+
# * sale_partner_sale_contact
4+
#
5+
msgid ""
6+
msgstr ""
7+
"Project-Id-Version: Odoo Server 16.0\n"
8+
"Report-Msgid-Bugs-To: \n"
9+
"Last-Translator: Automatically generated\n"
10+
"Language-Team: none\n"
11+
"MIME-Version: 1.0\n"
12+
"Content-Type: text/plain; charset=UTF-8\n"
13+
"Content-Transfer-Encoding: 8bit\n"
14+
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
15+
"Language: fr\n"
16+
17+
#. module: sale_partner_sale_contact
18+
#: model_terms:ir.ui.view,arch_db:sale_partner_sale_contact.report_invoice_document
19+
#: model_terms:ir.ui.view,arch_db:sale_partner_sale_contact.report_saleorder_document
20+
msgid ""
21+
"<br/>\n"
22+
" <strong>Sale Contact:</strong>"
23+
msgstr ""
24+
"<br/>\n"
25+
" <strong>Contact Commercial :</strong>"
26+
27+
#. module: sale_partner_sale_contact
28+
#: model:ir.model,name:sale_partner_sale_contact.model_res_company
29+
msgid "Companies"
30+
msgstr "Sociétés"
31+
32+
#. module: sale_partner_sale_contact
33+
#: model:ir.model,name:sale_partner_sale_contact.model_res_config_settings
34+
msgid "Config Settings"
35+
msgstr "Paramètres de configuration"
36+
37+
#. module: sale_partner_sale_contact
38+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_account_bank_statement_line__sale_contact_partner_id
39+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_account_move__sale_contact_partner_id
40+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_account_payment__sale_contact_partner_id
41+
msgid ""
42+
"Contact person for this invoice. Only child contacts of the partner can be "
43+
"selected."
44+
msgstr ""
45+
"Personne de contact pour cette facture. Seuls les contacts enfants du "
46+
"partenaire peuvent être sélectionnés."
47+
48+
#. module: sale_partner_sale_contact
49+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_sale_order__sale_contact_partner_id
50+
msgid ""
51+
"Contact person for this sale order. Only child contacts of the customer can "
52+
"be selected."
53+
msgstr ""
54+
"Personne de contact pour cette commande de vente. Seuls les contacts enfants "
55+
"du client peuvent être sélectionnés."
56+
57+
#. module: sale_partner_sale_contact
58+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_res_company__sale_display_contact_on_reports
59+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_res_config_settings__sale_display_contact_on_reports
60+
msgid "Display sale contact on reports"
61+
msgstr "Afficher le contact commercial sur les rapports"
62+
63+
#. module: sale_partner_sale_contact
64+
#: model_terms:ir.ui.view,arch_db:sale_partner_sale_contact.res_config_settings_view_form
65+
msgid "Display the sale contact on sale orders and invoices PDF reports"
66+
msgstr "Afficher le contact commercial sur les commandes de vente et les factures PDF"
67+
68+
#. module: sale_partner_sale_contact
69+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_res_company__sale_display_contact_on_reports
70+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_res_config_settings__sale_display_contact_on_reports
71+
msgid ""
72+
"If enabled, the sale contact will be displayed on sale orders and invoices "
73+
"PDF reports."
74+
msgstr ""
75+
"Si activé, le contact commercial sera affiché sur les commandes de vente et "
76+
"les factures PDF."
77+
78+
#. module: sale_partner_sale_contact
79+
#: model:ir.model,name:sale_partner_sale_contact.model_account_move
80+
msgid "Journal Entry"
81+
msgstr "Écriture comptable"
82+
83+
#. module: sale_partner_sale_contact
84+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_account_bank_statement_line__sale_contact_partner_id
85+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_account_move__sale_contact_partner_id
86+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_account_payment__sale_contact_partner_id
87+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_sale_order__sale_contact_partner_id
88+
msgid "Sale Contact"
89+
msgstr "Contact Commercial"
90+
91+
#. module: sale_partner_sale_contact
92+
#: model:ir.model,name:sale_partner_sale_contact.model_sale_order
93+
msgid "Sales Order"
94+
msgstr "Bon de commande"
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Translation of Odoo Server.
2+
# This file contains the translation of the following modules:
3+
# * sale_partner_sale_contact
4+
#
5+
msgid ""
6+
msgstr ""
7+
"Project-Id-Version: Odoo Server 16.0\n"
8+
"Report-Msgid-Bugs-To: \n"
9+
"Last-Translator: \n"
10+
"Language-Team: \n"
11+
"MIME-Version: 1.0\n"
12+
"Content-Type: text/plain; charset=UTF-8\n"
13+
"Content-Transfer-Encoding: \n"
14+
"Plural-Forms: \n"
15+
16+
#. module: sale_partner_sale_contact
17+
#: model_terms:ir.ui.view,arch_db:sale_partner_sale_contact.report_invoice_document
18+
#: model_terms:ir.ui.view,arch_db:sale_partner_sale_contact.report_saleorder_document
19+
msgid ""
20+
"<br/>\n"
21+
" <strong>Sale Contact:</strong>"
22+
msgstr ""
23+
24+
#. module: sale_partner_sale_contact
25+
#: model:ir.model,name:sale_partner_sale_contact.model_res_company
26+
msgid "Companies"
27+
msgstr ""
28+
29+
#. module: sale_partner_sale_contact
30+
#: model:ir.model,name:sale_partner_sale_contact.model_res_config_settings
31+
msgid "Config Settings"
32+
msgstr ""
33+
34+
#. module: sale_partner_sale_contact
35+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_account_bank_statement_line__sale_contact_partner_id
36+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_account_move__sale_contact_partner_id
37+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_account_payment__sale_contact_partner_id
38+
msgid ""
39+
"Contact person for this invoice. Only child contacts of the partner can be "
40+
"selected."
41+
msgstr ""
42+
43+
#. module: sale_partner_sale_contact
44+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_sale_order__sale_contact_partner_id
45+
msgid ""
46+
"Contact person for this sale order. Only child contacts of the customer can "
47+
"be selected."
48+
msgstr ""
49+
50+
#. module: sale_partner_sale_contact
51+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_res_company__sale_display_contact_on_reports
52+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_res_config_settings__sale_display_contact_on_reports
53+
msgid "Display sale contact on reports"
54+
msgstr ""
55+
56+
#. module: sale_partner_sale_contact
57+
#: model_terms:ir.ui.view,arch_db:sale_partner_sale_contact.res_config_settings_view_form
58+
msgid "Display the sale contact on sale orders and invoices PDF reports"
59+
msgstr ""
60+
61+
#. module: sale_partner_sale_contact
62+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_res_company__sale_display_contact_on_reports
63+
#: model:ir.model.fields,help:sale_partner_sale_contact.field_res_config_settings__sale_display_contact_on_reports
64+
msgid ""
65+
"If enabled, the sale contact will be displayed on sale orders and invoices "
66+
"PDF reports."
67+
msgstr ""
68+
69+
#. module: sale_partner_sale_contact
70+
#: model:ir.model,name:sale_partner_sale_contact.model_account_move
71+
msgid "Journal Entry"
72+
msgstr ""
73+
74+
#. module: sale_partner_sale_contact
75+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_account_bank_statement_line__sale_contact_partner_id
76+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_account_move__sale_contact_partner_id
77+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_account_payment__sale_contact_partner_id
78+
#: model:ir.model.fields,field_description:sale_partner_sale_contact.field_sale_order__sale_contact_partner_id
79+
msgid "Sale Contact"
80+
msgstr ""
81+
82+
#. module: sale_partner_sale_contact
83+
#: model:ir.model,name:sale_partner_sale_contact.model_sale_order
84+
msgid "Sales Order"
85+
msgstr ""
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copyright 2025 Odoo Community Association (OCA)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from . import account_move
5+
from . import res_company
6+
from . import res_config_settings
7+
from . import sale_order
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright 2025 Odoo Community Association (OCA)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from odoo import api, fields, models
5+
6+
7+
class AccountMove(models.Model):
8+
_inherit = "account.move"
9+
10+
sale_contact_partner_id = fields.Many2one(
11+
comodel_name="res.partner",
12+
string="Sale Contact",
13+
domain=(
14+
"[('id', 'child_of', partner_id), "
15+
"('is_company', '=', False), ('id', '!=', partner_id)]"
16+
),
17+
help="Contact person for this invoice. "
18+
"Only child contacts of the partner can be selected.",
19+
)
20+
21+
@api.onchange("partner_id")
22+
def _onchange_partner_id_clear_sale_contact(self):
23+
"""Clear sale contact when partner changes if it's not a child of new partner."""
24+
if self.sale_contact_partner_id:
25+
if (
26+
self.sale_contact_partner_id.parent_id != self.partner_id
27+
and self.sale_contact_partner_id != self.partner_id
28+
):
29+
self.sale_contact_partner_id = False
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright 2025 Odoo Community Association (OCA)
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
4+
from odoo import fields, models
5+
6+
7+
class ResCompany(models.Model):
8+
_inherit = "res.company"
9+
10+
sale_display_contact_on_reports = fields.Boolean(
11+
string="Display sale contact on reports",
12+
default=True,
13+
help=(
14+
"If enabled, the sale contact will be displayed on "
15+
"sale orders and invoices PDF reports."
16+
),
17+
)

0 commit comments

Comments
 (0)