Skip to content

Commit

Permalink
[REF] views_migration_17: refactor patch
Browse files Browse the repository at this point in the history
  • Loading branch information
jjscarafia authored and bruno-zanotti committed Nov 21, 2023
1 parent 5f6e28d commit e2eb1f8
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 131 deletions.
53 changes: 53 additions & 0 deletions addons/views_migration_17/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. image:: https://img.shields.io/badge/python-3.6-blue.svg
:alt: Python support: 3.6
.. image:: https://app.travis-ci.com/OCA/odoo-module-migrator.svg?branch=master
:target: https://app.travis-ci.com/OCA/odoo-module-migrator

====================
Views-migration-v17
====================

``views-migration-v17`` is a odoo server mode module that allows you to automatically migrate the views of a Odoo module versión <= v16 to v17 .

For example:

.. code-block:: xml
<field name="test_field_1" attrs="{'invisible': [('active', '=', True)]}"/>
<field name="test_field_2" attrs="{'invisible': [('zip', '!=', 123)]}"/>
<field name="test_field_3" attrs="{'readonly': [('zip', '!=', False)]}"/>
To:

.. code-block:: xml
<field name="test_field_1" invisible="active"/>
<field name="test_field_2" invisible="zip != 123"/>
<field name="test_field_3" readonly="zip"/>
Usage
=====

.. code-block:: shell
odoo -d [database_name] -i [module_name] --load=base,web,views_migration_17
Credits
=======

Authors
-------
* ADHOC SA


Contributors
------------
* `ADHOC SA <https://www.adhoc.com.ar>`_:

* Juan José Scarafía
* Bruno Zanotti
12 changes: 3 additions & 9 deletions addons/views_migration_17/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from . import patch_xml_import # patch xml_import so that view is fixed

# patch vies so that they don't break
from odoo.addons.base.models.ir_ui_view import View
import logging
_logger = logging.getLogger(__name__)


_original_check_xml = View._check_xml
Expand All @@ -11,14 +11,8 @@ def _check_xml(self):
# TODO we should check exeception is due to the expected error
try:
_original_check_xml
except Exception as e:
except Exception:
pass


View._check_xml = _check_xml


# patch xml_import so that view is fixed
from odoo.tools.convert import xml_import
from .convert import _tag_record
xml_import._tag_record = _tag_record
Original file line number Diff line number Diff line change
Expand Up @@ -9,138 +9,26 @@
from odoo.tools import mute_logger
from odoo.tools.misc import file_open
from odoo.tools.translate import _
from odoo.tools.convert import _eval_xml, nodeattr2bool, _get_idref
from odoo.tools import config
from odoo.tools.template_inheritance import locate_node
from odoo.exceptions import ValidationError

_logger = logging.getLogger(__name__)


def _tag_record(self, rec, extra_vals=None):
rec_model = rec.get("model")
env = self.get_env(rec)
rec_id = rec.get("id", '')

model = env[rec_model]

if self.xml_filename and rec_id:
model = model.with_context(
install_module=self.module,
install_filename=self.xml_filename,
install_xmlid=rec_id,
)

self._test_xml_id(rec_id)
xid = self.make_xml_id(rec_id)

# in update mode, the record won't be updated if the data node explicitly
# opt-out using @noupdate="1". A second check will be performed in
# model._load_records() using the record's ir.model.data `noupdate` field.
if self.noupdate and self.mode != 'init':
# check if the xml record has no id, skip
if not rec_id:
return None

record = env['ir.model.data']._load_xmlid(xid)
if record:
# if the resource already exists, don't update it but store
# its database id (can be useful)
self.idref[rec_id] = record.id
return None
elif not nodeattr2bool(rec, 'forcecreate', True):
# if it doesn't exist and we shouldn't create it, skip it
return None
# else create it normally

if xid and xid.partition('.')[0] != self.module:
# updating a record created by another module
record = self.env['ir.model.data']._load_xmlid(xid)
if not record:
if self.noupdate and not nodeattr2bool(rec, 'forcecreate', True):
# if it doesn't exist and we shouldn't create it, skip it
return None
raise Exception("Cannot update missing record %r" % xid)
from odoo.tools.convert import xml_import
original_tag_record = xml_import._tag_record


def new_tag_record(self, rec, extra_vals=None):

rec_model = rec.get("model")
if rec_model == 'ir.ui.view':
_convert_ir_ui_view_modifiers(self, rec, extra_vals=extra_vals)
return original_tag_record(self, rec, extra_vals=extra_vals)


xml_import._tag_record = new_tag_record

res = {}
sub_records = []
for field in rec.findall('./field'):
#TODO: most of this code is duplicated above (in _eval_xml)...
f_name = field.get("name")
f_ref = field.get("ref")
f_search = field.get("search")
f_model = field.get("model")
if not f_model and f_name in model._fields:
f_model = model._fields[f_name].comodel_name
f_use = field.get("use",'') or 'id'
f_val = False

if f_search:
idref2 = _get_idref(self, env, f_model, self.idref)
q = safe_eval(f_search, idref2)
assert f_model, 'Define an attribute model="..." in your .XML file!'
# browse the objects searched
s = env[f_model].search(q)
# column definitions of the "local" object
_fields = env[rec_model]._fields
# if the current field is many2many
if (f_name in _fields) and _fields[f_name].type == 'many2many':
f_val = [odoo.Command.set([x[f_use] for x in s])]
elif len(s):
# otherwise (we are probably in a many2one field),
# take the first element of the search
f_val = s[0][f_use]
elif f_ref:
if f_name in model._fields and model._fields[f_name].type == 'reference':
val = self.model_id_get(f_ref)
f_val = val[0] + ',' + str(val[1])
else:
f_val = self.id_get(f_ref, raise_if_not_found=nodeattr2bool(rec, 'forcecreate', True))
if not f_val:
_logger.warning("Skipping creation of %r because %s=%r could not be resolved", xid, f_name, f_ref)
return None
else:
f_val = _eval_xml(self, field, env)
if f_name in model._fields:
field_type = model._fields[f_name].type
if field_type == 'many2one':
f_val = int(f_val) if f_val else False
elif field_type == 'integer':
f_val = int(f_val)
elif field_type in ('float', 'monetary'):
f_val = float(f_val)
elif field_type == 'boolean' and isinstance(f_val, str):
f_val = str2bool(f_val)
elif field_type == 'one2many':
for child in field.findall('./record'):
sub_records.append((child, model._fields[f_name].inverse_name))
if isinstance(f_val, str):
# We do not want to write on the field since we will write
# on the childrens' parents later
continue
elif field_type == 'html':
if field.get('type') == 'xml':
_logger.warning('HTML field %r is declared as `type="xml"`', f_name)
res[f_name] = f_val
if extra_vals:
res.update(extra_vals)
if 'sequence' not in res and 'sequence' in model._fields:
sequence = self.next_sequence()
if sequence:
res['sequence'] = sequence

data = dict(xml_id=xid, values=res, noupdate=self.noupdate)
record = model._load_records([data], self.mode == 'update')
if rec_id:
self.idref[rec_id] = record.id
if config.get('import_partial'):
env.cr.commit()
for child_rec, inverse_name in sub_records:
self._tag_record(child_rec, extra_vals={inverse_name: record.id})
return rec_model, record.id

def _convert_ir_ui_view_modifiers(self, record_node, extra_vals=None):
rec_id = record_node.get("id", '')
Expand Down

0 comments on commit e2eb1f8

Please sign in to comment.