From 33116141ccc1c4e9363743f2688f16177fcb553f Mon Sep 17 00:00:00 2001 From: Fernando Date: Thu, 21 May 2026 15:27:56 -0400 Subject: [PATCH 1/7] [FIX] partner_address_street3: copy street3 to child contacts --- README.md | 1 - partner_address_street3/models/res_partner.py | 31 ++ .../tests/test_street_3.py | 113 +++++ partner_category_description/README.rst | 111 ----- partner_category_description/__init__.py | 1 - partner_category_description/__manifest__.py | 23 - partner_category_description/i18n/es.po | 28 -- partner_category_description/i18n/it.po | 27 -- .../i18n/partner_category_description.pot | 34 -- .../models/__init__.py | 1 - .../models/res_partner_category.py | 10 - partner_category_description/pyproject.toml | 3 - .../readme/CONTRIBUTORS.md | 5 - .../readme/DESCRIPTION.md | 1 - partner_category_description/readme/USAGE.md | 4 - .../static/description/icon.png | Bin 9455 -> 0 bytes .../static/description/index.html | 452 ------------------ .../tests/__init__.py | 1 - .../test_partner_category_description.py | 21 - .../views/res_partner_category_views.xml | 36 -- setup/_metapackage/pyproject.toml | 2 - 21 files changed, 144 insertions(+), 761 deletions(-) delete mode 100644 partner_category_description/README.rst delete mode 100644 partner_category_description/__init__.py delete mode 100644 partner_category_description/__manifest__.py delete mode 100644 partner_category_description/i18n/es.po delete mode 100644 partner_category_description/i18n/it.po delete mode 100644 partner_category_description/i18n/partner_category_description.pot delete mode 100644 partner_category_description/models/__init__.py delete mode 100644 partner_category_description/models/res_partner_category.py delete mode 100644 partner_category_description/pyproject.toml delete mode 100644 partner_category_description/readme/CONTRIBUTORS.md delete mode 100644 partner_category_description/readme/DESCRIPTION.md delete mode 100644 partner_category_description/readme/USAGE.md delete mode 100644 partner_category_description/static/description/icon.png delete mode 100644 partner_category_description/static/description/index.html delete mode 100644 partner_category_description/tests/__init__.py delete mode 100644 partner_category_description/tests/test_partner_category_description.py delete mode 100644 partner_category_description/views/res_partner_category_views.xml diff --git a/README.md b/README.md index e1f33daefa5..d1d18d9ff4f 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,6 @@ addon | version | maintainers | summary [partner_address_street3](partner_address_street3/) | 19.0.1.0.0 | | Add a third address line on partners [partner_affiliate](partner_affiliate/) | 19.0.1.0.0 | | Partner Affiliates [partner_auto_archive](partner_auto_archive/) | 19.0.1.0.0 | | Archive periodically all contacts marked as auto-archive. -[partner_category_description](partner_category_description/) | 19.0.1.0.1 | edlopen rafaelbn | Adds a description field to contact categories to improve organization and managment of customer relationships. [partner_company_default](partner_company_default/) | 19.0.1.0.0 | | Partner Company Default [partner_company_group](partner_company_group/) | 19.0.1.0.0 | luisg123v | Adds the possibility to add a company group to a company [partner_company_type](partner_company_type/) | 19.0.1.0.0 | | Adds a company type to partner that are companies diff --git a/partner_address_street3/models/res_partner.py b/partner_address_street3/models/res_partner.py index 1b3a2f33db1..6c8a73610eb 100644 --- a/partner_address_street3/models/res_partner.py +++ b/partner_address_street3/models/res_partner.py @@ -2,6 +2,8 @@ # @author: Nicolas Bessi # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from lxml import etree + from odoo import api, fields, models @@ -18,6 +20,35 @@ def _address_fields(self): res.append("street3") return res + @api.model + def default_get(self, default_fields): + values = super().default_get(default_fields) + parent_id = self.env.context.get("default_parent_id") or values.get("parent_id") + if parent_id: + parent = self.browse(parent_id) + for field in self._address_fields(): + if field in default_fields and not values.get(field): + val = parent[field] + values[field] = val.id if isinstance(val, models.BaseModel) else val + return values + + @api.model + def get_view(self, view_id=None, view_type="form", **options): + res = super().get_view(view_id=view_id, view_type=view_type, **options) + if view_type == "form": + doc = etree.XML(res["arch"]) + for node in doc.xpath("//field[@name='child_ids']"): + context = node.get("context") + if not context: + node.set("context", "{'default_street3': street3}") + elif "default_street3" not in context: + context_str = context.strip() + if context_str.endswith("}"): + new_context = context_str[:-1] + ", 'default_street3': street3}" + node.set("context", new_context) + res["arch"] = etree.tostring(doc, encoding="unicode") + return res + def _display_address(self, without_company=False): """Remove empty lines which can happen when street3 field is empty.""" res = super()._display_address(without_company=without_company) diff --git a/partner_address_street3/tests/test_street_3.py b/partner_address_street3/tests/test_street_3.py index 93daad700d6..625605ae036 100644 --- a/partner_address_street3/tests/test_street_3.py +++ b/partner_address_street3/tests/test_street_3.py @@ -64,3 +64,116 @@ def test_uninstall(self): uninstall_hook(self.env) us_country = self.env.ref("base.us") self.assertTrue("%(street3)s" not in us_country.address_format) + + def test_default_get_copies_street3_from_parent(self): + parent = self.env["res.partner"].create( + { + "name": "Parent Company", + "street": "123 Main St", + "street2": "Floor 2", + "street3": "Suite 100", + "city": "Springfield", + "country_id": self.env.ref("base.us").id, + } + ) + Partner = self.env["res.partner"] + defaults = Partner.with_context(default_parent_id=parent.id).default_get( + ["name", "street", "street2", "street3", "city", "parent_id"] + ) + self.assertEqual(defaults.get("street3"), "Suite 100") + self.assertEqual(defaults.get("street2"), "Floor 2") + self.assertEqual(defaults.get("street"), "123 Main St") + self.assertEqual(defaults.get("parent_id"), parent.id) + + def test_child_ids_context_contains_street3(self): + view = self.env.ref("base.view_partner_form") + arch = self.env["res.partner"].get_view(view.id, view_type="form")["arch"] + self.assertIn("default_street3", arch) + + def test_get_view_various_scenarios(self): + # 1. view_type != "form" (e.g. search view) + search_view = self.env["ir.ui.view"].create( + { + "name": "test.partner.search", + "model": "res.partner", + "type": "search", + "arch": """ + + + + """, + } + ) + res = self.env["res.partner"].get_view(search_view.id, view_type="search") + self.assertNotIn("default_street3", res["arch"]) + + # 2. form view without child_ids field (xpath yields no match) + form_view_no_child_ids = self.env["ir.ui.view"].create( + { + "name": "test.partner.form.no.child.ids", + "model": "res.partner", + "type": "form", + "arch": """ +
+ + + """, + } + ) + res = self.env["res.partner"].get_view( + form_view_no_child_ids.id, view_type="form" + ) + self.assertNotIn("default_street3", res["arch"]) + + # 3. child_ids with no context attribute + form_view_no_context = self.env["ir.ui.view"].create( + { + "name": "test.partner.form.no.context", + "model": "res.partner", + "type": "form", + "arch": """ +
+ + + """, + } + ) + res = self.env["res.partner"].get_view( + form_view_no_context.id, view_type="form" + ) + self.assertIn("context=\"{'default_street3': street3}\"", res["arch"]) + + # 4. child_ids with context already containing default_street3 + form_view_existing = self.env["ir.ui.view"].create( + { + "name": "test.partner.form.existing", + "model": "res.partner", + "type": "form", + "arch": """ +
+ + + """, + } + ) + res = self.env["res.partner"].get_view(form_view_existing.id, view_type="form") + self.assertIn("context=\"{'default_street3': 'custom'}\"", res["arch"]) + self.assertNotIn("street3}", res["arch"]) # No duplicate injection + + # 5. child_ids with context string not ending with } (e.g. parenthesized dict) + form_view_invalid_context = self.env["ir.ui.view"].create( + { + "name": "test.partner.form.invalid.context", + "model": "res.partner", + "type": "form", + "arch": """ +
+ + + """, + } + ) + res = self.env["res.partner"].get_view( + form_view_invalid_context.id, view_type="form" + ) + self.assertNotIn("default_street3", res["arch"]) diff --git a/partner_category_description/README.rst b/partner_category_description/README.rst deleted file mode 100644 index c5d257bdc3f..00000000000 --- a/partner_category_description/README.rst +++ /dev/null @@ -1,111 +0,0 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - -============================ -Partner Category Description -============================ - -.. - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! This file is generated by oca-gen-addon-readme !! - !! changes will be overwritten. !! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:134864c8e3b41388b5d4e643fd2497e0b539f6b943a766c64a4ef83cf21aebbd - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png - :target: https://odoo-community.org/page/development-status - :alt: Alpha -.. |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%2Fpartner--contact-lightgray.png?logo=github - :target: https://github.com/OCA/partner-contact/tree/19.0/partner_category_description - :alt: OCA/partner-contact -.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/partner-contact-19-0/partner-contact-19-0-partner_category_description - :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/partner-contact&target_branch=19.0 - :alt: Try me on Runboat - -|badge1| |badge2| |badge3| |badge4| |badge5| - -This module adds a description field to contact tags. - -.. IMPORTANT:: - This is an alpha version, the data model and design can change at any time without warning. - Only for development or testing purpose, do not use in production. - `More details on development status `_ - -**Table of contents** - -.. contents:: - :local: - -Usage -===== - -1. Create a Tag: Navigate to Contacts > Configuration > Contact Tags and - click on "Create" to add a new tag. - -2. Add a Description: Provide a detailed explanation of the tag's - purpose and criteria in the newly added "Description" field. - -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 -------- - -* Moduon - -Contributors ------------- - -- Eduardo L??pez (`Moduon `__) - -- `Heliconia Solutions Pvt. Ltd. `__ - - - Bhavesh Heliconia - -- Hudson Amadeus Leonardy (https://solusiaglis.co.id) - -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. - -.. |maintainer-edlopen| image:: https://github.com/edlopen.png?size=40px - :target: https://github.com/edlopen - :alt: edlopen -.. |maintainer-rafaelbn| image:: https://github.com/rafaelbn.png?size=40px - :target: https://github.com/rafaelbn - :alt: rafaelbn - -Current `maintainers `__: - -|maintainer-edlopen| |maintainer-rafaelbn| - -This module is part of the `OCA/partner-contact `_ project on GitHub. - -You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/partner_category_description/__init__.py b/partner_category_description/__init__.py deleted file mode 100644 index 0650744f6bc..00000000000 --- a/partner_category_description/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import models diff --git a/partner_category_description/__manifest__.py b/partner_category_description/__manifest__.py deleted file mode 100644 index 1a5dd628ae4..00000000000 --- a/partner_category_description/__manifest__.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2024 Moduon Team S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/LGPL-3.0) - -{ - "name": "Partner Category Description", - "summary": """Adds a description field to contact categories to improve - organization and managment of customer relationships.""", - "version": "19.0.1.0.1", - "development_status": "Alpha", - "category": "Marketing", - "website": "https://github.com/OCA/partner-contact", - "author": "Moduon, Odoo Community Association (OCA)", - "maintainers": ["edlopen", "rafaelbn"], - "license": "LGPL-3", - "application": False, - "installable": True, - "depends": [ - "contacts", - ], - "data": [ - "views/res_partner_category_views.xml", - ], -} diff --git a/partner_category_description/i18n/es.po b/partner_category_description/i18n/es.po deleted file mode 100644 index b87f70db70b..00000000000 --- a/partner_category_description/i18n/es.po +++ /dev/null @@ -1,28 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * partner_category_description -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 16.0+e\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-07-22 14:17+0000\n" -"PO-Revision-Date: 2024-07-22 16:18+0200\n" -"Last-Translator: Eduardo L??pez \n" -"Language-Team: \n" -"Language: es\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 3.4.4\n" - -#. module: partner_category_description -#: model:ir.model.fields,field_description:partner_category_description.field_res_partner_category__description -msgid "Description" -msgstr "Descripci??n" - -#. module: partner_category_description -#: model:ir.model,name:partner_category_description.model_res_partner_category -msgid "Partner Tags" -msgstr "Etiquetas del contacto" diff --git a/partner_category_description/i18n/it.po b/partner_category_description/i18n/it.po deleted file mode 100644 index f5bde11f0ce..00000000000 --- a/partner_category_description/i18n/it.po +++ /dev/null @@ -1,27 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * partner_category_description -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 16.0\n" -"Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2024-07-30 11:58+0000\n" -"Last-Translator: mymage \n" -"Language-Team: none\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.6.2\n" - -#. module: partner_category_description -#: model:ir.model.fields,field_description:partner_category_description.field_res_partner_category__description -msgid "Description" -msgstr "Descrizione" - -#. module: partner_category_description -#: model:ir.model,name:partner_category_description.model_res_partner_category -msgid "Partner Tags" -msgstr "Etichette partner" diff --git a/partner_category_description/i18n/partner_category_description.pot b/partner_category_description/i18n/partner_category_description.pot deleted file mode 100644 index 1dd921aec4c..00000000000 --- a/partner_category_description/i18n/partner_category_description.pot +++ /dev/null @@ -1,34 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * partner_category_description -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 19.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: partner_category_description -#: model:ir.model.fields,field_description:partner_category_description.field_res_partner_category__description -msgid "Description" -msgstr "" - -#. module: partner_category_description -#: model:ir.model.fields,field_description:partner_category_description.field_res_partner_category__display_name -msgid "Display Name" -msgstr "" - -#. module: partner_category_description -#: model:ir.model.fields,field_description:partner_category_description.field_res_partner_category__id -msgid "ID" -msgstr "" - -#. module: partner_category_description -#: model:ir.model,name:partner_category_description.model_res_partner_category -msgid "Partner Tags" -msgstr "" diff --git a/partner_category_description/models/__init__.py b/partner_category_description/models/__init__.py deleted file mode 100644 index da908a80fd6..00000000000 --- a/partner_category_description/models/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import res_partner_category diff --git a/partner_category_description/models/res_partner_category.py b/partner_category_description/models/res_partner_category.py deleted file mode 100644 index 13d8773b060..00000000000 --- a/partner_category_description/models/res_partner_category.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2024 Moduon Team S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/LGPL-3.0) - -from odoo import fields, models - - -class ResPartnerCategory(models.Model): - _inherit = "res.partner.category" - - description = fields.Char(translate=True) diff --git a/partner_category_description/pyproject.toml b/partner_category_description/pyproject.toml deleted file mode 100644 index 4231d0cccb3..00000000000 --- a/partner_category_description/pyproject.toml +++ /dev/null @@ -1,3 +0,0 @@ -[build-system] -requires = ["whool"] -build-backend = "whool.buildapi" diff --git a/partner_category_description/readme/CONTRIBUTORS.md b/partner_category_description/readme/CONTRIBUTORS.md deleted file mode 100644 index 092a31ea327..00000000000 --- a/partner_category_description/readme/CONTRIBUTORS.md +++ /dev/null @@ -1,5 +0,0 @@ -- Eduardo L??pez ([Moduon](https://www.moduon.team/)) -- [Heliconia Solutions Pvt. Ltd.](https://www.heliconia.io) - - Bhavesh Heliconia - -- Hudson Amadeus Leonardy (https://solusiaglis.co.id) diff --git a/partner_category_description/readme/DESCRIPTION.md b/partner_category_description/readme/DESCRIPTION.md deleted file mode 100644 index a2180398fd4..00000000000 --- a/partner_category_description/readme/DESCRIPTION.md +++ /dev/null @@ -1 +0,0 @@ -This module adds a description field to contact tags. diff --git a/partner_category_description/readme/USAGE.md b/partner_category_description/readme/USAGE.md deleted file mode 100644 index 88e7b0ce503..00000000000 --- a/partner_category_description/readme/USAGE.md +++ /dev/null @@ -1,4 +0,0 @@ -1. Create a Tag: Navigate to Contacts > Configuration > Contact Tags and click on "Create" to add a new tag. - -2. Add a Description: Provide a detailed explanation of the tag's purpose and -criteria in the newly added "Description" field. diff --git a/partner_category_description/static/description/icon.png b/partner_category_description/static/description/icon.png deleted file mode 100644 index 3a0328b516c4980e8e44cdb63fd945757ddd132d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I diff --git a/partner_category_description/static/description/index.html b/partner_category_description/static/description/index.html deleted file mode 100644 index 450532f0f5b..00000000000 --- a/partner_category_description/static/description/index.html +++ /dev/null @@ -1,452 +0,0 @@ - - - - - -README.rst - - - -
- - - -Odoo Community Association - -
-

Partner Category Description

- -

Alpha License: LGPL-3 OCA/partner-contact Translate me on Weblate Try me on Runboat

-

This module adds a description field to contact tags.

-
-

Important

-

This is an alpha version, the data model and design can change at any time without warning. -Only for development or testing purpose, do not use in production. -More details on development status

-
-

Table of contents

- -
-

Usage

-
    -
  1. Create a Tag: Navigate to Contacts > Configuration > Contact Tags and -click on “Create” to add a new tag.
  2. -
  3. Add a Description: Provide a detailed explanation of the tag’s -purpose and criteria in the newly added “Description” field.
  4. -
-
-
-

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

-
    -
  • Moduon
  • -
-
-
-

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.

-

Current maintainers:

-

edlopen rafaelbn

-

This module is part of the OCA/partner-contact project on GitHub.

-

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

-
-
-
-
- - diff --git a/partner_category_description/tests/__init__.py b/partner_category_description/tests/__init__.py deleted file mode 100644 index 30a2e1ecde4..00000000000 --- a/partner_category_description/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import test_partner_category_description diff --git a/partner_category_description/tests/test_partner_category_description.py b/partner_category_description/tests/test_partner_category_description.py deleted file mode 100644 index 6a78dd63ab8..00000000000 --- a/partner_category_description/tests/test_partner_category_description.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2024 Moduon Team S.L. -# License LGPL-3.0 or later (https://www.gnu.org/licenses/LGPL-3.0) - -from odoo.addons.base.tests.common import BaseCommon - - -class TestResPartnerCategory(BaseCommon): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.partner_category = cls.env["res.partner.category"].create( - {"name": "Test Category", "description": "This is a test description"} - ) - - def test_category_creation(self): - """Test that a partner category is created correctly.""" - self.assertTrue(self.partner_category, "Partner category should be created.") - self.assertEqual(self.partner_category.name, "Test Category") - self.assertEqual( - self.partner_category.description, "This is a test description" - ) diff --git a/partner_category_description/views/res_partner_category_views.xml b/partner_category_description/views/res_partner_category_views.xml deleted file mode 100644 index 9193765e86c..00000000000 --- a/partner_category_description/views/res_partner_category_views.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - res.partner.category - - - - - - - - - - res.partner.category - - - - - - - - - - - - res.partner.category - - - - - - - - diff --git a/setup/_metapackage/pyproject.toml b/setup/_metapackage/pyproject.toml index e033e0cbeb0..b40456428bb 100644 --- a/setup/_metapackage/pyproject.toml +++ b/setup/_metapackage/pyproject.toml @@ -12,7 +12,6 @@ dependencies = [ "odoo-addon-partner_address_street3==19.0.*", "odoo-addon-partner_affiliate==19.0.*", "odoo-addon-partner_auto_archive==19.0.*", - "odoo-addon-partner_category_description==19.0.*", "odoo-addon-partner_company_default==19.0.*", "odoo-addon-partner_company_group==19.0.*", "odoo-addon-partner_company_type==19.0.*", @@ -57,7 +56,6 @@ dependencies = [ "odoo-addon-partner_title_contacts==19.0.*", "odoo-addon-partner_type_base==19.0.*", "odoo-addon-partner_tz==19.0.*", - "odoo-addon-partner_uom_mapping==19.0.*", "odoo-addon-partner_utm_source==19.0.*", "odoo-addon-partner_vat_unique==19.0.*", "odoo-addon-sale_partner_company_group==19.0.*", From c1349a5e27b6f31a67876388de29f51aa491f9f9 Mon Sep 17 00:00:00 2001 From: Fernando Date: Wed, 27 May 2026 10:56:30 -0400 Subject: [PATCH 2/7] [FIX] partner_address_street3: use onchange instead of default_get+get_view for street3 copy Replace the default_get override (which fails with unsaved parents/NewId) and the get_view override (which injected default_street3 into child_ids context via lxml) with a simple onchange("parent_id") that extends base's onchange_parent_id to ensure street3 is always copied. The base onchange_parent_id already copies all _address_fields(), but the explicit setdefault guarantees street3 is included even when it's the only address field set on the parent. Co-authored-by: BhaveshHeliconia --- partner_address_street3/models/res_partner.py | 36 +---- .../tests/test_street_3.py | 129 +++++------------- 2 files changed, 40 insertions(+), 125 deletions(-) diff --git a/partner_address_street3/models/res_partner.py b/partner_address_street3/models/res_partner.py index 6c8a73610eb..cdb7895fbda 100644 --- a/partner_address_street3/models/res_partner.py +++ b/partner_address_street3/models/res_partner.py @@ -2,8 +2,6 @@ # @author: Nicolas Bessi # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from lxml import etree - from odoo import api, fields, models @@ -20,34 +18,12 @@ def _address_fields(self): res.append("street3") return res - @api.model - def default_get(self, default_fields): - values = super().default_get(default_fields) - parent_id = self.env.context.get("default_parent_id") or values.get("parent_id") - if parent_id: - parent = self.browse(parent_id) - for field in self._address_fields(): - if field in default_fields and not values.get(field): - val = parent[field] - values[field] = val.id if isinstance(val, models.BaseModel) else val - return values - - @api.model - def get_view(self, view_id=None, view_type="form", **options): - res = super().get_view(view_id=view_id, view_type=view_type, **options) - if view_type == "form": - doc = etree.XML(res["arch"]) - for node in doc.xpath("//field[@name='child_ids']"): - context = node.get("context") - if not context: - node.set("context", "{'default_street3': street3}") - elif "default_street3" not in context: - context_str = context.strip() - if context_str.endswith("}"): - new_context = context_str[:-1] + ", 'default_street3': street3}" - node.set("context", new_context) - res["arch"] = etree.tostring(doc, encoding="unicode") - return res + @api.onchange("parent_id") + def _onchange_parent_id_street3(self): + result = super().onchange_parent_id() or {} + if self.parent_id: + result.setdefault("value", {})["street3"] = self.parent_id.street3 + return result def _display_address(self, without_company=False): """Remove empty lines which can happen when street3 field is empty.""" diff --git a/partner_address_street3/tests/test_street_3.py b/partner_address_street3/tests/test_street_3.py index 625605ae036..b5f91e6cd54 100644 --- a/partner_address_street3/tests/test_street_3.py +++ b/partner_address_street3/tests/test_street_3.py @@ -65,7 +65,7 @@ def test_uninstall(self): us_country = self.env.ref("base.us") self.assertTrue("%(street3)s" not in us_country.address_format) - def test_default_get_copies_street3_from_parent(self): + def test_onchange_parent_id_copies_street3(self): parent = self.env["res.partner"].create( { "name": "Parent Company", @@ -76,104 +76,43 @@ def test_default_get_copies_street3_from_parent(self): "country_id": self.env.ref("base.us").id, } ) - Partner = self.env["res.partner"] - defaults = Partner.with_context(default_parent_id=parent.id).default_get( - ["name", "street", "street2", "street3", "city", "parent_id"] + partner = self.env["res.partner"].new( + {"name": "Child", "type": "contact", "parent_id": parent.id} ) - self.assertEqual(defaults.get("street3"), "Suite 100") - self.assertEqual(defaults.get("street2"), "Floor 2") - self.assertEqual(defaults.get("street"), "123 Main St") - self.assertEqual(defaults.get("parent_id"), parent.id) - - def test_child_ids_context_contains_street3(self): - view = self.env.ref("base.view_partner_form") - arch = self.env["res.partner"].get_view(view.id, view_type="form")["arch"] - self.assertIn("default_street3", arch) - - def test_get_view_various_scenarios(self): - # 1. view_type != "form" (e.g. search view) - search_view = self.env["ir.ui.view"].create( - { - "name": "test.partner.search", - "model": "res.partner", - "type": "search", - "arch": """ - - - - """, - } - ) - res = self.env["res.partner"].get_view(search_view.id, view_type="search") - self.assertNotIn("default_street3", res["arch"]) - - # 2. form view without child_ids field (xpath yields no match) - form_view_no_child_ids = self.env["ir.ui.view"].create( - { - "name": "test.partner.form.no.child.ids", - "model": "res.partner", - "type": "form", - "arch": """ -
- - - """, - } - ) - res = self.env["res.partner"].get_view( - form_view_no_child_ids.id, view_type="form" - ) - self.assertNotIn("default_street3", res["arch"]) - - # 3. child_ids with no context attribute - form_view_no_context = self.env["ir.ui.view"].create( - { - "name": "test.partner.form.no.context", - "model": "res.partner", - "type": "form", - "arch": """ -
- - - """, - } - ) - res = self.env["res.partner"].get_view( - form_view_no_context.id, view_type="form" + result = partner._onchange_parent_id_street3() + self.assertIsNotNone(result) + self.assertIn("value", result) + self.assertEqual(result["value"]["street3"], "Suite 100") + self.assertEqual(result["value"]["street2"], "Floor 2") + self.assertEqual(result["value"]["street"], "123 Main St") + + def test_onchange_parent_id_no_parent(self): + partner = self.env["res.partner"].new({"name": "Orphan", "type": "contact"}) + result = partner._onchange_parent_id_street3() + self.assertIsNone(result) + + def test_onchange_parent_id_preserves_empty_parent(self): + parent = self.env["res.partner"] + partner = self.env["res.partner"].new( + {"name": "Child", "type": "contact", "parent_id": False} ) - self.assertIn("context=\"{'default_street3': street3}\"", res["arch"]) + result = partner._onchange_parent_id_street3() + self.assertIsNone(result) - # 4. child_ids with context already containing default_street3 - form_view_existing = self.env["ir.ui.view"].create( - { - "name": "test.partner.form.existing", - "model": "res.partner", - "type": "form", - "arch": """ -
- - - """, - } - ) - res = self.env["res.partner"].get_view(form_view_existing.id, view_type="form") - self.assertIn("context=\"{'default_street3': 'custom'}\"", res["arch"]) - self.assertNotIn("street3}", res["arch"]) # No duplicate injection - - # 5. child_ids with context string not ending with } (e.g. parenthesized dict) - form_view_invalid_context = self.env["ir.ui.view"].create( + def test_onchange_parent_id_extends_base_result(self): + parent = self.env["res.partner"].create( { - "name": "test.partner.form.invalid.context", - "model": "res.partner", - "type": "form", - "arch": """ -
- - - """, + "name": "Parent Company", + "street": "123 Main St", + "city": "Springfield", } ) - res = self.env["res.partner"].get_view( - form_view_invalid_context.id, view_type="form" + partner = self.env["res.partner"].new( + {"name": "Child", "type": "contact", "parent_id": parent.id} ) - self.assertNotIn("default_street3", res["arch"]) + result = partner._onchange_parent_id_street3() + self.assertIsNotNone(result) + self.assertIn("value", result) + self.assertIn("street", result["value"]) + self.assertIn("street3", result["value"]) + self.assertIn("city", result["value"]) From 71a050298cb2a281f585574d7a3b216f0b068965 Mon Sep 17 00:00:00 2001 From: Fernando Date: Fri, 29 May 2026 14:01:47 -0400 Subject: [PATCH 3/7] [FIX] partner_address_street3: remove unused variable in test --- partner_address_street3/tests/test_street_3.py | 1 - 1 file changed, 1 deletion(-) diff --git a/partner_address_street3/tests/test_street_3.py b/partner_address_street3/tests/test_street_3.py index b5f91e6cd54..55b022776bc 100644 --- a/partner_address_street3/tests/test_street_3.py +++ b/partner_address_street3/tests/test_street_3.py @@ -92,7 +92,6 @@ def test_onchange_parent_id_no_parent(self): self.assertIsNone(result) def test_onchange_parent_id_preserves_empty_parent(self): - parent = self.env["res.partner"] partner = self.env["res.partner"].new( {"name": "Child", "type": "contact", "parent_id": False} ) From 0c468faee0c1e1310d1781df85ecaa1f289a4d9e Mon Sep 17 00:00:00 2001 From: Fernando Date: Fri, 29 May 2026 14:12:10 -0400 Subject: [PATCH 4/7] [FIX] partner_address_street3: handle Odoo 19 onchange return value In Odoo 19, onchange_parent_id() returns {} instead of None. Move the 'or {}' fallback after the parent_id check so the method preserves the base return value when there is no parent. Update tests to assert no street3 is added rather than asserting exact return type, making them compatible across Odoo versions. --- partner_address_street3/models/res_partner.py | 3 ++- partner_address_street3/tests/test_street_3.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/partner_address_street3/models/res_partner.py b/partner_address_street3/models/res_partner.py index cdb7895fbda..5fc887f53f1 100644 --- a/partner_address_street3/models/res_partner.py +++ b/partner_address_street3/models/res_partner.py @@ -20,8 +20,9 @@ def _address_fields(self): @api.onchange("parent_id") def _onchange_parent_id_street3(self): - result = super().onchange_parent_id() or {} + result = super().onchange_parent_id() if self.parent_id: + result = result or {} result.setdefault("value", {})["street3"] = self.parent_id.street3 return result diff --git a/partner_address_street3/tests/test_street_3.py b/partner_address_street3/tests/test_street_3.py index 55b022776bc..4d869eb3a00 100644 --- a/partner_address_street3/tests/test_street_3.py +++ b/partner_address_street3/tests/test_street_3.py @@ -89,14 +89,14 @@ def test_onchange_parent_id_copies_street3(self): def test_onchange_parent_id_no_parent(self): partner = self.env["res.partner"].new({"name": "Orphan", "type": "contact"}) result = partner._onchange_parent_id_street3() - self.assertIsNone(result) + self.assertNotIn("street3", (result or {}).get("value", {})) def test_onchange_parent_id_preserves_empty_parent(self): partner = self.env["res.partner"].new( {"name": "Child", "type": "contact", "parent_id": False} ) result = partner._onchange_parent_id_street3() - self.assertIsNone(result) + self.assertNotIn("street3", (result or {}).get("value", {})) def test_onchange_parent_id_extends_base_result(self): parent = self.env["res.partner"].create( From f754852096f7c6e5ce6315be08d6443456317eea Mon Sep 17 00:00:00 2001 From: Fernando Date: Wed, 3 Jun 2026 19:07:33 -0400 Subject: [PATCH 5/7] [FIX] partner_category_description: restore module removed in error The street3 fix PR (#2352) accidentally removed this module via a cherry-pick mis-merge. Restore it to its previous 19.0 state so the PR diff is scoped to partner_address_street3 only. Reported-by: @NL66278 --- partner_category_description/README.rst | 111 +++++ partner_category_description/__init__.py | 1 + partner_category_description/__manifest__.py | 23 + partner_category_description/i18n/es.po | 28 ++ partner_category_description/i18n/it.po | 27 ++ .../i18n/partner_category_description.pot | 34 ++ .../models/__init__.py | 1 + .../models/res_partner_category.py | 10 + partner_category_description/pyproject.toml | 3 + .../readme/CONTRIBUTORS.md | 5 + .../readme/DESCRIPTION.md | 1 + partner_category_description/readme/USAGE.md | 4 + .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 452 ++++++++++++++++++ .../tests/__init__.py | 1 + .../test_partner_category_description.py | 21 + .../views/res_partner_category_views.xml | 36 ++ 17 files changed, 758 insertions(+) create mode 100644 partner_category_description/README.rst create mode 100644 partner_category_description/__init__.py create mode 100644 partner_category_description/__manifest__.py create mode 100644 partner_category_description/i18n/es.po create mode 100644 partner_category_description/i18n/it.po create mode 100644 partner_category_description/i18n/partner_category_description.pot create mode 100644 partner_category_description/models/__init__.py create mode 100644 partner_category_description/models/res_partner_category.py create mode 100644 partner_category_description/pyproject.toml create mode 100644 partner_category_description/readme/CONTRIBUTORS.md create mode 100644 partner_category_description/readme/DESCRIPTION.md create mode 100644 partner_category_description/readme/USAGE.md create mode 100644 partner_category_description/static/description/icon.png create mode 100644 partner_category_description/static/description/index.html create mode 100644 partner_category_description/tests/__init__.py create mode 100644 partner_category_description/tests/test_partner_category_description.py create mode 100644 partner_category_description/views/res_partner_category_views.xml diff --git a/partner_category_description/README.rst b/partner_category_description/README.rst new file mode 100644 index 00000000000..c5d257bdc3f --- /dev/null +++ b/partner_category_description/README.rst @@ -0,0 +1,111 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +============================ +Partner Category Description +============================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:134864c8e3b41388b5d4e643fd2497e0b539f6b943a766c64a4ef83cf21aebbd + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |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%2Fpartner--contact-lightgray.png?logo=github + :target: https://github.com/OCA/partner-contact/tree/19.0/partner_category_description + :alt: OCA/partner-contact +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/partner-contact-19-0/partner-contact-19-0-partner_category_description + :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/partner-contact&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds a description field to contact tags. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +1. Create a Tag: Navigate to Contacts > Configuration > Contact Tags and + click on "Create" to add a new tag. + +2. Add a Description: Provide a detailed explanation of the tag's + purpose and criteria in the newly added "Description" field. + +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 +------- + +* Moduon + +Contributors +------------ + +- Eduardo L??pez (`Moduon `__) + +- `Heliconia Solutions Pvt. Ltd. `__ + + - Bhavesh Heliconia + +- Hudson Amadeus Leonardy (https://solusiaglis.co.id) + +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. + +.. |maintainer-edlopen| image:: https://github.com/edlopen.png?size=40px + :target: https://github.com/edlopen + :alt: edlopen +.. |maintainer-rafaelbn| image:: https://github.com/rafaelbn.png?size=40px + :target: https://github.com/rafaelbn + :alt: rafaelbn + +Current `maintainers `__: + +|maintainer-edlopen| |maintainer-rafaelbn| + +This module is part of the `OCA/partner-contact `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/partner_category_description/__init__.py b/partner_category_description/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/partner_category_description/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/partner_category_description/__manifest__.py b/partner_category_description/__manifest__.py new file mode 100644 index 00000000000..1a5dd628ae4 --- /dev/null +++ b/partner_category_description/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2024 Moduon Team S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/LGPL-3.0) + +{ + "name": "Partner Category Description", + "summary": """Adds a description field to contact categories to improve + organization and managment of customer relationships.""", + "version": "19.0.1.0.1", + "development_status": "Alpha", + "category": "Marketing", + "website": "https://github.com/OCA/partner-contact", + "author": "Moduon, Odoo Community Association (OCA)", + "maintainers": ["edlopen", "rafaelbn"], + "license": "LGPL-3", + "application": False, + "installable": True, + "depends": [ + "contacts", + ], + "data": [ + "views/res_partner_category_views.xml", + ], +} diff --git a/partner_category_description/i18n/es.po b/partner_category_description/i18n/es.po new file mode 100644 index 00000000000..b87f70db70b --- /dev/null +++ b/partner_category_description/i18n/es.po @@ -0,0 +1,28 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_category_description +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-07-22 14:17+0000\n" +"PO-Revision-Date: 2024-07-22 16:18+0200\n" +"Last-Translator: Eduardo L??pez \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.4.4\n" + +#. module: partner_category_description +#: model:ir.model.fields,field_description:partner_category_description.field_res_partner_category__description +msgid "Description" +msgstr "Descripci??n" + +#. module: partner_category_description +#: model:ir.model,name:partner_category_description.model_res_partner_category +msgid "Partner Tags" +msgstr "Etiquetas del contacto" diff --git a/partner_category_description/i18n/it.po b/partner_category_description/i18n/it.po new file mode 100644 index 00000000000..f5bde11f0ce --- /dev/null +++ b/partner_category_description/i18n/it.po @@ -0,0 +1,27 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_category_description +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-07-30 11:58+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\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.6.2\n" + +#. module: partner_category_description +#: model:ir.model.fields,field_description:partner_category_description.field_res_partner_category__description +msgid "Description" +msgstr "Descrizione" + +#. module: partner_category_description +#: model:ir.model,name:partner_category_description.model_res_partner_category +msgid "Partner Tags" +msgstr "Etichette partner" diff --git a/partner_category_description/i18n/partner_category_description.pot b/partner_category_description/i18n/partner_category_description.pot new file mode 100644 index 00000000000..1dd921aec4c --- /dev/null +++ b/partner_category_description/i18n/partner_category_description.pot @@ -0,0 +1,34 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * partner_category_description +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 19.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: partner_category_description +#: model:ir.model.fields,field_description:partner_category_description.field_res_partner_category__description +msgid "Description" +msgstr "" + +#. module: partner_category_description +#: model:ir.model.fields,field_description:partner_category_description.field_res_partner_category__display_name +msgid "Display Name" +msgstr "" + +#. module: partner_category_description +#: model:ir.model.fields,field_description:partner_category_description.field_res_partner_category__id +msgid "ID" +msgstr "" + +#. module: partner_category_description +#: model:ir.model,name:partner_category_description.model_res_partner_category +msgid "Partner Tags" +msgstr "" diff --git a/partner_category_description/models/__init__.py b/partner_category_description/models/__init__.py new file mode 100644 index 00000000000..da908a80fd6 --- /dev/null +++ b/partner_category_description/models/__init__.py @@ -0,0 +1 @@ +from . import res_partner_category diff --git a/partner_category_description/models/res_partner_category.py b/partner_category_description/models/res_partner_category.py new file mode 100644 index 00000000000..13d8773b060 --- /dev/null +++ b/partner_category_description/models/res_partner_category.py @@ -0,0 +1,10 @@ +# Copyright 2024 Moduon Team S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/LGPL-3.0) + +from odoo import fields, models + + +class ResPartnerCategory(models.Model): + _inherit = "res.partner.category" + + description = fields.Char(translate=True) diff --git a/partner_category_description/pyproject.toml b/partner_category_description/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/partner_category_description/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/partner_category_description/readme/CONTRIBUTORS.md b/partner_category_description/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..092a31ea327 --- /dev/null +++ b/partner_category_description/readme/CONTRIBUTORS.md @@ -0,0 +1,5 @@ +- Eduardo L??pez ([Moduon](https://www.moduon.team/)) +- [Heliconia Solutions Pvt. Ltd.](https://www.heliconia.io) + - Bhavesh Heliconia + +- Hudson Amadeus Leonardy (https://solusiaglis.co.id) diff --git a/partner_category_description/readme/DESCRIPTION.md b/partner_category_description/readme/DESCRIPTION.md new file mode 100644 index 00000000000..a2180398fd4 --- /dev/null +++ b/partner_category_description/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module adds a description field to contact tags. diff --git a/partner_category_description/readme/USAGE.md b/partner_category_description/readme/USAGE.md new file mode 100644 index 00000000000..88e7b0ce503 --- /dev/null +++ b/partner_category_description/readme/USAGE.md @@ -0,0 +1,4 @@ +1. Create a Tag: Navigate to Contacts > Configuration > Contact Tags and click on "Create" to add a new tag. + +2. Add a Description: Provide a detailed explanation of the tag's purpose and +criteria in the newly added "Description" field. diff --git a/partner_category_description/static/description/icon.png b/partner_category_description/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 zcmW++2RxMjAAjx~&dlBk9S+%}OXg)AGE&Cb*&}d0jUxM@u(PQx^-s)697TX`ehR4?GS^qbkof1cslKgkU)h65qZ9Oc=ml_0temigYLJfnz{IDzUf>bGs4N!v3=Z3jMq&A#7%rM5eQ#dc?k~! zVpnB`o+K7|Al`Q_U;eD$B zfJtP*jH`siUq~{KE)`jP2|#TUEFGRryE2`i0**z#*^6~AI|YzIWy$Cu#CSLW3q=GA z6`?GZymC;dCPk~rBS%eCb`5OLr;RUZ;D`}um=H)BfVIq%7VhiMr)_#G0N#zrNH|__ zc+blN2UAB0=617@>_u;MPHN;P;N#YoE=)R#i$k_`UAA>WWCcEVMh~L_ zj--gtp&|K1#58Yz*AHCTMziU1Jzt_jG0I@qAOHsk$2}yTmVkBp_eHuY$A9)>P6o~I z%aQ?!(GqeQ-Y+b0I(m9pwgi(IIZZzsbMv+9w{PFtd_<_(LA~0H(xz{=FhLB@(1&qHA5EJw1>>=%q2f&^X>IQ{!GJ4e9U z&KlB)z(84HmNgm2hg2C0>WM{E(DdPr+EeU_N@57;PC2&DmGFW_9kP&%?X4}+xWi)( z;)z%wI5>D4a*5XwD)P--sPkoY(a~WBw;E~AW`Yue4kFa^LM3X`8x|}ZUeMnqr}>kH zG%WWW>3ml$Yez?i%)2pbKPI7?5o?hydokgQyZsNEr{a|mLdt;X2TX(#B1j35xPnPW z*bMSSOauW>o;*=kO8ojw91VX!qoOQb)zHJ!odWB}d+*K?#sY_jqPdg{Sm2HdYzdEx zOGVPhVRTGPtv0o}RfVP;Nd(|CB)I;*t&QO8h zFfekr30S!-LHmV_Su-W+rEwYXJ^;6&3|L$mMC8*bQptyOo9;>Qb9Q9`ySe3%V$A*9 zeKEe+b0{#KWGp$F+tga)0RtI)nhMa-K@JS}2krK~n8vJ=Ngm?R!9G<~RyuU0d?nz# z-5EK$o(!F?hmX*2Yt6+coY`6jGbb7tF#6nHA zuKk=GGJ;ZwON1iAfG$E#Y7MnZVmrY|j0eVI(DN_MNFJmyZ|;w4tf@=CCDZ#5N_0K= z$;R~bbk?}TpfDjfB&aiQ$VA}s?P}xPERJG{kxk5~R`iRS(SK5d+Xs9swCozZISbnS zk!)I0>t=A<-^z(cmSFz3=jZ23u13X><0b)P)^1T_))Kr`e!-pb#q&J*Q`p+B6la%C zuVl&0duN<;uOsB3%T9Fp8t{ED108<+W(nOZd?gDnfNBC3>M8WE61$So|P zVvqH0SNtDTcsUdzaMDpT=Ty0pDHHNL@Z0w$Y`XO z2M-_r1S+GaH%pz#Uy0*w$Vdl=X=rQXEzO}d6J^R6zjM1u&c9vYLvLp?W7w(?np9x1 zE_0JSAJCPB%i7p*Wvg)pn5T`8k3-uR?*NT|J`eS#_#54p>!p(mLDvmc-3o0mX*mp_ zN*AeS<>#^-{S%W<*mz^!X$w_2dHWpcJ6^j64qFBft-o}o_Vx80o0>}Du;>kLts;$8 zC`7q$QI(dKYG`Wa8#wl@V4jVWBRGQ@1dr-hstpQL)Tl+aqVpGpbSfN>5i&QMXfiZ> zaA?T1VGe?rpQ@;+pkrVdd{klI&jVS@I5_iz!=UMpTsa~mBga?1r}aRBm1WS;TT*s0f0lY=JBl66Upy)-k4J}lh=P^8(SXk~0xW=T9v*B|gzIhN z>qsO7dFd~mgxAy4V?&)=5ieYq?zi?ZEoj)&2o)RLy=@hbCRcfT5jigwtQGE{L*8<@Yd{zg;CsL5mvzfDY}P-wos_6PfprFVaeqNE%h zKZhLtcQld;ZD+>=nqN~>GvROfueSzJD&BE*}XfU|H&(FssBqY=hPCt`d zH?@s2>I(|;fcW&YM6#V#!kUIP8$Nkdh0A(bEVj``-AAyYgwY~jB zT|I7Bf@%;7aL7Wf4dZ%VqF$eiaC38OV6oy3Z#TER2G+fOCd9Iaoy6aLYbPTN{XRPz z;U!V|vBf%H!}52L2gH_+j;`bTcQRXB+y9onc^wLm5wi3-Be}U>k_u>2Eg$=k!(l@I zcCg+flakT2Nej3i0yn+g+}%NYb?ta;R?(g5SnwsQ49U8Wng8d|{B+lyRcEDvR3+`O{zfmrmvFrL6acVP%yG98X zo&+VBg@px@i)%o?dG(`T;n*$S5*rnyiR#=wW}}GsAcfyQpE|>a{=$Hjg=-*_K;UtD z#z-)AXwSRY?OPefw^iI+ z)AXz#PfEjlwTes|_{sB?4(O@fg0AJ^g8gP}ex9Ucf*@_^J(s_5jJV}c)s$`Myn|Kd z$6>}#q^n{4vN@+Os$m7KV+`}c%4)4pv@06af4-x5#wj!KKb%caK{A&Y#Rfs z-po?Dcb1({W=6FKIUirH&(yg=*6aLCekcKwyfK^JN5{wcA3nhO(o}SK#!CINhI`-I z1)6&n7O&ZmyFMuNwvEic#IiOAwNkR=u5it{B9n2sAJV5pNhar=j5`*N!Na;c7g!l$ z3aYBqUkqqTJ=Re-;)s!EOeij=7SQZ3Hq}ZRds%IM*PtM$wV z@;rlc*NRK7i3y5BETSKuumEN`Xu_8GP1Ri=OKQ$@I^ko8>H6)4rjiG5{VBM>B|%`&&s^)jS|-_95&yc=GqjNo{zFkw%%HHhS~e=s zD#sfS+-?*t|J!+ozP6KvtOl!R)@@-z24}`9{QaVLD^9VCSR2b`b!KC#o;Ki<+wXB6 zx3&O0LOWcg4&rv4QG0)4yb}7BFSEg~=IR5#ZRj8kg}dS7_V&^%#Do==#`u zpy6{ox?jWuR(;pg+f@mT>#HGWHAJRRDDDv~@(IDw&R>9643kK#HN`!1vBJHnC+RM&yIh8{gG2q zA%e*U3|N0XSRa~oX-3EAneep)@{h2vvd3Xvy$7og(sayr@95+e6~Xvi1tUqnIxoIH zVWo*OwYElb#uyW{Imam6f2rGbjR!Y3`#gPqkv57dB6K^wRGxc9B(t|aYDGS=m$&S!NmCtrMMaUg(c zc2qC=2Z`EEFMW-me5B)24AqF*bV5Dr-M5ig(l-WPS%CgaPzs6p_gnCIvTJ=Y<6!gT zVt@AfYCzjjsMEGi=rDQHo0yc;HqoRNnNFeWZgcm?f;cp(6CNylj36DoL(?TS7eU#+ z7&mfr#y))+CJOXQKUMZ7QIdS9@#-}7y2K1{8)cCt0~-X0O!O?Qx#E4Og+;A2SjalQ zs7r?qn0H044=sDN$SRG$arw~n=+T_DNdSrarmu)V6@|?1-ZB#hRn`uilTGPJ@fqEy zGt(f0B+^JDP&f=r{#Y_wi#AVDf-y!RIXU^0jXsFpf>=Ji*TeqSY!H~AMbJdCGLhC) zn7Rx+sXw6uYj;WRYrLd^5IZq@6JI1C^YkgnedZEYy<&4(z%Q$5yv#Boo{AH8n$a zhb4Y3PWdr269&?V%uI$xMcUrMzl=;w<_nm*qr=c3Rl@i5wWB;e-`t7D&c-mcQl7x! zZWB`UGcw=Y2=}~wzrfLx=uet<;m3~=8I~ZRuzvMQUQdr+yTV|ATf1Uuomr__nDf=X zZ3WYJtHp_ri(}SQAPjv+Y+0=fH4krOP@S&=zZ-t1jW1o@}z;xk8 z(Nz1co&El^HK^NrhVHa-_;&88vTU>_J33=%{if;BEY*J#1n59=07jrGQ#IP>@u#3A z;!q+E1Rj3ZJ+!4bq9F8PXJ@yMgZL;>&gYA0%_Kbi8?S=XGM~dnQZQ!yBSgcZhY96H zrWnU;k)qy`rX&&xlDyA%(a1Hhi5CWkmg(`Gb%m(HKi-7Z!LKGRP_B8@`7&hdDy5n= z`OIxqxiVfX@OX1p(mQu>0Ai*v_cTMiw4qRt3~NBvr9oBy0)r>w3p~V0SCm=An6@3n)>@z!|o-$HvDK z|3D2ZMJkLE5loMKl6R^ez@Zz%S$&mbeoqH5`Bb){Ei21q&VP)hWS2tjShfFtGE+$z zzCR$P#uktu+#!w)cX!lWN1XU%K-r=s{|j?)Akf@q#3b#{6cZCuJ~gCxuMXRmI$nGtnH+-h z+GEi!*X=AP<|fG`1>MBdTb?28JYc=fGvAi2I<$B(rs$;eoJCyR6_bc~p!XR@O-+sD z=eH`-ye})I5ic1eL~TDmtfJ|8`0VJ*Yr=hNCd)G1p2MMz4C3^Mj?7;!w|Ly%JqmuW zlIEW^Ft%z?*|fpXda>Jr^1noFZEwFgVV%|*XhH@acv8rdGxeEX{M$(vG{Zw+x(ei@ zmfXb22}8-?Fi`vo-YVrTH*C?a8%M=Hv9MqVH7H^J$KsD?>!SFZ;ZsvnHr_gn=7acz z#W?0eCdVhVMWN12VV^$>WlQ?f;P^{(&pYTops|btm6aj>_Uz+hqpGwB)vWp0Cf5y< zft8-je~nn?W11plq}N)4A{l8I7$!ks_x$PXW-2XaRFswX_BnF{R#6YIwMhAgd5F9X zGmwdadS6(a^fjHtXg8=l?Rc0Sm%hk6E9!5cLVloEy4eh(=FwgP`)~I^5~pBEWo+F6 zSf2ncyMurJN91#cJTy_u8Y}@%!bq1RkGC~-bV@SXRd4F{R-*V`bS+6;W5vZ(&+I<9$;-V|eNfLa5n-6% z2(}&uGRF;p92eS*sE*oR$@pexaqr*meB)VhmIg@h{uzkk$9~qh#cHhw#>O%)b@+(| z^IQgqzuj~Sk(J;swEM-3TrJAPCq9k^^^`q{IItKBRXYe}e0Tdr=Huf7da3$l4PdpwWDop%^}n;dD#K4s#DYA8SHZ z&1!riV4W4R7R#C))JH1~axJ)RYnM$$lIR%6fIVA@zV{XVyx}C+a-Dt8Y9M)^KU0+H zR4IUb2CJ{Hg>CuaXtD50jB(_Tcx=Z$^WYu2u5kubqmwp%drJ6 z?Fo40g!Qd<-l=TQxqHEOuPX0;^z7iX?Ke^a%XT<13TA^5`4Xcw6D@Ur&VT&CUe0d} z1GjOVF1^L@>O)l@?bD~$wzgf(nxX1OGD8fEV?TdJcZc2KoUe|oP1#=$$7ee|xbY)A zDZq+cuTpc(fFdj^=!;{k03C69lMQ(|>uhRfRu%+!k&YOi-3|1QKB z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/partner_category_description/static/description/index.html b/partner_category_description/static/description/index.html new file mode 100644 index 00000000000..450532f0f5b --- /dev/null +++ b/partner_category_description/static/description/index.html @@ -0,0 +1,452 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Partner Category Description

+ +

Alpha License: LGPL-3 OCA/partner-contact Translate me on Weblate Try me on Runboat

+

This module adds a description field to contact tags.

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

Usage

+
    +
  1. Create a Tag: Navigate to Contacts > Configuration > Contact Tags and +click on “Create” to add a new tag.
  2. +
  3. Add a Description: Provide a detailed explanation of the tag’s +purpose and criteria in the newly added “Description” field.
  4. +
+
+
+

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

+
    +
  • Moduon
  • +
+
+
+

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.

+

Current maintainers:

+

edlopen rafaelbn

+

This module is part of the OCA/partner-contact project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/partner_category_description/tests/__init__.py b/partner_category_description/tests/__init__.py new file mode 100644 index 00000000000..30a2e1ecde4 --- /dev/null +++ b/partner_category_description/tests/__init__.py @@ -0,0 +1 @@ +from . import test_partner_category_description diff --git a/partner_category_description/tests/test_partner_category_description.py b/partner_category_description/tests/test_partner_category_description.py new file mode 100644 index 00000000000..6a78dd63ab8 --- /dev/null +++ b/partner_category_description/tests/test_partner_category_description.py @@ -0,0 +1,21 @@ +# Copyright 2024 Moduon Team S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/LGPL-3.0) + +from odoo.addons.base.tests.common import BaseCommon + + +class TestResPartnerCategory(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner_category = cls.env["res.partner.category"].create( + {"name": "Test Category", "description": "This is a test description"} + ) + + def test_category_creation(self): + """Test that a partner category is created correctly.""" + self.assertTrue(self.partner_category, "Partner category should be created.") + self.assertEqual(self.partner_category.name, "Test Category") + self.assertEqual( + self.partner_category.description, "This is a test description" + ) diff --git a/partner_category_description/views/res_partner_category_views.xml b/partner_category_description/views/res_partner_category_views.xml new file mode 100644 index 00000000000..9193765e86c --- /dev/null +++ b/partner_category_description/views/res_partner_category_views.xml @@ -0,0 +1,36 @@ + + + + + res.partner.category + + + + + + + + + + res.partner.category + + + + + + + + + + + + res.partner.category + + + + + + + + From 16282c01bb013d66e4a2e9c8df5162e5e023f014 Mon Sep 17 00:00:00 2001 From: Fernando Date: Wed, 3 Jun 2026 19:07:46 -0400 Subject: [PATCH 6/7] [FIX] partner_address_street3: use default_get to copy from default_parent_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous onchange("parent_id") override never ran in the inline "Add in Contacts & Addresses" form, because parent_id is delivered via default_parent_id in the context, not via an interactive onchange. That is why the original issue (#2298) — street3 not prefilled in the inline create dialog — was not actually fixed. Replace the onchange override with a default_get that reads default_parent_id from the context and copies the address fields, guarded by 'if not values.get(field)' so explicit defaults are not clobbered. This matches the suggestion from BhaveshHeliconia and addresses the 'onchange_parent_id called twice' concern raised by NL66278 (the override was redundant with the base behaviour anyway). Tests rewritten around default_get to cover the inline create context and the no-clobber guarantee. --- partner_address_street3/models/res_partner.py | 18 +++-- .../tests/test_street_3.py | 69 +++++++++---------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/partner_address_street3/models/res_partner.py b/partner_address_street3/models/res_partner.py index 5fc887f53f1..078d4e55b9f 100644 --- a/partner_address_street3/models/res_partner.py +++ b/partner_address_street3/models/res_partner.py @@ -18,13 +18,17 @@ def _address_fields(self): res.append("street3") return res - @api.onchange("parent_id") - def _onchange_parent_id_street3(self): - result = super().onchange_parent_id() - if self.parent_id: - result = result or {} - result.setdefault("value", {})["street3"] = self.parent_id.street3 - return result + @api.model + def default_get(self, default_fields): + values = super().default_get(default_fields) + parent_id = self.env.context.get("default_parent_id") or values.get("parent_id") + if parent_id: + parent = self.browse(parent_id) + for field in self._address_fields(): + if field in default_fields and not values.get(field): + val = parent[field] + values[field] = val.id if isinstance(val, models.BaseModel) else val + return values def _display_address(self, without_company=False): """Remove empty lines which can happen when street3 field is empty.""" diff --git a/partner_address_street3/tests/test_street_3.py b/partner_address_street3/tests/test_street_3.py index 4d869eb3a00..479a4118e5c 100644 --- a/partner_address_street3/tests/test_street_3.py +++ b/partner_address_street3/tests/test_street_3.py @@ -65,7 +65,14 @@ def test_uninstall(self): us_country = self.env.ref("base.us") self.assertTrue("%(street3)s" not in us_country.address_format) - def test_onchange_parent_id_copies_street3(self): + def test_default_get_copies_street3_from_default_parent_id(self): + """Replicate the "Add in Contacts & Addresses" inline form context. + + Odoo passes ``default_parent_id`` in the context when the inline + ``child_ids`` form is opened from a company contact, so ``default_get`` + must pre-fill the address fields (including ``street3``) from that + parent. + """ parent = self.env["res.partner"].create( { "name": "Parent Company", @@ -76,42 +83,34 @@ def test_onchange_parent_id_copies_street3(self): "country_id": self.env.ref("base.us").id, } ) - partner = self.env["res.partner"].new( - {"name": "Child", "type": "contact", "parent_id": parent.id} - ) - result = partner._onchange_parent_id_street3() - self.assertIsNotNone(result) - self.assertIn("value", result) - self.assertEqual(result["value"]["street3"], "Suite 100") - self.assertEqual(result["value"]["street2"], "Floor 2") - self.assertEqual(result["value"]["street"], "123 Main St") - - def test_onchange_parent_id_no_parent(self): - partner = self.env["res.partner"].new({"name": "Orphan", "type": "contact"}) - result = partner._onchange_parent_id_street3() - self.assertNotIn("street3", (result or {}).get("value", {})) - - def test_onchange_parent_id_preserves_empty_parent(self): - partner = self.env["res.partner"].new( - {"name": "Child", "type": "contact", "parent_id": False} + values = ( + self.env["res.partner"] + .with_context(default_parent_id=parent.id, default_type="contact") + .default_get(["street", "street2", "street3", "city"]) ) - result = partner._onchange_parent_id_street3() - self.assertNotIn("street3", (result or {}).get("value", {})) + self.assertEqual(values.get("street3"), "Suite 100") + self.assertEqual(values.get("street2"), "Floor 2") + self.assertEqual(values.get("street"), "123 Main St") + self.assertEqual(values.get("city"), "Springfield") - def test_onchange_parent_id_extends_base_result(self): + def test_default_get_does_not_overwrite_explicit_value(self): + """An explicit default must win over the parent's value.""" parent = self.env["res.partner"].create( - { - "name": "Parent Company", - "street": "123 Main St", - "city": "Springfield", - } + {"name": "Parent", "street3": "From parent"} ) - partner = self.env["res.partner"].new( - {"name": "Child", "type": "contact", "parent_id": parent.id} + values = ( + self.env["res.partner"] + .with_context( + default_parent_id=parent.id, + default_type="contact", + default_street3="Explicit", + ) + .default_get(["street3"]) + ) + self.assertEqual(values.get("street3"), "Explicit") + + def test_default_get_no_parent(self): + values = self.env["res.partner"].with_context(default_type="contact").default_get( + ["street3"] ) - result = partner._onchange_parent_id_street3() - self.assertIsNotNone(result) - self.assertIn("value", result) - self.assertIn("street", result["value"]) - self.assertIn("street3", result["value"]) - self.assertIn("city", result["value"]) + self.assertNotIn("street3", values) From 88854b757a11ad17a4a977e904113cd73999760c Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 3 Jun 2026 19:17:38 -0400 Subject: [PATCH 7/7] [FIX] partner_address_street3: fix ruff E501 line length in test_default_get_no_parent --- partner_address_street3/tests/test_street_3.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/partner_address_street3/tests/test_street_3.py b/partner_address_street3/tests/test_street_3.py index 479a4118e5c..07854d63243 100644 --- a/partner_address_street3/tests/test_street_3.py +++ b/partner_address_street3/tests/test_street_3.py @@ -110,7 +110,9 @@ def test_default_get_does_not_overwrite_explicit_value(self): self.assertEqual(values.get("street3"), "Explicit") def test_default_get_no_parent(self): - values = self.env["res.partner"].with_context(default_type="contact").default_get( - ["street3"] + values = ( + self.env["res.partner"] + .with_context(default_type="contact") + .default_get(["street3"]) ) self.assertNotIn("street3", values)