From 8a387580853d0aef9099200a148b813ce46b59df Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Mon, 19 Jun 2023 10:49:42 -0400 Subject: [PATCH 1/5] bemade_multiple_billing_contacts: Initial Commit --- __init__.py | 1 + __manifest__.py | 35 +++++++++++++++++++++++++++++++++++ models/__init__.py | 1 + 3 files changed, 37 insertions(+) create mode 100644 __init__.py create mode 100644 __manifest__.py create mode 100644 models/__init__.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..0e55682 --- /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': [], + '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 @@ + From 3424f7221cac9db4216e7e9492da3a42c2d15950 Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Mon, 19 Jun 2023 12:00:42 -0400 Subject: [PATCH 2/5] bemade_multiple_billing_contacts: Initial commit. --- __manifest__.py | 2 +- models/account_move.py | 0 models/res_partner.py | 16 ++++++++++++++++ models/sale_order.py | 6 ++++++ 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 models/account_move.py create mode 100644 models/res_partner.py create mode 100644 models/sale_order.py diff --git a/__manifest__.py b/__manifest__.py index 0e55682..52d08de 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -27,7 +27,7 @@ 'author': 'Bemade Inc.', 'website': 'https://www.bemade.org', 'license': 'OPL-1', - 'depends': [], + 'depends': ['sale', 'account'], 'data': [], 'demo': [], 'installable': True, 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 02624877d6bf4cdfd56ca36037fde643a6dd113a Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Mon, 19 Jun 2023 15:58:03 -0400 Subject: [PATCH 3/5] bemade_multiple_billing_contacts: Early development on multiple billing contacts. --- .gitignore | 74 ++++++++++++++++++++++++++++++++++ __manifest__.py | 5 ++- models/__init__.py | 4 +- models/account_move.py | 32 +++++++++++++++ models/res_partner.py | 20 +++++---- models/sale_order.py | 13 ++++++ tests/__init__.py | 1 + tests/test_billing_contacts.py | 40 ++++++++++++++++++ 8 files changed, 179 insertions(+), 10 deletions(-) create mode 100644 .gitignore create mode 100644 tests/__init__.py create mode 100644 tests/test_billing_contacts.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..9d4ee19 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -27,7 +27,10 @@ 'author': 'Bemade Inc.', 'website': 'https://www.bemade.org', 'license': 'OPL-1', - 'depends': ['sale', 'account'], + 'depends': ['sale', + 'account', + 'bemade_partner_root_ancestor', + ], 'data': [], 'demo': [], 'installable': True, diff --git a/models/__init__.py b/models/__init__.py index 8b13789..fdc1257 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -1 +1,3 @@ - +from . import res_partner +from . import sale_order +from . import account_move diff --git a/models/account_move.py b/models/account_move.py index e69de29..e5b191a 100644 --- a/models/account_move.py +++ b/models/account_move.py @@ -0,0 +1,32 @@ +from odoo import models, fields, api + + +class AccountMove(models.Model): + _inherit = 'account.move' + + billing_contacts = fields.Many2many(comodel_name='res.partner', + string="Billing Contacts", + compute='_compute_billing_contacts', + inverse='_inverse_billing_contacts', + store=True) + + @api.depends('line_ids.sale_line_ids.order_id', 'partner_id') + def _compute_billing_contacts(self): + for rec in self: + order_id = rec.line_ids and rec.line_ids.mapped('sale_line_ids').mapped('order_id') + if order_id and len(order_id) == 1 and order_id.billing_contacts: + rec.billing_contacts = order_id.billing_contacts + else: + rec.billing_contacts = rec.partner_id.billing_contacts + + def _inverse_billing_contacts(self): + pass + + def _post(self, soft=True): + # Override the original method to subscribe the partner's billing contacts instead of self.partner_id + initial_subscribers = self.message_partner_ids.ids + final_subscribers = initial_subscribers + self.partner_id.billing_contacts.ids + posted = super()._post() + self.message_unsubscribe(self.message_partner_ids - initial_subscribers) + self.message_subscribe(final_subscribers) + return posted diff --git a/models/res_partner.py b/models/res_partner.py index fa220a5..ae988ff 100644 --- a/models/res_partner.py +++ b/models/res_partner.py @@ -4,13 +4,17 @@ 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 + compute='_compute_billing_contacts', + inverse='_inverse_billing_contacts') + + @api.depends('child_ids.type') + def _compute_billing_contacts(self): + for rec in self: + rec.billing_contacts = rec.child_ids.filtered(lambda r: r.type == 'invoice') + + @api.depends('billing_contacts') + def _inverse_billing_contacts(self): + for partner in self.mapped('billing_contacts'): + partner.type = 'invoice' diff --git a/models/sale_order.py b/models/sale_order.py index ed1dad9..877cc5d 100644 --- a/models/sale_order.py +++ b/models/sale_order.py @@ -4,3 +4,16 @@ from odoo import models, fields, api, _, Command class SaleOrder(models.Model): _inherit = 'sale.order' + billing_contacts = fields.Many2many(comodel_name='res.partner', + string='Billing Contacts', + compute='_compute_billing_contacts', + inverse='_inverse_billing_contacts', + store=True) + + @api.depends('partner_id') + def _compute_billing_contacts(self): + for rec in self: + rec.billing_contacts = rec.partner_id.billing_contacts + + def _inverse_billing_contacts(self): + pass diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..219fd8e --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +from . import test_billing_contacts diff --git a/tests/test_billing_contacts.py b/tests/test_billing_contacts.py new file mode 100644 index 0000000..47f0a9b --- /dev/null +++ b/tests/test_billing_contacts.py @@ -0,0 +1,40 @@ +from odoo.tests import TransactionCase, tagged + + +class TestBillingContacts(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + partner = cls.env['res.partner'].create + cls.parent_co = partner({ + 'name': 'Partner', + 'company_type': 'company', + }) + cls.billing_contact1 = partner({ + 'name': 'Billing Contact 1', + 'company_type': 'person', + 'email': 'billingcontact1@partner.co', + 'parent_id': cls.parent_co.id, + 'type': 'invoice', + }) + cls.billing_contact2 = partner({ + 'name': 'Billing Contact 2', + 'company_type': 'person', + 'email': 'billingcontact2@partner.co', + 'parent_id': cls.parent_co.id, + 'type': 'invoice', + }) + cls.non_billing_contact = partner({ + 'name': 'Non-billing contact', + 'company_type': 'person', + 'email': 'not_billing@partner.co', + 'parent_id': cls.parent_co.id, + 'type': 'contact', + }) + + @tagged('-at_install', 'post_install') + def test_sale_order_defaults(self): + billing_contacts = self.parent_co.billing_contacts + self.assertTrue(self.billing_contact1 in self.parent_co.billing_contacts) + self.assertTrue(self.billing_contact2 in self.parent_co.billing_contacts) + self.assertTrue(self.non_billing_contact not in self.parent_co.billing_contacts) From e374c53e6366ae96e6eb14c6ea6d9eb33fe5d9c0 Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Thu, 22 Jun 2023 15:33:54 -0400 Subject: [PATCH 4/5] bemade_multiple_billing_contacts: Added multiple unit tests and fixed a bug they found in the billing contacts / invoice functionality. --- __manifest__.py | 2 +- models/account_move.py | 4 +- tests/test_billing_contacts.py | 73 ++++++++++++++++++++++++++++++++-- 3 files changed, 73 insertions(+), 6 deletions(-) diff --git a/__manifest__.py b/__manifest__.py index 9d4ee19..5e4c2c7 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -18,7 +18,7 @@ # { 'name': 'bemade_multiple_billing_contacts', - 'version': '15.0.1.0.0', + 'version': '15.0.1.0.1', '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 diff --git a/models/account_move.py b/models/account_move.py index e5b191a..a12ddda 100644 --- a/models/account_move.py +++ b/models/account_move.py @@ -25,8 +25,8 @@ class AccountMove(models.Model): def _post(self, soft=True): # Override the original method to subscribe the partner's billing contacts instead of self.partner_id initial_subscribers = self.message_partner_ids.ids - final_subscribers = initial_subscribers + self.partner_id.billing_contacts.ids + final_subscribers = initial_subscribers + self.billing_contacts.ids posted = super()._post() - self.message_unsubscribe(self.message_partner_ids - initial_subscribers) + self.message_unsubscribe([s.id for s in self.message_partner_ids if s not in initial_subscribers]) self.message_subscribe(final_subscribers) return posted diff --git a/tests/test_billing_contacts.py b/tests/test_billing_contacts.py index 47f0a9b..c99d4d5 100644 --- a/tests/test_billing_contacts.py +++ b/tests/test_billing_contacts.py @@ -1,6 +1,9 @@ from odoo.tests import TransactionCase, tagged +from odoo import Command +import datetime +@tagged('-at_install', 'post_install') class TestBillingContacts(TransactionCase): @classmethod def setUpClass(cls): @@ -31,10 +34,74 @@ class TestBillingContacts(TransactionCase): 'parent_id': cls.parent_co.id, 'type': 'contact', }) + cls.product = cls.env['product.product'].with_company(cls.parent_co.company_id).create({ + 'name': 'Product', + 'categ_id': cls.env['product.category'].create({'name': 'Product Category'}).id, + 'list_price': 100.0, + 'type': 'service', + 'uom_id': cls.env.ref('uom.product_uom_unit').id, + 'uom_po_id': cls.env.ref('uom.product_uom_unit').id, + 'default_code': 'PRODUCT-X', + 'invoice_policy': 'order', + 'expense_policy': 'no', + 'taxes_id': [(6, 0, [])], + 'supplier_taxes_id': [(6, 0, [])], + }) - @tagged('-at_install', 'post_install') - def test_sale_order_defaults(self): - billing_contacts = self.parent_co.billing_contacts + cls.sale_order = cls.env['sale.order'].create({ + 'partner_id': cls.parent_co.id, + 'client_order_ref': 'abc123', + }) + + cls.env['sale.order.line'].create({ + 'product_id': cls.product.id, + 'name': cls.product.name, + 'product_uom_qty': 2, + 'product_uom': cls.product.uom_id.id, + 'price_unit': cls.product.list_price, + 'order_id': cls.sale_order.id, + 'tax_id': False, + 'qty_delivered_manual': 2, + }) + + def test_billing_contacts_structure(self): self.assertTrue(self.billing_contact1 in self.parent_co.billing_contacts) self.assertTrue(self.billing_contact2 in self.parent_co.billing_contacts) self.assertTrue(self.non_billing_contact not in self.parent_co.billing_contacts) + + def test_sale_order_default_billing_contacts(self): + self.assertTrue(self.sale_order.billing_contacts == self.parent_co.billing_contacts) + + def test_sale_order_change_contacts(self): + # Test that changing the billing contacts on an SO doesn't change them on the partner + # Validate that changing them manually on the SO transfers to the invoice + self.sale_order.write({'billing_contacts': [Command.link(self.non_billing_contact.id)]}) + self.assertTrue(all([c in self.sale_order.billing_contacts for c in self.parent_co.billing_contacts])) + self.assertTrue(self.non_billing_contact not in self.parent_co.billing_contacts) + self.assertTrue(self.non_billing_contact in self.sale_order.billing_contacts) + + def test_sale_order_to_invoice_contacts(self): + # Test that the invoices created from sales orders take the billing contacts configured on the SO + + self.sale_order.write({'billing_contacts': [Command.link(self.non_billing_contact.id)]}) + self.sale_order.action_confirm() + + wiz = self.env['sale.advance.payment.inv'].create({}) + invoice = wiz._create_invoice(self.sale_order,self.sale_order.order_line[0],self.sale_order.order_line.price_total) + self.assertTrue(invoice) + self.assertTrue(invoice.billing_contacts == self.sale_order.billing_contacts) + + def test_direct_invoice_contacts(self): + invoice = self.env['account.move'].create({ + 'move_type': 'out_invoice', + 'partner_id': self.parent_co, + }) + self.assertTrue(self.parent_co.billing_contacts == invoice.billing_contacts) + + def test_invoice_followers_on_validate(self): + self.sale_order.action_confirm() + wiz = self.env['sale.advance.payment.inv'].create({}) + invoice = wiz._create_invoice(self.sale_order,self.sale_order.order_line[0],self.sale_order.order_line.price_total) + invoice.write({'date': datetime.date.today()}) + invoice.action_post() + self.assertTrue(all([r in invoice.message_partner_ids for r in self.parent_co.billing_contacts])) From ecd5e2b55ec1e400cecc1a0f53b4ccb86e28e581 Mon Sep 17 00:00:00 2001 From: Marc Durepos Date: Mon, 26 Jun 2023 15:00:00 -0400 Subject: [PATCH 5/5] bemade_multiple_billing_contacts: Updated view to address a bug. --- __init__.py | 1 - __manifest__.py | 38 ------------ models/__init__.py | 3 - models/account_move.py | 32 ---------- models/res_partner.py | 20 ------ models/sale_order.py | 19 ------ tests/__init__.py | 1 - tests/test_billing_contacts.py | 107 --------------------------------- 8 files changed, 221 deletions(-) delete mode 100644 __init__.py delete mode 100644 __manifest__.py delete mode 100644 models/__init__.py delete mode 100644 models/account_move.py delete mode 100644 models/res_partner.py delete mode 100644 models/sale_order.py delete mode 100644 tests/__init__.py delete mode 100644 tests/test_billing_contacts.py diff --git a/__init__.py b/__init__.py deleted file mode 100644 index 0650744..0000000 --- a/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import models diff --git a/__manifest__.py b/__manifest__.py deleted file mode 100644 index 5e4c2c7..0000000 --- a/__manifest__.py +++ /dev/null @@ -1,38 +0,0 @@ -# -# 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.1', - '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', - 'bemade_partner_root_ancestor', - ], - 'data': [], - 'demo': [], - 'installable': True, - 'auto_install': False, -} diff --git a/models/__init__.py b/models/__init__.py deleted file mode 100644 index fdc1257..0000000 --- a/models/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from . import res_partner -from . import sale_order -from . import account_move diff --git a/models/account_move.py b/models/account_move.py deleted file mode 100644 index a12ddda..0000000 --- a/models/account_move.py +++ /dev/null @@ -1,32 +0,0 @@ -from odoo import models, fields, api - - -class AccountMove(models.Model): - _inherit = 'account.move' - - billing_contacts = fields.Many2many(comodel_name='res.partner', - string="Billing Contacts", - compute='_compute_billing_contacts', - inverse='_inverse_billing_contacts', - store=True) - - @api.depends('line_ids.sale_line_ids.order_id', 'partner_id') - def _compute_billing_contacts(self): - for rec in self: - order_id = rec.line_ids and rec.line_ids.mapped('sale_line_ids').mapped('order_id') - if order_id and len(order_id) == 1 and order_id.billing_contacts: - rec.billing_contacts = order_id.billing_contacts - else: - rec.billing_contacts = rec.partner_id.billing_contacts - - def _inverse_billing_contacts(self): - pass - - def _post(self, soft=True): - # Override the original method to subscribe the partner's billing contacts instead of self.partner_id - initial_subscribers = self.message_partner_ids.ids - final_subscribers = initial_subscribers + self.billing_contacts.ids - posted = super()._post() - self.message_unsubscribe([s.id for s in self.message_partner_ids if s not in initial_subscribers]) - self.message_subscribe(final_subscribers) - return posted diff --git a/models/res_partner.py b/models/res_partner.py deleted file mode 100644 index ae988ff..0000000 --- a/models/res_partner.py +++ /dev/null @@ -1,20 +0,0 @@ -from odoo import models, fields, api, _, Command - - -class Partner(models.Model): - _inherit = 'res.partner' - - billing_contacts = fields.Many2many(string='Default Billing Contacts', - comodel_name='res.partner', - compute='_compute_billing_contacts', - inverse='_inverse_billing_contacts') - - @api.depends('child_ids.type') - def _compute_billing_contacts(self): - for rec in self: - rec.billing_contacts = rec.child_ids.filtered(lambda r: r.type == 'invoice') - - @api.depends('billing_contacts') - def _inverse_billing_contacts(self): - for partner in self.mapped('billing_contacts'): - partner.type = 'invoice' diff --git a/models/sale_order.py b/models/sale_order.py deleted file mode 100644 index 877cc5d..0000000 --- a/models/sale_order.py +++ /dev/null @@ -1,19 +0,0 @@ -from odoo import models, fields, api, _, Command - - -class SaleOrder(models.Model): - _inherit = 'sale.order' - - billing_contacts = fields.Many2many(comodel_name='res.partner', - string='Billing Contacts', - compute='_compute_billing_contacts', - inverse='_inverse_billing_contacts', - store=True) - - @api.depends('partner_id') - def _compute_billing_contacts(self): - for rec in self: - rec.billing_contacts = rec.partner_id.billing_contacts - - def _inverse_billing_contacts(self): - pass diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index 219fd8e..0000000 --- a/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import test_billing_contacts diff --git a/tests/test_billing_contacts.py b/tests/test_billing_contacts.py deleted file mode 100644 index c99d4d5..0000000 --- a/tests/test_billing_contacts.py +++ /dev/null @@ -1,107 +0,0 @@ -from odoo.tests import TransactionCase, tagged -from odoo import Command -import datetime - - -@tagged('-at_install', 'post_install') -class TestBillingContacts(TransactionCase): - @classmethod - def setUpClass(cls): - super().setUpClass() - partner = cls.env['res.partner'].create - cls.parent_co = partner({ - 'name': 'Partner', - 'company_type': 'company', - }) - cls.billing_contact1 = partner({ - 'name': 'Billing Contact 1', - 'company_type': 'person', - 'email': 'billingcontact1@partner.co', - 'parent_id': cls.parent_co.id, - 'type': 'invoice', - }) - cls.billing_contact2 = partner({ - 'name': 'Billing Contact 2', - 'company_type': 'person', - 'email': 'billingcontact2@partner.co', - 'parent_id': cls.parent_co.id, - 'type': 'invoice', - }) - cls.non_billing_contact = partner({ - 'name': 'Non-billing contact', - 'company_type': 'person', - 'email': 'not_billing@partner.co', - 'parent_id': cls.parent_co.id, - 'type': 'contact', - }) - cls.product = cls.env['product.product'].with_company(cls.parent_co.company_id).create({ - 'name': 'Product', - 'categ_id': cls.env['product.category'].create({'name': 'Product Category'}).id, - 'list_price': 100.0, - 'type': 'service', - 'uom_id': cls.env.ref('uom.product_uom_unit').id, - 'uom_po_id': cls.env.ref('uom.product_uom_unit').id, - 'default_code': 'PRODUCT-X', - 'invoice_policy': 'order', - 'expense_policy': 'no', - 'taxes_id': [(6, 0, [])], - 'supplier_taxes_id': [(6, 0, [])], - }) - - cls.sale_order = cls.env['sale.order'].create({ - 'partner_id': cls.parent_co.id, - 'client_order_ref': 'abc123', - }) - - cls.env['sale.order.line'].create({ - 'product_id': cls.product.id, - 'name': cls.product.name, - 'product_uom_qty': 2, - 'product_uom': cls.product.uom_id.id, - 'price_unit': cls.product.list_price, - 'order_id': cls.sale_order.id, - 'tax_id': False, - 'qty_delivered_manual': 2, - }) - - def test_billing_contacts_structure(self): - self.assertTrue(self.billing_contact1 in self.parent_co.billing_contacts) - self.assertTrue(self.billing_contact2 in self.parent_co.billing_contacts) - self.assertTrue(self.non_billing_contact not in self.parent_co.billing_contacts) - - def test_sale_order_default_billing_contacts(self): - self.assertTrue(self.sale_order.billing_contacts == self.parent_co.billing_contacts) - - def test_sale_order_change_contacts(self): - # Test that changing the billing contacts on an SO doesn't change them on the partner - # Validate that changing them manually on the SO transfers to the invoice - self.sale_order.write({'billing_contacts': [Command.link(self.non_billing_contact.id)]}) - self.assertTrue(all([c in self.sale_order.billing_contacts for c in self.parent_co.billing_contacts])) - self.assertTrue(self.non_billing_contact not in self.parent_co.billing_contacts) - self.assertTrue(self.non_billing_contact in self.sale_order.billing_contacts) - - def test_sale_order_to_invoice_contacts(self): - # Test that the invoices created from sales orders take the billing contacts configured on the SO - - self.sale_order.write({'billing_contacts': [Command.link(self.non_billing_contact.id)]}) - self.sale_order.action_confirm() - - wiz = self.env['sale.advance.payment.inv'].create({}) - invoice = wiz._create_invoice(self.sale_order,self.sale_order.order_line[0],self.sale_order.order_line.price_total) - self.assertTrue(invoice) - self.assertTrue(invoice.billing_contacts == self.sale_order.billing_contacts) - - def test_direct_invoice_contacts(self): - invoice = self.env['account.move'].create({ - 'move_type': 'out_invoice', - 'partner_id': self.parent_co, - }) - self.assertTrue(self.parent_co.billing_contacts == invoice.billing_contacts) - - def test_invoice_followers_on_validate(self): - self.sale_order.action_confirm() - wiz = self.env['sale.advance.payment.inv'].create({}) - invoice = wiz._create_invoice(self.sale_order,self.sale_order.order_line[0],self.sale_order.order_line.price_total) - invoice.write({'date': datetime.date.today()}) - invoice.action_post() - self.assertTrue(all([r in invoice.message_partner_ids for r in self.parent_co.billing_contacts]))