diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/README.rst b/ext/3rd-party-addons/product_tax_multicompany_default/README.rst new file mode 100644 index 00000000..2f30137f --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/README.rst @@ -0,0 +1,70 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +================================= +Product Tax Multi Company Default +================================= + +This module sets the default company taxes for all the existing companies when +a product is created. It also adds a button to set all the taxes from other +companies matching them by tax code. + +Configuration +============= + +#. As obvious, you need to have several companies. +#. Go to Accounting > Configuration > Settings +#. Select the proper company (if you are admin or a user with several companies + access), or keep the current one (for a regular user). +#. On Invoicing & Payments section, set fields "Default Sale Tax" and "Default + Purchase Tax". + +Usage +===== + +To use this module, you need to: + +#. Go to Sales > Sales > Products. +#. Create a new product and save it. +#. Switching user company (or being as admin or user with several companies + access), you will see that the product has the default taxes for all the + companies. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/133/9.0 + +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 smashing it by providing a detailed and welcomed feedback. + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Carlos Dauden - Tecnativa +* Pedro M. Baeza + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +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. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/__init__.py b/ext/3rd-party-addons/product_tax_multicompany_default/__init__.py new file mode 100644 index 00000000..7b113364 --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Carlos Dauden - Tecnativa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/__manifest__.py b/ext/3rd-party-addons/product_tax_multicompany_default/__manifest__.py new file mode 100644 index 00000000..6dd728dc --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/__manifest__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Carlos Dauden - Tecnativa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +# noinspection PyStatementEffect +{ + 'name': 'Product Tax Multi Company Default', + 'version': '11.0.1.0.0', + 'category': 'Account', + 'website': 'https://www.tecnativa.com', + 'author': 'Tecnativa, ' + 'Odoo Community Association (OCA)', + 'license': 'AGPL-3', + 'depends': [ + 'account', + 'product', + ], + 'data': [ + 'views/product_template_view.xml', + ], +} diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/i18n/de.po b/ext/3rd-party-addons/product_tax_multicompany_default/i18n/de.po new file mode 100644 index 00000000..2eabf701 --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/i18n/de.po @@ -0,0 +1,73 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_tax_multicompany_default +# +# Translators: +# Rudolf Schnapka , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-08-17 03:16+0000\n" +"PO-Revision-Date: 2017-08-17 03:16+0000\n" +"Last-Translator: Rudolf Schnapka , 2017\n" +"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_company_ids +msgid "Companies" +msgstr "Unternehmen" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_taxes_id +msgid "Customer Taxes" +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_property_account_expense_id +msgid "Expense Account" +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_property_account_income_id +msgid "Income Account" +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model,name:product_tax_multicompany_default.model_product_product +msgid "Product" +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model,name:product_tax_multicompany_default.model_product_template +msgid "Product Template" +msgstr "Produktvorlage" + +#. module: product_tax_multicompany_default +#: model:ir.ui.view,arch_db:product_tax_multicompany_default.product_template_form_view +msgid "Propagate Taxes" +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,help:product_tax_multicompany_default.field_product_product_property_account_expense_id +msgid "" +"This account will be used for invoices instead of the default one to value " +"expenses for the current product." +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,help:product_tax_multicompany_default.field_product_product_property_account_income_id +msgid "" +"This account will be used for invoices instead of the default one to value " +"sales for the current product." +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_supplier_taxes_id +msgid "Vendor Taxes" +msgstr "" diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/i18n/es.po b/ext/3rd-party-addons/product_tax_multicompany_default/i18n/es.po new file mode 100644 index 00000000..ec1f8028 --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/i18n/es.po @@ -0,0 +1,73 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_tax_multicompany_default +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-08-17 03:16+0000\n" +"PO-Revision-Date: 2017-08-17 03:16+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_company_ids +msgid "Companies" +msgstr "Compañías" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_taxes_id +msgid "Customer Taxes" +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_property_account_expense_id +msgid "Expense Account" +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_property_account_income_id +msgid "Income Account" +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model,name:product_tax_multicompany_default.model_product_product +msgid "Product" +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model,name:product_tax_multicompany_default.model_product_template +msgid "Product Template" +msgstr "Plantilla producto" + +#. module: product_tax_multicompany_default +#: model:ir.ui.view,arch_db:product_tax_multicompany_default.product_template_form_view +msgid "Propagate Taxes" +msgstr "Propagar impuestos" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,help:product_tax_multicompany_default.field_product_product_property_account_expense_id +msgid "" +"This account will be used for invoices instead of the default one to value " +"expenses for the current product." +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,help:product_tax_multicompany_default.field_product_product_property_account_income_id +msgid "" +"This account will be used for invoices instead of the default one to value " +"sales for the current product." +msgstr "" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_supplier_taxes_id +msgid "Vendor Taxes" +msgstr "" diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/i18n/fr.po b/ext/3rd-party-addons/product_tax_multicompany_default/i18n/fr.po new file mode 100644 index 00000000..51e3b140 --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/i18n/fr.po @@ -0,0 +1,78 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_tax_multicompany_default +# +# Translators: +# OCA Transbot , 2017 +# Quentin THEURET , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-08-19 05:30+0000\n" +"PO-Revision-Date: 2017-08-19 05:30+0000\n" +"Last-Translator: Quentin THEURET , 2017\n" +"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_company_ids +msgid "Companies" +msgstr "Sociétés" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_taxes_id +msgid "Customer Taxes" +msgstr "Taxes client" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_property_account_expense_id +msgid "Expense Account" +msgstr "Compte de dépense" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_property_account_income_id +msgid "Income Account" +msgstr "Compte de revenu" + +#. module: product_tax_multicompany_default +#: model:ir.model,name:product_tax_multicompany_default.model_product_product +msgid "Product" +msgstr "Produit" + +#. module: product_tax_multicompany_default +#: model:ir.model,name:product_tax_multicompany_default.model_product_template +msgid "Product Template" +msgstr "Template de produit" + +#. module: product_tax_multicompany_default +#: model:ir.ui.view,arch_db:product_tax_multicompany_default.product_template_form_view +msgid "Propagate Taxes" +msgstr "Propager les taxes" + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,help:product_tax_multicompany_default.field_product_product_property_account_expense_id +msgid "" +"This account will be used for invoices instead of the default one to value " +"expenses for the current product." +msgstr "" +"Ce compte sera utilisé pour les factures à la place de celui par défaut pour" +" évaluer les dépenses pour le produit courant." + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,help:product_tax_multicompany_default.field_product_product_property_account_income_id +msgid "" +"This account will be used for invoices instead of the default one to value " +"sales for the current product." +msgstr "" +"Ce compte sera utilisé pour les factures à la place de celui par défaut pour" +" évaluer les ventes du produit courant." + +#. module: product_tax_multicompany_default +#: model:ir.model.fields,field_description:product_tax_multicompany_default.field_product_product_supplier_taxes_id +msgid "Vendor Taxes" +msgstr "Taxes sur la vente" diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/models/__init__.py b/ext/3rd-party-addons/product_tax_multicompany_default/models/__init__.py new file mode 100644 index 00000000..b8fcc3ca --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Carlos Dauden - Tecnativa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import product diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/models/product.py b/ext/3rd-party-addons/product_tax_multicompany_default/models/product.py new file mode 100644 index 00000000..38344a6e --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/models/product.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Carlos Dauden - Tecnativa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models + + +class ProductTemplate(models.Model): + _inherit = 'product.template' + + def taxes_by_company(self, field, company_id, match_tax_ids=None): + taxes_ids = [] + if match_tax_ids is None: + taxes_ids = self.env['ir.values'].get_default( + 'product.template', field, company_id=company_id) + # If None: return default taxes if []: return empty list + if not match_tax_ids: + return isinstance(taxes_ids, list) and taxes_ids or [] + AccountTax = self.env['account.tax'] + for tax in AccountTax.browse(match_tax_ids): + taxes_ids.extend(AccountTax.search([ + ('name', '=', tax.name), + ('company_id', '=', company_id) + ]).ids) + return taxes_ids + + @api.multi + def set_multicompany_taxes(self): + self.ensure_one() + customer_tax_ids = self.taxes_id.ids + supplier_tax_ids = self.supplier_taxes_id.ids + company_id = self.env.user.company_id.id + obj = self.sudo() + default_customer_tax_ids = obj.taxes_by_company( + 'taxes_id', company_id) + default_supplier_tax_ids = obj.taxes_by_company( + 'supplier_taxes_id', company_id) + # Use list() to copy list + match_customer_tax_ids = ( + default_customer_tax_ids != customer_tax_ids and + list(customer_tax_ids) or None) + match_suplier_tax_ids = ( + default_supplier_tax_ids != supplier_tax_ids and + list(supplier_tax_ids) or None) + for company in obj.env['res.company'].search( + [('id', '!=', company_id)]): + customer_tax_ids.extend(obj.taxes_by_company( + 'taxes_id', company.id, match_customer_tax_ids)) + supplier_tax_ids.extend(obj.taxes_by_company( + 'supplier_taxes_id', company.id, match_suplier_tax_ids)) + self.write({ + 'taxes_id': [(6, 0, customer_tax_ids)], + 'supplier_taxes_id': [(6, 0, supplier_tax_ids)], + }) + + @api.model + def create(self, vals): + res = super(ProductTemplate, self).create(vals) + res.set_multicompany_taxes() + return res + + +class ProductProduct(models.Model): + _inherit = 'product.product' + + @api.multi + def set_multicompany_taxes(self): + self.product_tmpl_id.set_multicompany_taxes() diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/tests/__init__.py b/ext/3rd-party-addons/product_tax_multicompany_default/tests/__init__.py new file mode 100644 index 00000000..ea7abca5 --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/tests/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import test_product_tax_multicompany diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/tests/test_product_tax_multicompany.py b/ext/3rd-party-addons/product_tax_multicompany_default/tests/test_product_tax_multicompany.py new file mode 100644 index 00000000..f7b00c49 --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/tests/test_product_tax_multicompany.py @@ -0,0 +1,127 @@ +# -*- coding: utf-8 -*- +# Copyright 2017 Carlos Dauden - Tecnativa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp.tests.common import SavepointCase + + +class TestsProductTaxMulticompany(SavepointCase): + @classmethod + def setUpClass(cls): + super(TestsProductTaxMulticompany, cls).setUpClass() + cls.company_1 = cls.env['res.company'].create( + {'name': 'Test company 1'}) + cls.company_2 = cls.env['res.company'].create( + {'name': 'Test company 2'}) + group_sale_manager = cls.env.ref('base.group_sale_manager') + group_account_manager = cls.env.ref('account.group_account_manager') + ResUsers = cls.env['res.users'] + cls.user_1 = ResUsers.create( + {'name': 'User not admin', + 'login': 'user_1', + 'email': 'test@test.com', + 'groups_id': [(6, 0, ( + group_sale_manager | group_account_manager).ids)], + 'company_id': cls.company_1.id, + 'company_ids': [(6, 0, cls.company_1.ids)]}) + cls.user_2 = ResUsers.create( + {'name': 'User not admin', + 'login': 'user_2', + 'email': 'test@test.com', + 'groups_id': [(6, 0, ( + group_sale_manager | group_account_manager).ids)], + 'company_id': cls.company_2.id, + 'company_ids': [(6, 0, cls.company_2.ids)]}) + AccountTax = cls.env['account.tax'] + tax_vals = { + 'name': 'Test Customer Tax 10%', + 'amount': 10.0, + 'amount_type': 'percent', + 'type_tax_use': 'sale', + } + cls.tax_10_cc1 = AccountTax.sudo(cls.user_1.id).create(tax_vals) + cls.tax_10_cc2 = AccountTax.sudo(cls.user_2.id).create(tax_vals) + tax_vals.update({ + 'name': 'Test Customer Tax 20%', + 'amount': 20.0, + }) + cls.tax_20_cc1 = AccountTax.sudo(cls.user_1.id).create(tax_vals) + cls.tax_20_cc2 = AccountTax.sudo(cls.user_2.id).create(tax_vals) + tax_vals.update({ + 'name': 'Test Supplier Tax 10%', + 'amount': 10.0, + 'type_tax_use': 'purchase', + }) + cls.tax_10_sc1 = AccountTax.sudo(cls.user_1.id).create(tax_vals) + cls.tax_10_sc2 = AccountTax.sudo(cls.user_2.id).create(tax_vals) + tax_vals.update({ + 'name': 'Test Supplier Tax 20%', + 'amount': 20.0, + }) + cls.tax_20_sc1 = AccountTax.sudo(cls.user_1.id).create(tax_vals) + cls.tax_20_sc2 = AccountTax.sudo(cls.user_2.id).create(tax_vals) + IrValues = cls.env['ir.values'] + IrValues.set_default( + 'product.template', "taxes_id", [cls.tax_10_cc1.id], + for_all_users=True, company_id=cls.company_1.id) + IrValues.set_default( + 'product.template', "supplier_taxes_id", [cls.tax_10_sc1.id], + for_all_users=True, company_id=cls.company_1.id) + IrValues.set_default( + 'product.template', "taxes_id", [cls.tax_20_cc2.id], + for_all_users=True, company_id=cls.company_2.id) + IrValues.set_default( + 'product.template', "supplier_taxes_id", [cls.tax_20_sc2.id], + for_all_users=True, company_id=cls.company_2.id) + + def test_multicompany_default_tax(self): + product = self.env['product.product'].sudo(self.user_1.id).create({ + 'name': 'Test Product', + 'company_id': False, + }) + product = product.sudo() + self.assertIn(self.tax_10_cc1, product.taxes_id) + self.assertIn(self.tax_20_cc2, product.taxes_id) + self.assertIn(self.tax_10_sc1, product.supplier_taxes_id) + self.assertIn(self.tax_20_sc2, product.supplier_taxes_id) + + def test_not_default_tax_if_set(self): + product = self.env['product.product'].sudo(self.user_1.id).create({ + 'name': 'Test Product', + 'taxes_id': [(6, 0, self.tax_20_cc1.ids)], + 'supplier_taxes_id': [(6, 0, self.tax_20_sc1.ids)], + 'company_id': False, + }) + product = product.sudo() + self.assertNotIn(self.tax_10_cc1, product.taxes_id) + self.assertNotIn(self.tax_10_sc1, product.supplier_taxes_id) + + def test_default_tax_if_set_match(self): + product = self.env['product.product'].sudo(self.user_2.id).create({ + 'name': 'Test Product', + 'taxes_id': [(6, 0, self.tax_20_cc2.ids)], + 'supplier_taxes_id': [(6, 0, self.tax_20_sc2.ids)], + 'company_id': False, + }) + product = product.sudo() + self.assertIn(self.tax_10_cc1, product.taxes_id) + self.assertIn(self.tax_10_sc1, product.supplier_taxes_id) + + def test_tax_not_default_set_match(self): + IrValues = self.env['ir.values'] + IrValues.set_default( + 'product.template', "taxes_id", [self.tax_20_cc1.id], + for_all_users=True, company_id=self.company_1.id) + IrValues.set_default( + 'product.template', "supplier_taxes_id", [self.tax_20_sc1.id], + for_all_users=True, company_id=self.company_1.id) + + product = self.env['product.product'].sudo(self.user_1.id).create({ + 'name': 'Test Product', + 'taxes_id': [(6, 0, self.tax_10_cc1.ids)], + 'supplier_taxes_id': [(6, 0, self.tax_10_sc1.ids)], + 'company_id': False, + }) + product = product.sudo() + self.assertIn(self.tax_10_cc2, product.taxes_id) + self.assertIn(self.tax_10_sc2, product.supplier_taxes_id) diff --git a/ext/3rd-party-addons/product_tax_multicompany_default/views/product_template_view.xml b/ext/3rd-party-addons/product_tax_multicompany_default/views/product_template_view.xml new file mode 100644 index 00000000..83ab0779 --- /dev/null +++ b/ext/3rd-party-addons/product_tax_multicompany_default/views/product_template_view.xml @@ -0,0 +1,20 @@ + + + + + + Product template form (multi-company tax button) + product.template + + + +