From 9a8add9b9ad7004987846a48c52a973c32502785 Mon Sep 17 00:00:00 2001 From: Laurent Stukkens Date: Tue, 26 Dec 2023 16:24:15 +0100 Subject: [PATCH] [IMP] mis-builder: set analytic account constraint in the filter when displayed This commit extracts, when the filters are displayed, the domain info from the `mis_analytic_domain` context key or from the analyticAccountIdField props and add it to the active filters. The system prevents the user from removing the constraint. --- mis_builder/__manifest__.py | 1 + .../src/components/mis_report_widget.esm.js | 77 +++++++------ .../static/src/components/search_model.esm.js | 105 ++++++++++++++++++ 3 files changed, 150 insertions(+), 33 deletions(-) create mode 100644 mis_builder/static/src/components/search_model.esm.js diff --git a/mis_builder/__manifest__.py b/mis_builder/__manifest__.py index fb1d8dc44..d727bca72 100644 --- a/mis_builder/__manifest__.py +++ b/mis_builder/__manifest__.py @@ -29,6 +29,7 @@ ], "assets": { "web.assets_backend": [ + "mis_builder/static/src/components/search_model.esm.js", "mis_builder/static/src/components/mis_report_widget.esm.js", "mis_builder/static/src/components/mis_report_widget.xml", "mis_builder/static/src/components/mis_report_widget.css", diff --git a/mis_builder/static/src/components/mis_report_widget.esm.js b/mis_builder/static/src/components/mis_report_widget.esm.js index 0acc25ed7..5b8db981f 100644 --- a/mis_builder/static/src/components/mis_report_widget.esm.js +++ b/mis_builder/static/src/components/mis_report_widget.esm.js @@ -3,10 +3,9 @@ import {Component, onWillStart, useState, useSubEnv} from "@odoo/owl"; import {useBus, useService} from "@web/core/utils/hooks"; import {DatePicker} from "@web/core/datepicker/datepicker"; -import {Domain} from "@web/core/domain"; import {FilterMenu} from "@web/search/filter_menu/filter_menu"; +import {MisReportSearchModel} from "@mis_builder/components/search_model.esm"; import {SearchBar} from "@web/search/search_bar/search_bar"; -import {SearchModel} from "@web/search/search_model"; import {parseDate} from "@web/core/l10n/dates"; import {registry} from "@web/core/registry"; import {standardFieldProps} from "@web/views/fields/standard_field_props"; @@ -23,7 +22,7 @@ export class MisReportWidget extends Component { mis_report_data: {header: [], body: []}, pivot_date: null, }); - this.searchModel = new SearchModel(this.env, { + this.searchModel = new MisReportSearchModel(this.env, { user: this.user, orm: this.orm, view: this.view, @@ -63,6 +62,7 @@ export class MisReportWidget extends Component { await this.searchModel.load({ resModel: this.source_aml_model_name, searchViewId: this.widget_search_view_id, + analyticAccountId: this.analyticAccountId, }); } @@ -111,12 +111,10 @@ export class MisReportWidget extends Component { get context() { let ctx = this.props.record.context; - this.setMisAnalyticDomainContextKey(ctx); if (this.showSearchBar && this.searchModel.searchDomain) { - ctx[this.misAnalyticDomainContextKey] = Domain.and([ - ctx[this.misAnalyticDomainContextKey], - new Domain(this.searchModel.searchDomain), - ]).toList(); + ctx[this.misAnalyticDomainContextKey] = this.searchModel.searchDomain; + } else { + this._setMisAnalyticDomainContextKey(ctx); } if (this.showPivotDate && this.state.pivot_date) { ctx = { @@ -147,34 +145,47 @@ export class MisReportWidget extends Component { ); } - setMisAnalyticDomainContextKey(context) { + get analyticAccountId() { + let analyticAccountId = this._getAnalyticAccountIdFromData(); if ( - this.props.analytic_account_id_field && - !(this.misAnalyticDomainContextKey in context) + !analyticAccountId && + this.props.record.context && + this.props.record.context.mis_analytic_domain ) { - let analyticAccountId = false; - const analyticAccountIdFieldType = - this.props.record.fields[this.props.analytic_account_id_field].type; - switch (analyticAccountIdFieldType) { - case "many2one": - analyticAccountId = - this.props.record.data[this.props.analytic_account_id_field][0]; - break; - case "integer": - analyticAccountId = - this.props.record.data[this.props.analytic_account_id_field]; - break; - default: - throw new Error( - ```Unsupported field type for analytic_account_id: ${analyticAccountIdFieldType}``` - ); - } - if (analyticAccountId) { - context[this.misAnalyticDomainContextKey] = [ - ["analytic_account_id", "=", analyticAccountId], - ]; - } + analyticAccountId = this.props.record.context.mis_analytic_domain[0][2]; } + return analyticAccountId; + } + + _getAnalyticAccountIdFromData() { + if ( + !this.props.analyticAccountIdField || + !(this.props.analyticAccountIdField in this.props.record.fields) + ) { + return false; + } + const analyticAccountIdFieldType = + this.props.record.fields[this.props.analyticAccountIdField].type; + switch (analyticAccountIdFieldType) { + case "many2one": + return this.props.record.data[this.props.analyticAccountIdField][0]; + case "integer": + return this.props.record.data[this.props.analyticAccountIdField]; + default: + throw new Error( + ```Unsupported field type for analytic_account_id: ${analyticAccountIdFieldType}``` + ); + } + } + + _setMisAnalyticDomainContextKey(context) { + const analyticAccountId = this._getAnalyticAccountIdFromData(); + if (!analyticAccountId) { + return; + } + context[this.misAnalyticDomainContextKey] = [ + ["analytic_account_id", "=", analyticAccountId], + ]; } async printPdf() { diff --git a/mis_builder/static/src/components/search_model.esm.js b/mis_builder/static/src/components/search_model.esm.js new file mode 100644 index 000000000..61bfcd835 --- /dev/null +++ b/mis_builder/static/src/components/search_model.esm.js @@ -0,0 +1,105 @@ +/** @odoo-module **/ + +import {SearchModel} from "@web/search/search_model"; +import {useService} from "@web/core/utils/hooks"; + +export class MisReportSearchModel extends SearchModel { + /** + * @override + */ + setup() { + this.notificationService = useService("notification"); + super.setup(...arguments); + } + + /** + * @override + */ + deactivateGroup(groupId) { + // Prevent removing the analytic account filter and let the user know. + let reactivateAnalyticAccountFilter = false; + if (this.analyticAccountSearchItem.groupId === groupId) { + if ( + this.query.filter( + (query) => query.searchItemId === this.analyticAccountSearchItem.id + ).length === 1 + ) { + this.notificationService.add( + this.env._t("The analytic account filter cannot be removed"), + {type: "info"} + ); + return; + } + // As there are more than one filter on the analytic account, let + // super remove them and add it back after. + reactivateAnalyticAccountFilter = true; + } + super.deactivateGroup(groupId); + if (reactivateAnalyticAccountFilter) { + this._addAnalyticAccountFilter(); + } + } + + /** + * @override + */ + async load(config) { + // Store analytic account id in the SearchModel for reuse in other functions. + this.analyticAccountId = config.analyticAccountId; + const analyticAccountNamePromise = this._loadAnalyticAccountName(); + await Promise.all([analyticAccountNamePromise, super.load(...arguments)]); + this._determineAnalyticAccountSearchItem(); + this._addAnalyticAccountFilter(); + } + + /** + * Add the filter regarding the analytic account in the search model. + * @private + */ + _addAnalyticAccountFilter() { + if (!this.analyticAccountSearchItem || !this.analyticAccountName) { + return; + } + this.addAutoCompletionValues(this.analyticAccountSearchItem.id, { + label: this.analyticAccountName, + operator: "=", + value: this.analyticAccountId, + }); + } + + /** + * Find the searchItem that correspond to the analytic account field and store it + * under analyticAccountSearchItem. + * @private + */ + _determineAnalyticAccountSearchItem() { + // Store analytic account searchItem in the SearchModel for reuse in other functions. + for (const searchItem of Object.values(this.searchItems)) { + if ( + searchItem.type === "field" && + searchItem.fieldName === "analytic_account_id" + ) { + this.analyticAccountSearchItem = searchItem; + break; + } + } + } + + /** + * Load the analytic account name and store it under analyticAccountName. + * @returns {Promise} + * @private + */ + async _loadAnalyticAccountName() { + if (!this.analyticAccountId) { + return; + } + const readResult = await this.orm.read( + "account.analytic.account", + [this.analyticAccountId], + ["display_name"] + ); + const analyticAccount = readResult[0]; + this.analyticAccountName = analyticAccount.display_name; + } +}