Skip to content

Commit 22d4267

Browse files
committed
[UPD] web_m2x_options_manager: overhaul
* align M2ODialog option configuration to other options * allow configuring models' inverse fields too * add proper menu and views * refactoring * improve tests
1 parent 0811ee0 commit 22d4267

File tree

20 files changed

+808
-241
lines changed

20 files changed

+808
-241
lines changed

web_m2x_options_manager/README.rst

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,16 @@ Usage
4141

4242
Go to Settings > Technical > Models.
4343

44-
Choose the model you wish to edit, and open its form view. Go to the
45-
"Create/Edit Options" tab, and add the fields you want to manage.
44+
Choose the model you wish to edit, and open its form view. Go to the "Create/Edit Options" tab,
45+
and add the fields you want to manage in 2 different sections:
4646

47-
Button "Fill" will add every missing field to the options.
48-
Button "Empty" will remove every option.
47+
* the first list view allows you to handle fields for the selected model
48+
* the second list view allows you handle fields where the selected model is the comodel
49+
50+
For both sections:
51+
52+
* button "Fill" will add every missing field to the options
53+
* button "Empty" will remove every option
4954

5055
Bug Tracker
5156
===========
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
# Copyright 2021 Camptocamp SA
2-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3-
41
from . import models
2+
from .hooks import pre_init_hook

web_m2x_options_manager/__manifest__.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,25 @@
66
"summary": 'Adds an interface to manage the "Create" and'
77
' "Create and Edit" options for specific models and'
88
" fields.",
9-
"version": "14.0.1.3.0",
9+
"version": "14.0.2.0.0",
1010
"author": "Camptocamp, Odoo Community Association (OCA)",
1111
"license": "AGPL-3",
1212
"category": "Web",
1313
"data": [
1414
"security/ir.model.access.csv",
1515
"views/ir_model.xml",
16+
"views/m2x_create_edit_option.xml",
1617
],
1718
"demo": [
1819
"demo/res_partner_demo_view.xml",
1920
],
20-
"depends": ["base", "web_m2x_options"],
21+
"depends": [
22+
# OCA/server-tools
23+
"base_view_inheritance_extension",
24+
# OCA/web
25+
"web_m2x_options",
26+
],
2127
"website": "https://github.com/OCA/web",
2228
"installable": True,
29+
"pre_init_hook": "pre_init_hook",
2330
}

web_m2x_options_manager/demo/res_partner_demo_view.xml

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@
99
<form>
1010
<sheet>
1111
<group>
12-
<!-- Many2one -->
12+
<!-- Many2one w/o options -->
1313
<field name="title" />
14-
<!-- Many2many -->
15-
<field name="category_id" options="{'create': False}" />
16-
<!-- One2many -->
17-
<field name="user_ids">
18-
<tree>
19-
<!-- Many2one within tree -->
20-
<field name="company_id" options="{'create': False}" />
21-
</tree>
22-
</field>
14+
<!-- Many2one w/ options -->
15+
<field
16+
name="parent_id"
17+
options="{'create': False, 'create_edit': False, 'm2o_dialog': False}"
18+
/>
19+
<!-- Many2many w/ options -->
20+
<field
21+
name="category_id"
22+
options="{'create': False, 'create_edit': False, 'm2o_dialog': False}"
23+
/>
2324
</group>
2425
</sheet>
2526
</form>

web_m2x_options_manager/hooks.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright 2025 Camptocamp SA
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
4+
from .tools import prepare_column_can_have_options, prepare_column_comodel_id
5+
6+
7+
def pre_init_hook(cr):
8+
# Pre-create and pre-fill these columns for perf reasons (might take a while to
9+
# let Odoo do it via the ORM for huge DBs)
10+
prepare_column_can_have_options(cr)
11+
prepare_column_comodel_id(cr)

web_m2x_options_manager/i18n/it.po

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ msgid "Create & Edit Option"
3434
msgstr "Opzione crea & modifica"
3535

3636
#. module: web_m2x_options_manager
37-
#: model:ir.model.fields,field_description:web_m2x_options_manager.field_m2x_create_edit_option__option_create_edit_wizard
37+
#: model:ir.model.fields,field_description:web_m2x_options_manager.field_m2x_create_edit_option__option_m2o_dialog
3838
msgid "Create & Edit Wizard"
3939
msgstr "Procedura guidata crea & modifica"
4040

@@ -59,7 +59,7 @@ msgid "Created on"
5959
msgstr "Creato il"
6060

6161
#. module: web_m2x_options_manager
62-
#: model:ir.model.fields,help:web_m2x_options_manager.field_m2x_create_edit_option__option_create_edit_wizard
62+
#: model:ir.model.fields,help:web_m2x_options_manager.field_m2x_create_edit_option__option_m2o_dialog
6363
msgid ""
6464
"Defines behaviour for 'Create & Edit' Wizard\n"
6565
"Set to False to prevent 'Create & Edit' Wizard to pop up"
@@ -180,7 +180,7 @@ msgid "Last Updated on"
180180
msgstr "Ultimo aggiornamento il"
181181

182182
#. module: web_m2x_options_manager
183-
#: model:ir.model.fields,field_description:web_m2x_options_manager.field_ir_model__m2x_create_edit_option_ids
183+
#: model:ir.model.fields,field_description:web_m2x_options_manager.field_ir_model__m2x_option_ids
184184
msgid "M2X Create Edit Option"
185185
msgstr "Crea opzione modifica M2X"
186186

web_m2x_options_manager/i18n/web_m2x_options_manager.pot

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ msgid "Create & Edit Option"
3131
msgstr ""
3232

3333
#. module: web_m2x_options_manager
34-
#: model:ir.model.fields,field_description:web_m2x_options_manager.field_m2x_create_edit_option__option_create_edit_wizard
34+
#: model:ir.model.fields,field_description:web_m2x_options_manager.field_m2x_create_edit_option__option_m2o_dialog
3535
msgid "Create & Edit Wizard"
3636
msgstr ""
3737

@@ -56,7 +56,7 @@ msgid "Created on"
5656
msgstr ""
5757

5858
#. module: web_m2x_options_manager
59-
#: model:ir.model.fields,help:web_m2x_options_manager.field_m2x_create_edit_option__option_create_edit_wizard
59+
#: model:ir.model.fields,help:web_m2x_options_manager.field_m2x_create_edit_option__option_m2o_dialog
6060
msgid ""
6161
"Defines behaviour for 'Create & Edit' Wizard\n"
6262
"Set to False to prevent 'Create & Edit' Wizard to pop up"
@@ -158,7 +158,7 @@ msgid "Last Updated on"
158158
msgstr ""
159159

160160
#. module: web_m2x_options_manager
161-
#: model:ir.model.fields,field_description:web_m2x_options_manager.field_ir_model__m2x_create_edit_option_ids
161+
#: model:ir.model.fields,field_description:web_m2x_options_manager.field_ir_model__m2x_option_ids
162162
msgid "M2X Create Edit Option"
163163
msgstr ""
164164

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright 2025 Camptocamp SA
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
4+
from odoo.tools.sql import column_exists, create_column, drop_constraint
5+
6+
# pylint: disable=odoo-addons-relative-import
7+
from odoo.addons.web_m2x_options_manager.tools import (
8+
prepare_column_can_have_options,
9+
prepare_column_comodel_id,
10+
)
11+
12+
13+
def migrate(cr, version):
14+
if not version:
15+
return
16+
17+
# Migrate values from ``option_create_edit_wizard`` to ``option_m2o_dialog``
18+
if not column_exists(cr, "m2x_create_edit_option", "option_m2o_dialog"):
19+
create_column(cr, "m2x_create_edit_option", "option_m2o_dialog", "varchar")
20+
cr.execute(
21+
"""
22+
UPDATE m2x_create_edit_option
23+
SET option_m2o_dialog =
24+
CASE
25+
WHEN not option_create_edit_wizard THEN 'set_false'
26+
ELSE 'null'
27+
END
28+
"""
29+
)
30+
31+
# Pre-create and pre-fill these columns for perf reasons (might take a while to
32+
# let Odoo do it via the ORM for huge DBs)
33+
prepare_column_can_have_options(cr)
34+
prepare_column_comodel_id(cr)
35+
36+
# Replaced by SQL constraint ``m2x_create_edit_option_field_uniqueness``
37+
drop_constraint(
38+
cr,
39+
tablename="m2x_create_edit_option",
40+
constraintname="m2x_create_edit_option_model_field_uniqueness",
41+
)
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
# Copyright 2021 Camptocamp SA
2-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3-
41
from . import ir_model
2+
from . import ir_model_fields
53
from . import ir_ui_view
64
from . import m2x_create_edit_option
Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,68 @@
11
# Copyright 2021 Camptocamp SA
22
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
33

4-
from odoo import api, fields, models
4+
from odoo import fields, models
55

66

77
class IrModel(models.Model):
88
_inherit = "ir.model"
99

10-
m2x_create_edit_option_ids = fields.One2many(
10+
m2x_option_ids = fields.One2many(
1111
"m2x.create.edit.option",
1212
"model_id",
1313
)
14+
m2x_comodels_option_ids = fields.One2many(
15+
"m2x.create.edit.option",
16+
"comodel_id",
17+
)
18+
comodel_field_ids = fields.One2many("ir.model.fields", "comodel_id")
19+
20+
def button_empty_m2x_options(self):
21+
for ir_model in self:
22+
ir_model._empty_m2x_options(own=True)
1423

15-
def button_empty(self):
24+
def button_fill_m2x_options(self):
1625
for ir_model in self:
17-
ir_model._empty_m2x_create_edit_option()
26+
ir_model._fill_m2x_options(own=True)
1827

19-
def button_fill(self):
28+
def button_empty_m2x_comodels_options(self):
2029
for ir_model in self:
21-
ir_model._fill_m2x_create_edit_option()
30+
ir_model._empty_m2x_options(comodels=True)
2231

23-
def _empty_m2x_create_edit_option(self):
24-
"""Removes every option for model ``self``"""
32+
def button_fill_m2x_comodels_options(self):
33+
for ir_model in self:
34+
ir_model._fill_m2x_options(comodels=True)
35+
36+
def _empty_m2x_options(self, own=False, comodels=False):
37+
"""Removes every option for model ``self``'s fields
38+
39+
:param bool own: if True, deletes options for model's fields
40+
:param bool comodels: if True, deletes options for fields where ``self`` is comodel
41+
"""
2542
self.ensure_one()
26-
self.m2x_create_edit_option_ids.unlink()
43+
to_delete = self.env["m2x.create.edit.option"]
44+
if own:
45+
to_delete += self.m2x_option_ids
46+
if comodels:
47+
to_delete += self.m2x_comodels_option_ids
48+
if to_delete:
49+
to_delete.unlink()
50+
51+
def _fill_m2x_options(self, own=False, comodels=False):
52+
"""Adds every missing field option for model ``self`` (with default values)
2753
28-
def _fill_m2x_create_edit_option(self):
29-
"""Adds every missing field option for model ``self``"""
54+
:param bool own: if True, creates options for model's fields
55+
:param bool comodels: if True, creates options for fields where ``self`` is comodel
56+
"""
3057
self.ensure_one()
31-
existing = self.m2x_create_edit_option_ids.mapped("field_id")
32-
valid = self.field_id.filtered(lambda f: f.ttype in ("many2many", "many2one"))
33-
vals = [(0, 0, {"field_id": f.id}) for f in valid - existing]
34-
self.write({"m2x_create_edit_option_ids": vals})
35-
36-
37-
class IrModelFields(models.Model):
38-
_inherit = "ir.model.fields"
39-
40-
@api.model
41-
def name_search(self, name="", args=None, operator="ilike", limit=100):
42-
res = super().name_search(name, args, operator, limit)
43-
if not (name and self.env.context.get("search_by_technical_name")):
44-
return res
45-
domain = list(args or []) + [("name", operator, name)]
46-
new_fids = self.search(domain, limit=limit).ids
47-
for fid in [x[0] for x in res]:
48-
if fid not in new_fids:
49-
new_fids.append(fid)
50-
if limit and limit > 0:
51-
new_fids = new_fids[:limit]
52-
return self.browse(new_fids).sudo().name_get()
58+
todo = set()
59+
if own:
60+
exist = self.m2x_option_ids.mapped("field_id")
61+
valid = self.field_id.filtered("can_have_options")
62+
todo.update((valid - exist).ids)
63+
if comodels:
64+
exist = self.m2x_comodels_option_ids.mapped("field_id")
65+
valid = self.comodel_field_ids.filtered("can_have_options")
66+
todo.update((valid - exist).ids)
67+
if todo:
68+
self.env["m2x.create.edit.option"].create([{"field_id": i} for i in todo])

0 commit comments

Comments
 (0)