From 68d6427a2a15f7f3f6f7e1df05e85624e0feff81 Mon Sep 17 00:00:00 2001 From: "Laurent Stukkens (LTU)" Date: Wed, 17 Mar 2021 14:24:09 +0000 Subject: [PATCH] [FIX] web: correctly set current_company_id in BasicModel This commit fix a bug introduced in #66551 where a mismatch has been done between session.user_context.allowed_company_ids and session.user_companies.allowed_companies. This commit also adds the following tests: - a JS test in order to prevent future unwanted issues regarding multi company in BasicModel. - a Python test in order to ensure that session_info['user_companies'] is not involuntarily changed. closes odoo/odoo#68025 Signed-off-by: Yannick Tivisse (yti) --- .../static/src/js/views/basic/basic_model.js | 2 +- .../static/tests/views/basic_model_tests.js | 70 +++++++++++++++++++ addons/web/tests/__init__.py | 1 + addons/web/tests/test_session_info.py | 58 +++++++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 addons/web/tests/test_session_info.py diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index 1e14b4c1f41..8a420d4cea1 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -3711,7 +3711,7 @@ var BasicModel = AbstractModel.extend({ // in general, the actual "company_id" field of the form should be used for m2o domains, not this fallback let current_company_id; if (session.user_context.allowed_company_ids) { - current_company_id = Object.keys(session.user_context.allowed_company_ids)[0]; + current_company_id = session.user_context.allowed_company_ids[0]; } else { current_company_id = session.user_companies ? session.user_companies.current_company : diff --git a/addons/web/static/tests/views/basic_model_tests.js b/addons/web/static/tests/views/basic_model_tests.js index a97fb0ddd1c..a9ee71393bc 100644 --- a/addons/web/static/tests/views/basic_model_tests.js +++ b/addons/web/static/tests/views/basic_model_tests.js @@ -4,6 +4,7 @@ odoo.define('web.basic_model_tests', function (require) { var BasicModel = require('web.BasicModel'); var FormView = require('web.FormView'); var testUtils = require('web.test_utils'); + const session = require('web.session'); var createModel = testUtils.createModel; var createView = testUtils.createView; @@ -2530,4 +2531,73 @@ odoo.define('web.basic_model_tests', function (require) { assert.equal(model.getActiveField(record), 'active', 'should have returned "active" field name'); }); }); + QUnit.module('Multi Company', function (hooks) { + let sessionUserCompaniesBackup; + let sessionUserContextBackup; + hooks.before(function (assert) { + // Backups session parts that this testing module will alter in order to restore it at the end. + sessionUserCompaniesBackup = 'user_companies' in session && session.user_companies || false; + sessionUserContextBackup = 'user_context' in session && session.user_context || false; + session.user_companies = { + current_company: 3, + allowed_companies: { + 1: { + id: 1, + name: 'Company 1', + }, + 2: { + id: 2, + name: 'Company 2', + }, + 3: { + id: 3, + name: 'Company 3', + }, + }, + }; + session.user_context = { + allowed_company_ids: [1, 2], + }; + }); + hooks.after(function (assert) { + if (sessionUserCompaniesBackup !== false) { + session.user_companies = sessionUserCompaniesBackup || { }; + } else { + delete session.user_companies; + } + if (sessionUserContextBackup !== false) { + session.user_context = sessionUserContextBackup || { }; + } else { + delete session.user_context; + } + }); + QUnit.test('basic_model _getEvalContext returns a correct current_company_id', async function(assert) { + assert.expect(3); + + const model = await createModel({ + Model: BasicModel, + data: this.data, + }); + + let context = model._getEvalContext({ }); + assert.strictEqual( + context.current_company_id, + session.user_context.allowed_company_ids[0], + 'basic_model _getEvalContext returns the first entry in session.user_context.allowed_company_ids array'); + + session.user_context.allowed_company_ids = [2, 1]; + context = model._getEvalContext({ }); + assert.strictEqual( + context.current_company_id, + session.user_context.allowed_company_ids[0], + 'basic_model _getEvalContext returns the first entry in session.user_context.allowed_company_ids array'); + + delete session.user_context.allowed_company_ids; + context = model._getEvalContext({ }); + assert.strictEqual( + context.current_company_id, + session.user_companies.current_company, + 'basic_model _getEvalContext returns session.user_companies.current_company when session.user_context.allowed_company_ids is not set'); + }); + }); }); diff --git a/addons/web/tests/__init__.py b/addons/web/tests/__init__.py index 5008bb7fabe..5ec79d46d36 100644 --- a/addons/web/tests/__init__.py +++ b/addons/web/tests/__init__.py @@ -7,3 +7,4 @@ from . import test_menu from . import test_serving_base from . import test_click_everywhere from . import test_base_document_layout +from . import test_session_info diff --git a/addons/web/tests/test_session_info.py b/addons/web/tests/test_session_info.py new file mode 100644 index 00000000000..3db8fe89cf2 --- /dev/null +++ b/addons/web/tests/test_session_info.py @@ -0,0 +1,58 @@ +# -*- encoding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +import json +from uuid import uuid4 + +from odoo import Command +from odoo.tests import common + + +class TestSessionInfo(common.HttpCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.company_a = cls.env['res.company'].create({'name': "A"}) + cls.company_b = cls.env['res.company'].create({'name': "B"}) + cls.company_c = cls.env['res.company'].create({'name': "C"}) + cls.companies = [cls.company_a, cls.company_b, cls.company_c] + + cls.user_password = "info" + cls.user = common.new_test_user( + cls.env, + "session", + email="session@in.fo", + password=cls.user_password, + tz="UTC") + cls.user.write({ + 'company_id': cls.company_a.id, + 'company_ids': [Command.set([company.id for company in cls.companies])], + }) + + cls.payload = json.dumps(dict(jsonrpc="2.0", method="call", id=str(uuid4()))) + cls.headers = { + "Content-Type": "application/json", + } + + def test_session_info(self): + """ Checks that the session_info['user_companies'] structure correspond to what is expected """ + self.authenticate(self.user.login, self.user_password) + response = self.url_open("/web/session/get_session_info", data=self.payload, headers=self.headers) + self.assertEqual(response.status_code, 200) + + data = response.json() + result = data["result"] + + expected_allowed_companies = { + str(company.id): { + 'id': company.id, + 'name': company.name, + } for company in self.companies + } + expected_user_companies = { + 'current_company': self.company_a.id, + 'allowed_companies': expected_allowed_companies, + } + self.assertEqual( + result['user_companies'], + expected_user_companies, + "The session_info['user_companies'] does not have the expected structure")