forked from OCA/multi-company
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] base_multi_company: Create new module
* Create new module to provide base multi company logic and mixin * Add deactivation by company mixin * Add company_id/ids handling * Add break after company is found Squashed commits: [854cc36] Increase test coverage [770bd71] Revert hook view create back to model init [40e803e] Fix apples and oranges [7a4dfb4] Use registry correctly [6e9f170] Switch company_id to computed & move company aliased view creation to post init hook [faa4fc9] Remove active functionality [fecfb59] Add explicit tests for active and inactive searches
- Loading branch information
1 parent
35f74dc
commit 97700d2
Showing
12 changed files
with
381 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
.. image:: https://img.shields.io/badge/licence-lgpl--3-blue.svg | ||
:target: http://www.gnu.org/licenses/LGPL-3.0-standalone.html | ||
:alt: License: LGPL-3 | ||
|
||
================== | ||
Multi Company Base | ||
================== | ||
|
||
This module provides an abstract model to be inherited by models that need to implement multi-company functionality. | ||
|
||
Installation | ||
============ | ||
|
||
To install this module, simply follow the standard install process. | ||
|
||
Configuration | ||
============= | ||
|
||
No configuration is needed or possible. | ||
|
||
Usage | ||
===== | ||
|
||
Todo | ||
|
||
.. 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/10.0 | ||
|
||
Known Issues / Roadmap | ||
====================== | ||
|
||
* Docs | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/multi-company/issues>`_. | ||
In case of trouble, please check there if your issue has already been reported. | ||
If you spotted it first, help us smash it by providing detailed and welcomed | ||
feedback. | ||
|
||
Credits | ||
======= | ||
|
||
Images | ||
------ | ||
|
||
* Odoo Community Association: | ||
`Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. | ||
|
||
Contributors | ||
------------ | ||
|
||
* Dave Lasley <dave@laslabs.com> | ||
* Pedro M. Baeza <pedro.baeza@tecnativa.com> | ||
|
||
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 http://odoo-community.org. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 LasLabs Inc. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). | ||
|
||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 LasLabs Inc. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). | ||
|
||
{ | ||
'name': 'Multi Company Base', | ||
'summary': 'Provides a base for adding multi-company support to models.', | ||
'version': '10.0.1.0.0', | ||
'author': "LasLabs, Tecnativa, Odoo Community Association (OCA)", | ||
'category': 'base', | ||
'website': 'https://laslabs.com', | ||
'license': 'LGPL-3', | ||
'installable': True, | ||
'application': False, | ||
'depends': [ | ||
'base', | ||
], | ||
'data': [ | ||
'security/ir.model.access.csv', | ||
], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2015-2016 Pedro M. Baeza <pedro.baeza@tecnativa.com> | ||
# Copyright 2017 LasLabs Inc. | ||
# License LGPL-3 - See http://www.gnu.org/licenses/lgpl-3.0.html | ||
|
||
from odoo import api, SUPERUSER_ID | ||
|
||
|
||
__all__ = [ | ||
'post_init_hook', | ||
'uninstall_hook', | ||
] | ||
|
||
|
||
def post_init_hook(cr, rule_ref, model_name): | ||
""" Set the `domain_force` and default `company_ids` to `company_id`. | ||
Args: | ||
cr (Cursor): Database cursor to use for operation. | ||
rule_ref (string): XML ID of security rule to write the | ||
`domain_force` from. | ||
model_name (string): Name of Odoo model object to search for | ||
existing records. | ||
""" | ||
with api.Environment.manage(): | ||
env = api.Environment(cr, SUPERUSER_ID, {}) | ||
# Change access rule | ||
rule = env.ref(rule_ref) | ||
rule.write({ | ||
'active': True, | ||
'domain_force': ( | ||
"['|', ('company_ids', 'in', user.company_id.ids)," | ||
" ('company_id', '=', False)]" | ||
), | ||
}) | ||
# Copy company values | ||
model = env[model_name] | ||
groups = model.read_group([], ['company_id'], ['company_id']) | ||
for group in groups: | ||
if not group['company_id']: | ||
continue | ||
records = model.search(group['__domain']) | ||
records.write({ | ||
'company_ids': [(6, 0, [group['company_id'][0]])], | ||
}) | ||
|
||
|
||
def uninstall_hook(cr, rule_ref): | ||
""" Restore product rule to base value. | ||
Args: | ||
cr (Cursor): Database cursor to use for operation. | ||
rule_ref (string): XML ID of security rule to remove the | ||
`domain_force` from. | ||
""" | ||
with api.Environment.manage(): | ||
env = api.Environment(cr, SUPERUSER_ID, {}) | ||
# Change access rule | ||
rule = env.ref(rule_ref) | ||
rule.write({ | ||
'active': False, | ||
'domain_force': ( | ||
" ['|', ('company_id', '=', user.company_id.id)," | ||
" ('company_id', '=', False)]" | ||
), | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 LasLabs Inc. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). | ||
|
||
from . import multi_company_abstract | ||
from . import res_company_assignment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 LasLabs Inc. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). | ||
|
||
from odoo import api, fields, models | ||
|
||
|
||
class MultiCompanyAbstract(models.AbstractModel): | ||
|
||
_name = 'multi.company.abstract' | ||
_description = 'Multi-Company Abstract' | ||
|
||
company_id = fields.Many2one( | ||
string='Company', | ||
comodel_name='res.company', | ||
compute='_compute_company_id', | ||
inverse='_inverse_company_id', | ||
search='_search_company_id', | ||
) | ||
company_ids = fields.Many2many( | ||
string='Companies', | ||
comodel_name='res.company.assignment', | ||
default=lambda s: s._default_company_ids(), | ||
) | ||
|
||
@api.model | ||
def _default_company_ids(self): | ||
Companies = self.env['res.company'] | ||
return [ | ||
(6, 0, Companies._company_default_get().ids), | ||
] | ||
|
||
@api.multi | ||
@api.depends('company_ids') | ||
def _compute_company_id(self): | ||
for record in self: | ||
for company in record.company_ids: | ||
if company.id in self.env.user.company_ids.ids: | ||
record.company_id = company.id | ||
break | ||
|
||
@api.multi | ||
def _inverse_company_id(self): | ||
for record in self: | ||
if record.company_id.id not in record.company_ids.ids: | ||
record.company_ids = [(4, record.company_id.id)] | ||
|
||
@api.model | ||
def _search_company_id(self, operator, value): | ||
return [('company_ids', operator, value)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 LasLabs Inc. | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). | ||
|
||
from odoo import api, fields, models, tools | ||
|
||
|
||
class ResCompanyAssignment(models.Model): | ||
|
||
_name = 'res.company.assignment' | ||
_auto = False | ||
|
||
name = fields.Char() | ||
|
||
@api.model_cr | ||
def init(self): | ||
tools.drop_view_if_exists(self.env.cr, self._table) | ||
self.env.cr.execute(""" | ||
CREATE OR REPLACE VIEW %s | ||
AS SELECT id, name | ||
FROM res_company; | ||
""" % (self._table)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
access_res_company_assignment_group_erp_manager,res_company_assignment group_erp_manager,model_res_company_assignment,base.group_erp_manager,1,1,1,1 | ||
access_res_company_assignment_group_user,res_company_assignment group_user,model_res_company_assignment,base.group_user,1,0,0,0 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# -*- coding: utf-8 -*- | ||
# License LGPL-3 - See http://www.gnu.org/licenses/lgpl-3.0.html | ||
|
||
from . import test_multi_company_abstract | ||
from . import test_res_company_assignment |
106 changes: 106 additions & 0 deletions
106
base_multi_company/tests/test_multi_company_abstract.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 LasLabs Inc. | ||
# License LGPL-3 - See http://www.gnu.org/licenses/lgpl-3.0.html | ||
|
||
from odoo import fields, models | ||
from odoo.tests import common | ||
|
||
|
||
class MultiCompanyAbstractTester(models.TransientModel): | ||
_name = 'multi.company.abstract.tester' | ||
_inherit = 'multi.company.abstract' | ||
|
||
name = fields.Char() | ||
|
||
|
||
class TestMultiCompanyAbstract(common.SavepointCase): | ||
|
||
@classmethod | ||
def _init_test_model(cls, model_cls): | ||
""" It builds a model from model_cls in order to test abstract models. | ||
Note that this does not actually create a table in the database, so | ||
there may be some unidentified edge cases. | ||
Args: | ||
model_cls (odoo.models.BaseModel): Class of model to initialize | ||
Returns: | ||
model_cls: Instance | ||
""" | ||
registry = cls.env.registry | ||
cr = cls.env.cr | ||
inst = model_cls._build_model(registry, cr) | ||
model = cls.env[model_cls._name].with_context(todo=[]) | ||
model._prepare_setup() | ||
model._setup_base(partial=False) | ||
model._setup_fields(partial=False) | ||
model._setup_complete() | ||
model._auto_init() | ||
model.init() | ||
model._auto_end() | ||
cls.test_model_record = cls.env['ir.model'].search([ | ||
('name', '=', model._name), | ||
]) | ||
return inst | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
super(TestMultiCompanyAbstract, cls).setUpClass() | ||
cls.env.registry.enter_test_mode() | ||
cls._init_test_model(MultiCompanyAbstractTester) | ||
cls.test_model = cls.env[MultiCompanyAbstractTester._name] | ||
|
||
@classmethod | ||
def tearDownClass(cls): | ||
cls.env.registry.leave_test_mode() | ||
super(TestMultiCompanyAbstract, cls).tearDownClass() | ||
|
||
def setUp(self): | ||
super(TestMultiCompanyAbstract, self).setUp() | ||
self.Model = self.env['multi.company.abstract.tester'] | ||
self.record = self.Model.create({ | ||
'name': 'test', | ||
'active': True, | ||
}) | ||
Companies = self.env['res.company'] | ||
self.company_1 = Companies._company_default_get() | ||
self.company_2 = Companies.create({ | ||
'name': 'Test Co 2', | ||
}) | ||
|
||
def add_company(self, company): | ||
""" Add company to the test record. """ | ||
self.record.company_ids = [4, company.id] | ||
|
||
def switch_user_company(self, user, company): | ||
""" Add a company to the user's allowed & set to current. """ | ||
user.write({ | ||
'company_ids': [(6, 0, (company + user.company_ids).ids)], | ||
'company_id': company.id, | ||
}) | ||
|
||
def test_default_company_ids(self): | ||
""" It should set company_ids to the default company. """ | ||
self.assertEqual( | ||
self.record.company_ids.ids, | ||
self.company_1.ids, | ||
) | ||
|
||
def test_compute_company_id(self): | ||
""" It should set company_id to the top of the company_ids stack. """ | ||
self.add_company(self.company_2) | ||
self.assertEqual( | ||
self.record.company_id.id, | ||
self.record.company_ids[0].id, | ||
) | ||
|
||
def test_inverse_company_id(self): | ||
""" It should add the company using company_id. """ | ||
self.record.company_id = self.company_2 | ||
self.assertIn(self.company_2.id, self.record.company_ids.ids) | ||
|
||
def test_search_company_id(self): | ||
""" It should return correct record by searching company_id. """ | ||
record = self.env['multi.company.abstract.tester'].search([ | ||
('company_id', '=', self.company_1.id), | ||
('id', '=', self.record.id), | ||
]) | ||
self.assertEqual(record, self.record) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 LasLabs Inc. | ||
# License LGPL-3 - See http://www.gnu.org/licenses/lgpl-3.0.html | ||
|
||
from odoo.tests import common | ||
|
||
|
||
class TestResCompanyAssignment(common.TransactionCase): | ||
|
||
def setUp(self): | ||
super(TestResCompanyAssignment, self).setUp() | ||
self.View = self.env['res.company.assignment'] | ||
self.Model = self.env['res.company'] | ||
self.views = self.View.search([]) | ||
|
||
def test_equality_len(self): | ||
""" The record lengths should match between mirror and original. """ | ||
len_views = len(self.views) | ||
len_records = len(self.Model.search([])) | ||
self.assertEqual(len_views, len_records) | ||
|
||
def test_equality_data(self): | ||
""" The record data should match between mirror and original. """ | ||
view = self.views[0] | ||
record = self.Model.browse(view.id) | ||
self.assertEqual(view.name, record.name) |