From 3135a41ed56c6076dabc3a964b77508226eb1ee8 Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Mon, 19 Jun 2023 11:07:39 -0400 Subject: [PATCH 1/3] bemade_partner_root_ancestor: initial commit --- __init__.py | 1 + __manifest__.py | 35 +++++++++++++++++++++++++++++++++++ models/__init__.py | 1 + models/account_move.py | 0 models/res_partner.py | 16 ++++++++++++++++ models/sale_order.py | 6 ++++++ 6 files changed, 59 insertions(+) create mode 100644 __init__.py create mode 100644 __manifest__.py create mode 100644 models/__init__.py create mode 100644 models/account_move.py create mode 100644 models/res_partner.py create mode 100644 models/sale_order.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/__manifest__.py b/__manifest__.py new file mode 100644 index 0000000..52d08de --- /dev/null +++ b/__manifest__.py @@ -0,0 +1,35 @@ +# +# Bemade Inc. +# +# Copyright (C) June 2023 Bemade Inc. (). +# Author: mdurepos (Contact : it@bemade.org) +# +# This program is under the terms of the Odoo Proprietary License v1.0 (OPL-1) +# It is forbidden to publish, distribute, sublicense, or sell copies of the Software +# or modified copies of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +{ + 'name': 'bemade_multiple_billing_contacts', + 'version': '15.0.1.0.0', + 'summary': 'Send invoices to multiple contacts by default.', + 'description': """By default, newly created invoices add all invoice addresses for the given partner as + followers on the invoice. If billing contacts are set manually on the sales order, those billing + contacts are added as followers on the invoice instead.""", + 'category': 'Invoicing Management', + 'author': 'Bemade Inc.', + 'website': 'https://www.bemade.org', + 'license': 'OPL-1', + 'depends': ['sale', 'account'], + 'data': [], + 'demo': [], + 'installable': True, + 'auto_install': False, +} diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/models/__init__.py @@ -0,0 +1 @@ + diff --git a/models/account_move.py b/models/account_move.py new file mode 100644 index 0000000..e69de29 diff --git a/models/res_partner.py b/models/res_partner.py new file mode 100644 index 0000000..fa220a5 --- /dev/null +++ b/models/res_partner.py @@ -0,0 +1,16 @@ +from odoo import models, fields, api, _, Command + + +class Partner(models.Model): + _inherit = 'res.partner' + + def _billing_contacts_domain(self): + self.ensure_one() + return [('is_company', '=', False), ('root_ancestor', '=', self.root_ancestor)] + billing_contacts = fields.Many2many(string='Default Billing Contacts', + comodel_name='res.partner', + relation='res_partner_billing_contact_rel', + column1='billing_contact_id', + column2='billed_partner_id', + domain=_billing_contacts_domain, + tracking=True) \ No newline at end of file diff --git a/models/sale_order.py b/models/sale_order.py new file mode 100644 index 0000000..ed1dad9 --- /dev/null +++ b/models/sale_order.py @@ -0,0 +1,6 @@ +from odoo import models, fields, api, _, Command + + +class SaleOrder(models.Model): + _inherit = 'sale.order' + From 168dc570630e4f5b71756eea2d7a726ed05e991e Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Mon, 19 Jun 2023 11:51:23 -0400 Subject: [PATCH 2/3] bemade_partner_root_ancestor: First working version with unit test. --- .gitignore | 74 +++++++++++++++++++++++++++++++++++++ __manifest__.py | 11 ++---- models/__init__.py | 2 +- models/account_move.py | 0 models/res_partner.py | 18 ++++----- models/sale_order.py | 6 --- tests/__init__.py | 1 + tests/test_root_ancestor.py | 55 +++++++++++++++++++++++++++ 8 files changed, 143 insertions(+), 24 deletions(-) create mode 100644 .gitignore delete mode 100644 models/account_move.py delete mode 100644 models/sale_order.py create mode 100644 tests/__init__.py create mode 100644 tests/test_root_ancestor.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9c283fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,74 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +/.venv +/.pytest_cache + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +bin/ +build/ +develop-eggs/ +dist/ +eggs/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg +*.eggs + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.mo + +# Pycharm +.idea + +# Eclipse +.settings + +# Visual Studio cache/options directory +.vs/ +.vscode + +# OSX Files +.DS_Store + +# Django stuff: +*.log + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# Rope +.ropeproject + +# Sphinx documentation +docs/_build/ + +# Backup files +*~ +*.swp + +# OCA rules +!static/lib/ diff --git a/__manifest__.py b/__manifest__.py index 52d08de..a92819b 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -17,17 +17,14 @@ # DEALINGS IN THE SOFTWARE. # { - 'name': 'bemade_multiple_billing_contacts', + 'name': 'Partner Root Ancestor', 'version': '15.0.1.0.0', - 'summary': 'Send invoices to multiple contacts by default.', - 'description': """By default, newly created invoices add all invoice addresses for the given partner as - followers on the invoice. If billing contacts are set manually on the sales order, those billing - contacts are added as followers on the invoice instead.""", - 'category': 'Invoicing Management', + 'summary': 'Technical module to add the field root_ancestor to res.partner.', + 'category': 'Generic Modules/Base', 'author': 'Bemade Inc.', 'website': 'https://www.bemade.org', 'license': 'OPL-1', - 'depends': ['sale', 'account'], + 'depends': ['base'], 'data': [], 'demo': [], 'installable': True, diff --git a/models/__init__.py b/models/__init__.py index 8b13789..91fed54 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -1 +1 @@ - +from . import res_partner diff --git a/models/account_move.py b/models/account_move.py deleted file mode 100644 index e69de29..0000000 diff --git a/models/res_partner.py b/models/res_partner.py index fa220a5..9028c93 100644 --- a/models/res_partner.py +++ b/models/res_partner.py @@ -4,13 +4,11 @@ from odoo import models, fields, api, _, Command class Partner(models.Model): _inherit = 'res.partner' - def _billing_contacts_domain(self): - self.ensure_one() - return [('is_company', '=', False), ('root_ancestor', '=', self.root_ancestor)] - billing_contacts = fields.Many2many(string='Default Billing Contacts', - comodel_name='res.partner', - relation='res_partner_billing_contact_rel', - column1='billing_contact_id', - column2='billed_partner_id', - domain=_billing_contacts_domain, - tracking=True) \ No newline at end of file + root_ancestor = fields.Many2one(comodel_name='res.partner', + string='Root Ancestor', + compute='_compute_root_ancestor') + + @api.depends('parent_id') + def _compute_root_ancestor(self): + for rec in self: + rec.root_ancestor = rec.parent_id and rec.parent_id.root_ancestor or rec diff --git a/models/sale_order.py b/models/sale_order.py deleted file mode 100644 index ed1dad9..0000000 --- a/models/sale_order.py +++ /dev/null @@ -1,6 +0,0 @@ -from odoo import models, fields, api, _, Command - - -class SaleOrder(models.Model): - _inherit = 'sale.order' - diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..77fc5d6 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +from . import test_root_ancestor diff --git a/tests/test_root_ancestor.py b/tests/test_root_ancestor.py new file mode 100644 index 0000000..a4e747e --- /dev/null +++ b/tests/test_root_ancestor.py @@ -0,0 +1,55 @@ +from odoo.tests.common import TransactionCase, tagged +from odoo import Command + + +class TestPartnerRootAncestor(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + partner = cls.env['res.partner'] + cls.common_ancestor = partner.create({ + 'name': 'Parnter name', + 'company_type': 'company', + }) + cls.first_child = partner.create({ + 'name': 'Child name', + 'company_type': 'company', + 'parent_id': cls.common_ancestor.id, + }) + cls.second_child = partner.create({ + 'name': 'Child name', + 'company_type': 'company', + 'parent_id': cls.common_ancestor.id, + }) + cls.first_grandchild = partner.create({ + 'name': 'Grandchild name', + 'company_type': 'person', + 'parent_id': cls.first_child.id, + }) + cls.second_grandchild = partner.create({ + 'name': 'Grandchild name', + 'company_type': 'person', + 'parent_id': cls.second_child.id, + }) + cls.unrelated_partner = partner.create({ + 'name': 'Unrelated partner', + }) + cls.relatives = [cls.common_ancestor, cls.first_child, cls.second_child, cls.first_grandchild, + cls.second_grandchild] + + @tagged('-at_install', 'post_install') + def testBaseCase(self): + for r1 in self.relatives: + self.assertFalse(r1.root_ancestor == self.unrelated_partner) + for r2 in self.relatives: + self.assertTrue(r1.root_ancestor == r2.root_ancestor) + + @tagged('-at_install', 'post_install') + def testNewRelative(self): + new_relative = self.env['res.partner'].create({ + 'name': 'Whatever', + 'company_type': 'person', + 'parent_id': self.second_grandchild.id, + }) + for r1 in self.relatives: + self.assertTrue(r1.root_ancestor == new_relative.root_ancestor) \ No newline at end of file From f0da5c361818a29c3f2d12a11f0ad44d1ddb0840 Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Mon, 26 Jun 2023 15:01:17 -0400 Subject: [PATCH 3/3] bemade_partner_root_ancestor: Added store=true, recursive=true to root ancestor field. bemade_partner_root_ancestor: Preparing to migrate bemade_partner_root_ancestor. --- __init__.py => bemade_partner_root_ancestor/__init__.py | 0 .../__manifest__.py | 0 {models => bemade_partner_root_ancestor/models}/__init__.py | 0 .../models}/res_partner.py | 6 ++++-- {tests => bemade_partner_root_ancestor/tests}/__init__.py | 0 .../tests}/test_root_ancestor.py | 0 6 files changed, 4 insertions(+), 2 deletions(-) rename __init__.py => bemade_partner_root_ancestor/__init__.py (100%) rename __manifest__.py => bemade_partner_root_ancestor/__manifest__.py (100%) rename {models => bemade_partner_root_ancestor/models}/__init__.py (100%) rename {models => bemade_partner_root_ancestor/models}/res_partner.py (73%) rename {tests => bemade_partner_root_ancestor/tests}/__init__.py (100%) rename {tests => bemade_partner_root_ancestor/tests}/test_root_ancestor.py (100%) diff --git a/__init__.py b/bemade_partner_root_ancestor/__init__.py similarity index 100% rename from __init__.py rename to bemade_partner_root_ancestor/__init__.py diff --git a/__manifest__.py b/bemade_partner_root_ancestor/__manifest__.py similarity index 100% rename from __manifest__.py rename to bemade_partner_root_ancestor/__manifest__.py diff --git a/models/__init__.py b/bemade_partner_root_ancestor/models/__init__.py similarity index 100% rename from models/__init__.py rename to bemade_partner_root_ancestor/models/__init__.py diff --git a/models/res_partner.py b/bemade_partner_root_ancestor/models/res_partner.py similarity index 73% rename from models/res_partner.py rename to bemade_partner_root_ancestor/models/res_partner.py index 9028c93..0b9181a 100644 --- a/models/res_partner.py +++ b/bemade_partner_root_ancestor/models/res_partner.py @@ -6,9 +6,11 @@ class Partner(models.Model): root_ancestor = fields.Many2one(comodel_name='res.partner', string='Root Ancestor', - compute='_compute_root_ancestor') + compute='_compute_root_ancestor', + store=True, + recursive=True) - @api.depends('parent_id') + @api.depends('parent_id', 'parent_id.root_ancestor') def _compute_root_ancestor(self): for rec in self: rec.root_ancestor = rec.parent_id and rec.parent_id.root_ancestor or rec diff --git a/tests/__init__.py b/bemade_partner_root_ancestor/tests/__init__.py similarity index 100% rename from tests/__init__.py rename to bemade_partner_root_ancestor/tests/__init__.py diff --git a/tests/test_root_ancestor.py b/bemade_partner_root_ancestor/tests/test_root_ancestor.py similarity index 100% rename from tests/test_root_ancestor.py rename to bemade_partner_root_ancestor/tests/test_root_ancestor.py