From dba7056c71c785cea714e93cbfb8acf11c1b07e4 Mon Sep 17 00:00:00 2001 From: gawa-odoo Date: Wed, 15 Mar 2023 16:10:40 +0000 Subject: [PATCH] [FIX] analytic: allow filtering based on analytic distribution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the field `analytic_distribution` does not appear in the filters, while it should (to be able to filter `account_move_line` for example). We added Json to the filterable fields. If not overriden, it will search on it like a String. We also have to add a non-stored field to be able to define a search function for `analytic_distribution`, to be able to search based on the keys of the json. closes odoo/odoo#121223 X-original-commit: 3d3e6847230d5cc9cd61a9bf83bef403a5b4b3ec Signed-off-by: William André (wan) --- addons/analytic/i18n/analytic.pot | 13 +++++++ addons/analytic/models/analytic_mixin.py | 36 ++++++++++++++++++- .../domain_selector/domain_selector_fields.js | 11 ++++++ .../tests/core/domain_selector_tests.js | 12 +++++++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/addons/analytic/i18n/analytic.pot b/addons/analytic/i18n/analytic.pot index f42e45223e1..19dd640704a 100644 --- a/addons/analytic/i18n/analytic.pot +++ b/addons/analytic/i18n/analytic.pot @@ -123,6 +123,12 @@ msgstr "" msgid "Analytic Distribution Models" msgstr "" +#. module: analytic +#: model:ir.model.fields,field_description:analytic.field_account_analytic_distribution_model__analytic_distribution_search +#: model:ir.model.fields,field_description:analytic.field_analytic_mixin__analytic_distribution_search +msgid "Analytic Distribution Search" +msgstr "" + #. module: analytic #. odoo-javascript #: code:addons/analytic/static/src/components/analytic_distribution/analytic_distribution.js:0 @@ -577,6 +583,13 @@ msgstr "" msgid "One or more lines require a 100% analytic distribution." msgstr "" +#. module: analytic +#. odoo-python +#: code:addons/analytic/models/analytic_mixin.py:0 +#, python-format +msgid "Operation not supported" +msgstr "" + #. module: analytic #. odoo-javascript #: code:addons/analytic/static/src/components/analytic_distribution/analytic_distribution.js:0 diff --git a/addons/analytic/models/analytic_mixin.py b/addons/analytic/models/analytic_mixin.py index 665dab1c004..33f3dc4c7f2 100644 --- a/addons/analytic/models/analytic_mixin.py +++ b/addons/analytic/models/analytic_mixin.py @@ -2,7 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import models, fields, api, _ from odoo.tools.float_utils import float_round, float_compare -from odoo.exceptions import ValidationError +from odoo.exceptions import UserError, ValidationError class AnalyticMixin(models.AbstractModel): _name = 'analytic.mixin' @@ -13,6 +13,11 @@ class AnalyticMixin(models.AbstractModel): compute="_compute_analytic_distribution", store=True, copy=True, readonly=False, precompute=True ) + # Json non stored to be able to search on analytic_distribution. + analytic_distribution_search = fields.Json( + store=False, + search="_search_analytic_distribution" + ) analytic_precision = fields.Integer( store=False, default=lambda self: self.env['decimal.precision'].precision_get("Percentage Analytic"), @@ -32,9 +37,38 @@ class AnalyticMixin(models.AbstractModel): self.env.cr.execute(query) super().init() + @api.model + def fields_get(self, allfields=None, attributes=None): + """ Hide analytic_distribution_search from filterable/searchable fields""" + res = super().fields_get(allfields, attributes) + if res.get('analytic_distribution_search'): + res['analytic_distribution_search']['searchable'] = False + return res + def _compute_analytic_distribution(self): pass + def _search_analytic_distribution(self, operator, value): + if operator not in ['=', '!=', 'ilike', 'not ilike'] or not isinstance(value, (str, bool)): + raise UserError(_('Operation not supported')) + operator_name_search = '=' if operator in ('=', '!=') else 'ilike' + account_ids = list(self.env['account.analytic.account']._name_search(name=value, operator=operator_name_search)) + + query = f""" + SELECT id + FROM {self._table} + WHERE analytic_distribution ?| array[%s] + """ + operator_inselect = 'inselect' if operator in ('=', 'ilike') else 'not inselect' + return [('id', operator_inselect, (query, [[str(account_id) for account_id in account_ids]]))] + + @api.model + def _search(self, domain, offset=0, limit=None, order=None, access_rights_uid=None): + for arg in domain: + if isinstance(arg, (list, tuple)) and arg[0] == 'analytic_distribution' and isinstance(arg[2], str): + arg[0] = 'analytic_distribution_search' + return super()._search(domain, offset, limit, order, access_rights_uid) + def write(self, vals): """ Format the analytic_distribution float value, so equality on analytic_distribution can be done """ decimal_precision = self.env['decimal.precision'].precision_get('Percentage Analytic') diff --git a/addons/web/static/src/core/domain_selector/domain_selector_fields.js b/addons/web/static/src/core/domain_selector/domain_selector_fields.js index abbd16e0f9e..723d3e8deb1 100644 --- a/addons/web/static/src/core/domain_selector/domain_selector_fields.js +++ b/addons/web/static/src/core/domain_selector/domain_selector_fields.js @@ -328,6 +328,16 @@ const PROPERTIES_RELATIONAL = { defaultValue: (fieldDef) => (fieldDef.type === "many2one" ? 1 : []), }; +// ---------------------------------------------------------------------------- + +const JSON_FIELD = { + operators: ["equal", "not_equal", "ilike", "not_ilike","set", "not_set"], + editors: { + default: makeEditor(Input), + }, + defaultValue: () => "", +}; + // ============================================================================ export const FIELD_DESCRIPTIONS = { @@ -338,6 +348,7 @@ export const FIELD_DESCRIPTIONS = { float: NUMBER, html: TEXT, integer: NUMBER, + json: JSON_FIELD, many2many: RELATIONAL, many2one: RELATIONAL, monetary: NUMBER, diff --git a/addons/web/static/tests/core/domain_selector_tests.js b/addons/web/static/tests/core/domain_selector_tests.js index 509539aada1..58640f89d8d 100644 --- a/addons/web/static/tests/core/domain_selector_tests.js +++ b/addons/web/static/tests/core/domain_selector_tests.js @@ -82,6 +82,7 @@ QUnit.module("Components", (hooks) => { }, datetime: { string: "Date Time", type: "datetime", searchable: true }, int: { string: "Integer", type: "integer", searchable: true }, + json_field: { string: "Json Field", type: "json", searchable: true}, }, records: [ { id: 1, foo: "yop", bar: true, product_id: 37 }, @@ -620,6 +621,17 @@ QUnit.module("Components", (hooks) => { assert.strictEqual(comp.domain, `[("state", "in", ["b"])]`); }); + QUnit.test("json field with operator change from 'equal' to 'ilike'", async (assert) => { + + await makeDomainSelector({ domain: `[['json_field', '=', "hey"]]` }); + assert.strictEqual(target.querySelector(".o_model_field_selector_chain_part").innerText, `Json Field`); + assert.strictEqual(target.querySelector(".o_domain_leaf_operator_select").value, "equal"); // option "=" + assert.strictEqual(target.querySelector(".o_domain_leaf_value_input").value, `hey`); + + await editSelect(target, ".o_domain_leaf_operator_select", "ilike"); + assert.strictEqual(target.querySelector(".o_domain_leaf_operator_select").value, "ilike"); // option "ilike" + }); + QUnit.test("parse -1", async (assert) => { class Parent extends Component { setup() {