diff --git a/addons/spreadsheet/models/spreadsheet_mixin.py b/addons/spreadsheet/models/spreadsheet_mixin.py index b59e916ce4e..8bf630dc68a 100644 --- a/addons/spreadsheet/models/spreadsheet_mixin.py +++ b/addons/spreadsheet/models/spreadsheet_mixin.py @@ -68,7 +68,8 @@ class SpreadsheetMixin(models.AbstractModel): ], "settings": { "locale": locale, - } + }, + "revisionId": "START_REVISION", } def _zip_xslx_files(self, files): diff --git a/addons/spreadsheet_dashboard/models/spreadsheet_dashboard.py b/addons/spreadsheet_dashboard/models/spreadsheet_dashboard.py index 0e4d2f6f065..6f332e06636 100644 --- a/addons/spreadsheet_dashboard/models/spreadsheet_dashboard.py +++ b/addons/spreadsheet_dashboard/models/spreadsheet_dashboard.py @@ -1,5 +1,8 @@ +import json + from odoo import fields, models + class SpreadsheetDashboard(models.Model): _name = 'spreadsheet.dashboard' _description = 'Spreadsheet Dashboard' @@ -10,3 +13,14 @@ class SpreadsheetDashboard(models.Model): dashboard_group_id = fields.Many2one('spreadsheet.dashboard.group', required=True) sequence = fields.Integer() group_ids = fields.Many2many('res.groups', default=lambda self: self.env.ref('base.group_user')) + + + def get_readonly_dashboard(self): + self.ensure_one() + snapshot = json.loads(self.spreadsheet_data) + user_locale = self.env['res.lang']._get_user_spreadsheet_locale() + snapshot.setdefault('settings', {})['locale'] = user_locale + return { + 'snapshot': snapshot, + 'revisions': [], + } diff --git a/addons/spreadsheet_dashboard/static/src/bundle/dashboard_action/dashboard_action.js b/addons/spreadsheet_dashboard/static/src/bundle/dashboard_action/dashboard_action.js index 36b0c1eea27..91047a464f1 100644 --- a/addons/spreadsheet_dashboard/static/src/bundle/dashboard_action/dashboard_action.js +++ b/addons/spreadsheet_dashboard/static/src/bundle/dashboard_action/dashboard_action.js @@ -25,9 +25,7 @@ export class SpreadsheetDashboardAction extends Component { // with the breadcrumb // TODO write a test /** @type {DashboardLoader}*/ - this.loader = useState( - new DashboardLoader(this.env, this.env.services.orm, this._fetchDashboardData) - ); + this.loader = useState(new DashboardLoader(this.env, this.env.services.orm)); onWillStart(async () => { if (this.props.state && this.props.state.dashboardLoader) { const { groups, dashboards } = this.props.state.dashboardLoader; @@ -117,20 +115,6 @@ export class SpreadsheetDashboardAction extends Component { this.state.activeDashboard = this.loader.getDashboard(dashboardId); } - /** - * @private - * @param {number} dashboardId - * @returns {Promise<{ data: string, revisions: object[] }>} - */ - async _fetchDashboardData(dashboardId) { - const [record] = await this.orm.read( - "spreadsheet.dashboard", - [dashboardId], - ["spreadsheet_data"] - ); - return { data: JSON.parse(record.spreadsheet_data), revisions: [] }; - } - async shareSpreadsheet(data, excelExport) { const url = await this.orm.call("spreadsheet.dashboard.share", "action_get_share_url", [ { diff --git a/addons/spreadsheet_dashboard/static/src/bundle/dashboard_action/dashboard_loader.js b/addons/spreadsheet_dashboard/static/src/bundle/dashboard_action/dashboard_loader.js index a4b46897687..eca717832d4 100644 --- a/addons/spreadsheet_dashboard/static/src/bundle/dashboard_action/dashboard_loader.js +++ b/addons/spreadsheet_dashboard/static/src/bundle/dashboard_action/dashboard_loader.js @@ -37,8 +37,6 @@ export const Status = { * @property {string} name * @property {Array} dashboards * - * @typedef {(dashboardId: number) => Promise<{ data: string, revisions: object[] }>} FetchDashboardData - * * @typedef {import("@web/env").OdooEnv} OdooEnv * * @typedef {import("@web/core/orm_service").ORM} ORM @@ -48,9 +46,8 @@ export class DashboardLoader { /** * @param {OdooEnv} env * @param {ORM} orm - * @param {FetchDashboardData} fetchDashboardData */ - constructor(env, orm, fetchDashboardData) { + constructor(env, orm) { /** @private */ this.env = env; /** @private */ @@ -59,8 +56,6 @@ export class DashboardLoader { this.groups = []; /** @private @type {Object} */ this.dashboards = {}; - /** @private */ - this.fetchDashboardData = fetchDashboardData; } /** @@ -166,8 +161,12 @@ export class DashboardLoader { const dashboard = this._getDashboard(dashboardId); dashboard.status = Status.Loading; try { - const { data, revisions } = await this.fetchDashboardData(dashboardId); - dashboard.model = this._createSpreadsheetModel(data, revisions); + const { snapshot, revisions } = await this.orm.call( + "spreadsheet.dashboard", + "get_readonly_dashboard", + [dashboardId] + ); + dashboard.model = this._createSpreadsheetModel(snapshot, revisions); dashboard.status = Status.Loaded; } catch (error) { dashboard.error = error; @@ -193,14 +192,14 @@ export class DashboardLoader { /** * @private - * @param {string} data + * @param {object} snapshot * @param {object[]} revisions * @returns {Model} */ - _createSpreadsheetModel(data, revisions = []) { + _createSpreadsheetModel(snapshot, revisions = []) { const dataSources = new DataSources(this.env); const model = new Model( - migrate(data), + migrate(snapshot), { custom: { env: this.env, orm: this.orm, dataSources }, mode: "dashboard", diff --git a/addons/spreadsheet_dashboard/static/tests/dashboard/dashboard_action_test.js b/addons/spreadsheet_dashboard/static/tests/dashboard/dashboard_action_test.js index 3d34d781025..745af57f904 100644 --- a/addons/spreadsheet_dashboard/static/tests/dashboard/dashboard_action_test.js +++ b/addons/spreadsheet_dashboard/static/tests/dashboard/dashboard_action_test.js @@ -102,12 +102,8 @@ QUnit.test("display error message", async (assert) => { mockRPC: function (route, args) { if ( args.model === "spreadsheet.dashboard" && - ((args.method === "read" && - args.args[0][0] === 2 && - args.args[1][0] === "spreadsheet_data") || - // this is not correct from a module dependency POV but it's required for the test - // to pass when `spreadsheet_dashboard_edition` module is installed - (args.method === "join_spreadsheet_session" && args.args[0] === 2)) + args.method === "get_readonly_dashboard" && + args.args[0] === 2 ) { throw new Error("Bip"); } diff --git a/addons/spreadsheet_dashboard/static/tests/dashboard/dashboard_loader_test.js b/addons/spreadsheet_dashboard/static/tests/dashboard/dashboard_loader_test.js index d84d586184a..06454ff117a 100644 --- a/addons/spreadsheet_dashboard/static/tests/dashboard/dashboard_loader_test.js +++ b/addons/spreadsheet_dashboard/static/tests/dashboard/dashboard_loader_test.js @@ -98,7 +98,14 @@ QUnit.test("load spreadsheet data", async (assert) => { QUnit.test("load spreadsheet data only once", async (assert) => { const loader = await createDashboardLoader({ mockRPC: function (route, args) { - if (args.method === "read" && args.model === "spreadsheet.dashboard") { + if (args.model === "spreadsheet.dashboard" && args.method === "read") { + // read names + assert.step(`spreadsheet ${args.args[0]} loaded`); + } + if ( + args.model === "spreadsheet.dashboard" && + args.method === "get_readonly_dashboard" + ) { assert.step(`spreadsheet ${args.args[0]} loaded`); } }, @@ -159,6 +166,13 @@ QUnit.test("load multiple spreadsheets", async (assert) => { assert.step("load groups"); } if (args.method === "read" && args.model === "spreadsheet.dashboard") { + // read names + assert.step(`spreadsheet ${args.args[0]} loaded`); + } + if ( + args.model === "spreadsheet.dashboard" && + args.method === "get_readonly_dashboard" + ) { assert.step(`spreadsheet ${args.args[0]} loaded`); } }, @@ -180,9 +194,8 @@ QUnit.test("load spreadsheet data with error", async (assert) => { const loader = await createDashboardLoader({ mockRPC: function (route, args) { if ( - args.method === "read" && - args.model === "spreadsheet.dashboard" && - args.args[1][0] === "spreadsheet_data" + args.method === "get_readonly_dashboard" && + args.model === "spreadsheet.dashboard" ) { throw new Error("Bip"); } diff --git a/addons/spreadsheet_dashboard/static/tests/utils/mock_server.js b/addons/spreadsheet_dashboard/static/tests/utils/mock_server.js new file mode 100644 index 00000000000..88187f3a4bd --- /dev/null +++ b/addons/spreadsheet_dashboard/static/tests/utils/mock_server.js @@ -0,0 +1,16 @@ +/** @odoo-module */ + +import { registry } from "@web/core/registry"; + +registry + .category("mock_server") + .add("spreadsheet.dashboard/get_readonly_dashboard", function (route, args) { + const [id] = args.args; + const dashboard = this.models["spreadsheet.dashboard"].records.find( + (record) => record.id === id + ); + return { + snapshot: JSON.parse(dashboard.spreadsheet_data), + revisions: [], + }; + }); diff --git a/addons/spreadsheet_dashboard/tests/test_spreadsheet_dashboard.py b/addons/spreadsheet_dashboard/tests/test_spreadsheet_dashboard.py index be08471ae24..c6c47d348ea 100644 --- a/addons/spreadsheet_dashboard/tests/test_spreadsheet_dashboard.py +++ b/addons/spreadsheet_dashboard/tests/test_spreadsheet_dashboard.py @@ -1,9 +1,11 @@ import json -from odoo.tests.common import TransactionCase from odoo.exceptions import UserError -class TestSpreadsheetDashboard(TransactionCase): +from .common import DashboardTestCommon + + +class TestSpreadsheetDashboard(DashboardTestCommon): def test_create_with_default_values(self): group = self.env["spreadsheet.dashboard.group"].create( {"name": "a group"} @@ -32,3 +34,18 @@ class TestSpreadsheetDashboard(TransactionCase): }) with self.assertRaises(UserError, msg="You cannot delete a_group as it is used in another module"): group.unlink() + + def test_load_with_user_locale(self): + dashboard = self.create_dashboard().with_user(self.user) + self.user.lang = "en_US" + data = dashboard.get_readonly_dashboard() + locale = data["snapshot"]["settings"]["locale"] + self.assertEqual(locale["code"], "en_US") + self.assertEqual(len(data["revisions"]), 0) + + self.env.ref("base.lang_fr").active = True + self.user.lang = "fr_FR" + data = dashboard.get_readonly_dashboard() + locale = data["snapshot"]["settings"]["locale"] + self.assertEqual(locale["code"], "fr_FR") + self.assertEqual(len(data["revisions"]), 0)