diff --git a/addons/board/controllers/main.py b/addons/board/controllers/main.py index 303f5b0908e..e3871b6f822 100644 --- a/addons/board/controllers/main.py +++ b/addons/board/controllers/main.py @@ -16,10 +16,9 @@ class Board(Controller): if action and action['res_model'] == 'board.board' and action['views'][0][1] == 'form' and action_id: # Maybe should check the content instead of model board.board ? view_id = action['views'][0][0] - board = request.env['board.board'].fields_view_get(view_id, 'form') - if board and 'arch' in board: - xml = ElementTree.fromstring(board['arch']) - column = xml.find('./board/column') + board_arch, _view = request.env['board.board']._get_view(view_id, 'form') + if board_arch: + column = board_arch.find('./board/column') if column is not None: new_action = ElementTree.Element('action', { 'name': str(action_id), @@ -29,7 +28,7 @@ class Board(Controller): 'domain': str(domain) }) column.insert(0, new_action) - arch = ElementTree.tostring(xml, encoding='unicode') + arch = ElementTree.tostring(board_arch, encoding='unicode') request.env['ir.ui.view.custom'].create({ 'user_id': request.session.uid, 'ref_id': view_id, diff --git a/addons/board/models/board.py b/addons/board/models/board.py index 3d7a47f7574..9dc2978fd8e 100644 --- a/addons/board/models/board.py +++ b/addons/board/models/board.py @@ -20,13 +20,13 @@ class Board(models.AbstractModel): return self @api.model - def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): + def get_view(self, view_id=None, view_type='form', **options): """ Overrides orm field_view_get. @return: Dictionary of Fields, arch and toolbar. """ - res = super(Board, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) + res = super().get_view(view_id, view_type, **options) custom_view = self.env['ir.ui.view.custom'].search([('user_id', '=', self.env.uid), ('ref_id', '=', view_id)], limit=1) if custom_view: diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index 2a4f460a4b5..d8a0802fad2 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -862,16 +862,16 @@ class Lead(models.Model): return super(Lead, self.with_context(context)).copy(default=default) @api.model - def _fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): + def _get_view(self, view_id=None, view_type='form', **options): if self._context.get('opportunity_id'): opportunity = self.browse(self._context['opportunity_id']) action = opportunity.get_formview_action() if action.get('views') and any(view_id for view_id in action['views'] if view_id[1] == view_type): view_id = next(view_id[0] for view_id in action['views'] if view_id[1] == view_type) - res = super(Lead, self)._fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) + arch, view = super()._get_view(view_id, view_type, **options) if view_type == 'form': - res['arch'] = self._fields_view_get_address(res['arch']) - return res + arch = self._view_get_address(arch) + return arch, view @api.model def _read_group_stage_ids(self, stages, domain, order): diff --git a/addons/google_spreadsheet/models/google_drive.py b/addons/google_spreadsheet/models/google_drive.py index 10e04bbb050..c64e8e6b5f2 100644 --- a/addons/google_spreadsheet/models/google_drive.py +++ b/addons/google_spreadsheet/models/google_drive.py @@ -26,8 +26,8 @@ class GoogleDrive(models.Model): def write_config_formula(self, attachment_id, spreadsheet_key, model, domain, groupbys, view_id): access_token = self.get_access_token(scope='https://www.googleapis.com/auth/spreadsheets') - fields = self.env[model].fields_view_get(view_id=view_id, view_type='tree') - doc = etree.XML(fields.get('arch')) + arch, _view = self.env[model]._get_view(view_id, 'tree') + doc = arch display_fields = [] for node in doc.xpath("//field"): if node.get('modifiers'): diff --git a/addons/hr/models/hr_employee.py b/addons/hr/models/hr_employee.py index fe14ec9b5db..cb58ab6f98c 100644 --- a/addons/hr/models/hr_employee.py +++ b/addons/hr/models/hr_employee.py @@ -217,10 +217,10 @@ class HrEmployeePrivate(models.Model): return self.env['hr.employee.public'].browse(self.ids).read(fields, load=load) @api.model - def load_views(self, views, options=None): + def get_view(self, view_id=None, view_type='form', **options): if self.check_access_rights('read', raise_exception=False): - return super(HrEmployeePrivate, self).load_views(views, options=options) - return self.env['hr.employee.public'].load_views(views, options=options) + return super().get_view(view_id, view_type, **options) + return self.env['hr.employee.public'].get_view(view_id, view_type, **options) @api.model def _search(self, args, offset=0, limit=None, order=None, count=False, access_rights_uid=None): diff --git a/addons/hr/models/res_users.py b/addons/hr/models/res_users.py index 8123aa54bec..9a51fbed6ce 100644 --- a/addons/hr/models/res_users.py +++ b/addons/hr/models/res_users.py @@ -169,7 +169,7 @@ class User(models.Model): return super().SELF_WRITEABLE_FIELDS + HR_WRITABLE_FIELDS @api.model - def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): + def get_view(self, view_id=None, view_type='form', **options): # When the front-end loads the views it gets the list of available fields # for the user (according to its access rights). Later, when the front-end wants to # populate the view with data, it only asks to read those available fields. @@ -182,11 +182,11 @@ class User(models.Model): original_user = self.env.user if profile_view and view_id == profile_view.id: self = self.with_user(SUPERUSER_ID) - result = super(User, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) + result = super(User, self).get_view(view_id, view_type, **options) # Due to using the SUPERUSER the result will contain action that the user may not have access too # here we filter out actions that requires special implicit rights to avoid having unusable actions # in the dropdown menu. - if toolbar and self.env.user != original_user: + if options.get('toolbar') and self.env.user != original_user: self = self.with_user(original_user.id) if not self.user_has_groups("base.group_erp_manager"): change_password_action = self.env.ref("base.change_password_wizard_action") diff --git a/addons/hr/tests/test_self_user_access.py b/addons/hr/tests/test_self_user_access.py index 539476e48b0..36213ff912a 100644 --- a/addons/hr/tests/test_self_user_access.py +++ b/addons/hr/tests/test_self_user_access.py @@ -3,6 +3,7 @@ from collections import OrderedDict from itertools import chain +from lxml import etree from odoo.addons.hr.tests.common import TestHrCommon from odoo.tests import new_test_user, tagged, Form @@ -20,8 +21,8 @@ class TestSelfAccessProfile(TestHrCommon): 'user_id': james.id, }) view = self.env.ref('hr.res_users_view_form_profile') - view_infos = james.fields_view_get(view_id=view.id) - fields = view_infos['fields'].keys() + view_infos = james.get_view(view.id) + fields = [el.get('name') for el in etree.fromstring(view_infos['arch']).xpath('//field[not(ancestor::field)]')] james.read(fields) def test_readonly_fields(self): @@ -35,12 +36,12 @@ class TestSelfAccessProfile(TestHrCommon): }) view = self.env.ref('hr.res_users_view_form_profile') - view_infos = james.fields_view_get(view_id=view.id) - + fields = james._fields + view_infos = james.get_view(view.id) employee_related_fields = { - field_name - for field_name, field_attrs in view_infos['fields'].items() - if field_attrs.get('related', (None,))[0] == 'employee_id' + el.get('name') + for el in etree.fromstring(view_infos['arch']).xpath('//field[not(ancestor::field)]') + if fields[el.get('name')].related and fields[el.get('name')].related.split('.')[0] == 'employee_id' } form = Form(james, view=view) @@ -65,16 +66,16 @@ class TestSelfAccessProfile(TestHrCommon): all_groups |= self.env.ref(xml_id.strip()) user_all_groups = new_test_user(self.env, groups='base.group_user', login='hel', name='God') user_all_groups.write({'groups_id': [(4, group.id, False) for group in all_groups]}) - view_infos = self.env['res.users'].with_user(user_all_groups).fields_view_get(view_id=view.id) - full_fields = view_infos['fields'] + view_infos = self.env['res.users'].with_user(user_all_groups).get_view(view.id) + full_fields = [el.get('name') for el in etree.fromstring(view_infos['arch']).xpath('//field[not(ancestor::field)]')] # Now check the view for a simple user user = new_test_user(self.env, login='gro', name='Grouillot') - view_infos = self.env['res.users'].with_user(user).fields_view_get(view_id=view.id) - fields = view_infos['fields'] + view_infos = self.env['res.users'].with_user(user).get_view(view.id) + fields = [el.get('name') for el in etree.fromstring(view_infos['arch']).xpath('//field[not(ancestor::field)]')] # Compare both - self.assertEqual(full_fields.keys(), fields.keys(), "View fields should not depend on user's groups") + self.assertEqual(full_fields, fields, "View fields should not depend on user's groups") def test_access_my_profile_toolbar(self): """ A simple user shouldn't have the possibilities to see the 'Change Password' action""" @@ -85,7 +86,7 @@ class TestSelfAccessProfile(TestHrCommon): 'user_id': james.id, }) view = self.env.ref('hr.res_users_view_form_profile') - available_actions = james.fields_view_get(view_id=view.id, toolbar=True)['toolbar']['action'] + available_actions = james.get_view(view.id, toolbar=True)['toolbar']['action'] change_password_action = self.env.ref("base.change_password_wizard_action") self.assertFalse(any(x['id'] == change_password_action.id for x in available_actions)) @@ -98,7 +99,7 @@ class TestSelfAccessProfile(TestHrCommon): 'user_id': john.id, }) view = self.env.ref('hr.res_users_view_form_profile') - available_actions = john.fields_view_get(view_id=view.id, toolbar=True)['toolbar']['action'] + available_actions = john.get_view(view.id, toolbar=True)['toolbar']['action'] self.assertTrue(any(x['id'] == change_password_action.id for x in available_actions)) diff --git a/addons/hr_recruitment/models/hr_recruitment.py b/addons/hr_recruitment/models/hr_recruitment.py index de37dbbd150..0b2c0379a4a 100644 --- a/addons/hr_recruitment/models/hr_recruitment.py +++ b/addons/hr_recruitment/models/hr_recruitment.py @@ -52,14 +52,12 @@ class RecruitmentSource(models.Model): source.alias_id = self.env['mail.alias'].create(vals) @api.model - def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): - res = super().fields_view_get(view_id, view_type, toolbar, submenu) + def _get_view(self, view_id=None, view_type='form', **options): + arch, view = super()._get_view(view_id, view_type, **options) if view_type == 'tree' and not bool(self.env["ir.config_parameter"].sudo().get_param("mail.catchall.domain")): - arch = etree.fromstring(res['arch']) email = arch.xpath("//field[@name='email']")[0] email.getparent().remove(email) - res['arch'] = etree.tostring(arch, encoding='unicode') - return res + return arch, view class RecruitmentStage(models.Model): _name = "hr.recruitment.stage" @@ -437,10 +435,10 @@ class Applicant(models.Model): return nocontent_body % nocontent_values @api.model - def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): + def get_view(self, view_id=None, view_type='form', **options): if view_type == 'form' and self.user_has_groups('hr_recruitment.group_hr_recruitment_interviewer'): view_id = self.env.ref('hr_recruitment.hr_applicant_view_form_interviewer').id - return super().fields_view_get(view_id, view_type, toolbar, submenu) + return super().get_view(view_id, view_type, **options) def _notify_compute_recipients(self, message, msg_vals): """ diff --git a/addons/hr_timesheet/models/hr_timesheet.py b/addons/hr_timesheet/models/hr_timesheet.py index 8986c7f245f..197f4bd39b7 100644 --- a/addons/hr_timesheet/models/hr_timesheet.py +++ b/addons/hr_timesheet/models/hr_timesheet.py @@ -157,26 +157,26 @@ class AccountAnalyticLine(models.Model): return result @api.model - def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): + def _get_view(self, view_id=None, view_type='form', **options): """ Set the correct label for `unit_amount`, depending on company UoM """ - result = super(AccountAnalyticLine, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) - result['arch'] = self._apply_timesheet_label(result['arch'], view_type=view_type) - return result + arch, view = super()._get_view(view_id, view_type, **options) + arch = self._apply_timesheet_label(arch, view_type=view_type) + return arch, view @api.model - def _apply_timesheet_label(self, view_arch, view_type='form'): - doc = etree.XML(view_arch) + def _apply_timesheet_label(self, view_node, view_type='form'): + doc = view_node encoding_uom = self.env.company.timesheet_encode_uom_id # Here, we select only the unit_amount field having no string set to give priority to # custom inheretied view stored in database. Even if normally, no xpath can be done on # 'string' attribute. for node in doc.xpath("//field[@name='unit_amount'][@widget='timesheet_uom'][not(@string)]"): node.set('string', _('%s Spent') % (re.sub(r'[\(\)]', '', encoding_uom.name or ''))) - return etree.tostring(doc, encoding='unicode') + return doc @api.model - def _apply_time_label(self, view_arch, related_model): - doc = etree.XML(view_arch) + def _apply_time_label(self, view_node, related_model): + doc = view_node Model = self.env[related_model] # Just fetch the name of the uom in `timesheet_encode_uom_id` of the current company encoding_uom_name = self.env.company.timesheet_encode_uom_id.with_context(prefetch_fields=False).sudo().name @@ -184,7 +184,7 @@ class AccountAnalyticLine(models.Model): name_with_uom = re.sub(_('Hours') + "|Hours", encoding_uom_name or '', Model._fields[node.get('name')]._description_string(self.env), flags=re.IGNORECASE) node.set('string', name_with_uom) - return etree.tostring(doc, encoding='unicode') + return doc def _timesheet_get_portal_domain(self): if self.env.user.has_group('hr_timesheet.group_hr_timesheet_user'): diff --git a/addons/hr_timesheet/models/project.py b/addons/hr_timesheet/models/project.py index edab491a5d1..ebb9037f2ee 100644 --- a/addons/hr_timesheet/models/project.py +++ b/addons/hr_timesheet/models/project.py @@ -81,11 +81,11 @@ class Project(models.Model): return [('id', operator_new, (query, ()))] @api.model - def _fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): - result = super()._fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) + def _get_view(self, view_id=None, view_type='form', **options): + arch, view = super()._get_view(view_id, view_type, **options) if view_type in ['tree', 'form'] and self.env.company.timesheet_encode_uom_id == self.env.ref('uom.product_uom_day'): - result['arch'] = self.env['account.analytic.line']._apply_time_label(result['arch'], related_model=self._name) - return result + arch = self.env['account.analytic.line']._apply_time_label(arch, related_model=self._name) + return arch, view @api.depends('allow_timesheets', 'timesheet_ids') def _compute_remaining_hours(self): @@ -368,16 +368,16 @@ class Task(models.Model): return super().name_get() @api.model - def _fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): + def _get_view(self, view_id=None, view_type='form', **options): """ Set the correct label for `unit_amount`, depending on company UoM """ - result = super(Task, self)._fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) + arch, view = super()._get_view(view_id, view_type, **options) # Use of sudo as the portal user doesn't have access to uom - result['arch'] = self.env['account.analytic.line'].sudo()._apply_timesheet_label(result['arch']) + arch = self.env['account.analytic.line'].sudo()._apply_timesheet_label(arch) if view_type in ['tree', 'pivot', 'graph'] and self.env.company.timesheet_encode_uom_id == self.env.ref('uom.product_uom_day'): - result['arch'] = self.env['account.analytic.line']._apply_time_label(result['arch'], related_model=self._name) + arch = self.env['account.analytic.line']._apply_time_label(arch, related_model=self._name) - return result + return arch, view @api.ondelete(at_uninstall=False) def _unlink_except_contains_entries(self): diff --git a/addons/hr_timesheet/report/project_report.py b/addons/hr_timesheet/report/project_report.py index be4238b46db..fc40365952a 100644 --- a/addons/hr_timesheet/report/project_report.py +++ b/addons/hr_timesheet/report/project_report.py @@ -33,8 +33,8 @@ class ReportProjectTaskUser(models.Model): return super(ReportProjectTaskUser, self)._group_by() + group_by_append @api.model - def _fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): - result = super(ReportProjectTaskUser, self)._fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) + def _get_view(self, view_id=None, view_type='form', **options): + arch, view = super()._get_view(view_id, view_type, **options) if view_type in ['pivot', 'graph'] and self.env.company.timesheet_encode_uom_id == self.env.ref('uom.product_uom_day'): - result['arch'] = self.env['account.analytic.line']._apply_time_label(result['arch'], related_model=self._name) - return result + arch = self.env['account.analytic.line']._apply_time_label(arch, related_model=self._name) + return arch, view diff --git a/addons/mail/models/ir_ui_view.py b/addons/mail/models/ir_ui_view.py index 90fdea597b9..fb2a5552eaf 100644 --- a/addons/mail/models/ir_ui_view.py +++ b/addons/mail/models/ir_ui_view.py @@ -6,3 +6,10 @@ class View(models.Model): _inherit = 'ir.ui.view' type = fields.Selection(selection_add=[('activity', 'Activity')]) + + def _postprocess_tag_field(self, node, name_manager, node_info): + if node.xpath("ancestor::div[hasclass('oe_chatter')]"): + # Pass the postprocessing of the mail thread fields + # The web client makes it completely custom, and this is therefore pointless. + return + return super()._postprocess_tag_field(node, name_manager, node_info) diff --git a/addons/membership/models/product.py b/addons/membership/models/product.py index 6107ad3b3a0..b766df1240f 100644 --- a/addons/membership/models/product.py +++ b/addons/membership/models/product.py @@ -18,10 +18,10 @@ class Product(models.Model): ] @api.model - def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): + def get_view(self, view_id=None, view_type='form', **options): if self._context.get('product') == 'membership_product': if view_type == 'form': view_id = self.env.ref('membership.membership_products_form').id else: view_id = self.env.ref('membership.membership_products_tree').id - return super(Product, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) + return super().get_view(view_id, view_type, **options) diff --git a/addons/project/tests/test_project_sharing_portal_access.py b/addons/project/tests/test_project_sharing_portal_access.py index f7cfed90e29..e3cf97fc017 100644 --- a/addons/project/tests/test_project_sharing_portal_access.py +++ b/addons/project/tests/test_project_sharing_portal_access.py @@ -2,6 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from collections import OrderedDict +from lxml import etree from odoo import Command from odoo.exceptions import AccessError from odoo.tests import tagged @@ -49,10 +50,11 @@ class TestProjectSharingPortalAccess(TestProjectSharingCommon): def test_readonly_fields(self): """ The fields are not writeable should not be editable by the portal user. """ - view_infos = self.task_portal.fields_view_get(view_id=self.env.ref(self.project_sharing_form_view_xml_id).id) + view_infos = self.task_portal.get_view(self.env.ref(self.project_sharing_form_view_xml_id).id) + fields = [el.get('name') for el in etree.fromstring(view_infos['arch']).xpath('//field[not(ancestor::field)]')] project_task_fields = { field_name - for field_name, field_attrs in view_infos['fields'].items() + for field_name in fields if field_name not in self.write_protected_fields_task } with self.get_project_sharing_form_view(self.task_portal, self.user_portal) as form: diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index ee051576aba..bc78ba3efe5 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -428,35 +428,33 @@ class Product(models.Model): return res @api.model - def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): - res = super(Product, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) + def fields_get(self, allfields=None, attributes=None): + res = super().fields_get(allfields, attributes) if self._context.get('location') and isinstance(self._context['location'], int): location = self.env['stock.location'].browse(self._context['location']) - fields = res.get('fields') - if fields: - if location.usage == 'supplier': - if fields.get('virtual_available'): - res['fields']['virtual_available']['string'] = _('Future Receipts') - if fields.get('qty_available'): - res['fields']['qty_available']['string'] = _('Received Qty') - elif location.usage == 'internal': - if fields.get('virtual_available'): - res['fields']['virtual_available']['string'] = _('Forecasted Quantity') - elif location.usage == 'customer': - if fields.get('virtual_available'): - res['fields']['virtual_available']['string'] = _('Future Deliveries') - if fields.get('qty_available'): - res['fields']['qty_available']['string'] = _('Delivered Qty') - elif location.usage == 'inventory': - if fields.get('virtual_available'): - res['fields']['virtual_available']['string'] = _('Future P&L') - if fields.get('qty_available'): - res['fields']['qty_available']['string'] = _('P&L Qty') - elif location.usage == 'production': - if fields.get('virtual_available'): - res['fields']['virtual_available']['string'] = _('Future Productions') - if fields.get('qty_available'): - res['fields']['qty_available']['string'] = _('Produced Qty') + if location.usage == 'supplier': + if res.get('virtual_available'): + res['virtual_available']['string'] = _('Future Receipts') + if res.get('qty_available'): + res['qty_available']['string'] = _('Received Qty') + elif location.usage == 'internal': + if res.get('virtual_available'): + res['virtual_available']['string'] = _('Forecasted Quantity') + elif location.usage == 'customer': + if res.get('virtual_available'): + res['virtual_available']['string'] = _('Future Deliveries') + if res.get('qty_available'): + res['qty_available']['string'] = _('Delivered Qty') + elif location.usage == 'inventory': + if res.get('virtual_available'): + res['virtual_available']['string'] = _('Future P&L') + if res.get('qty_available'): + res['qty_available']['string'] = _('P&L Qty') + elif location.usage == 'production': + if res.get('virtual_available'): + res['virtual_available']['string'] = _('Future Productions') + if res.get('qty_available'): + res['qty_available']['string'] = _('Produced Qty') return res def action_view_orderpoints(self): diff --git a/addons/web/models/models.py b/addons/web/models/models.py index d42e0f4c452..318768a1d91 100644 --- a/addons/web/models/models.py +++ b/addons/web/models/models.py @@ -237,15 +237,15 @@ class Base(models.AbstractModel): }) @api.model - def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): - r = super().fields_view_get(view_id, view_type, toolbar, submenu) + def _get_view(self, view_id=None, view_type='form', **options): + arch, view = super()._get_view(view_id, view_type, **options) # avoid leaking the raw (un-rendered) template, also avoids bloating # the response payload for no reason. Only send the root node, # to send attributes such as `js_class`. - if r['type'] == 'qweb': - root = etree.fromstring(r['arch']) - r['arch'] = etree.tostring(etree.Element('qweb', root.attrib)) - return r + if view_type == 'qweb': + root = arch + arch = etree.Element('qweb', root.attrib) + return arch, view @api.model def _search_panel_field_image(self, field_name, **kwargs): diff --git a/addons/web/static/src/legacy/js/services/data_manager.js b/addons/web/static/src/legacy/js/services/data_manager.js index 0efcc2ecf2d..2a8fc5b425b 100644 --- a/addons/web/static/src/legacy/js/services/data_manager.js +++ b/addons/web/static/src/legacy/js/services/data_manager.js @@ -89,6 +89,9 @@ return core.Class.extend({ if (shouldLoadViews) { // Views info should be loaded options.load_filters = shouldLoadFilters; + if (config.device.isMobile) { + options.mobile = config.device.isMobile; + } this._cache.views[viewsKey] = rpc.query({ args: [], kwargs: { context, options, views: views_descr }, diff --git a/addons/web/static/src/views/view_service.js b/addons/web/static/src/views/view_service.js index cf8a0668551..423bc8b317c 100644 --- a/addons/web/static/src/views/view_service.js +++ b/addons/web/static/src/views/view_service.js @@ -1,6 +1,7 @@ /** @odoo-module **/ import { registry } from "@web/core/registry"; +import { device } from 'web.config'; /** * @typedef {Object} IrFilter @@ -65,14 +66,18 @@ export const viewService = { async function loadViews(params, options) { const key = JSON.stringify([params.resModel, params.views, params.context, options]); if (!cache[key]) { + var load_views_options = { + action_id: options.actionId || false, + load_filters: options.loadIrFilters || false, + toolbar: options.loadActionMenus || false, + } + if (device.isMobile){ + load_views_options.mobile = device.isMobile; + } cache[key] = orm .call(params.resModel, "load_views", [], { views: params.views, - options: { - action_id: options.actionId || false, - load_filters: options.loadIrFilters || false, - toolbar: options.loadActionMenus || false, - }, + options: load_views_options, context: params.context, }) .then((result) => { diff --git a/addons/web_editor/models/ir_qweb_fields.py b/addons/web_editor/models/ir_qweb_fields.py index d5a6b295c76..58e4d0e49a6 100644 --- a/addons/web_editor/models/ir_qweb_fields.py +++ b/addons/web_editor/models/ir_qweb_fields.py @@ -76,7 +76,7 @@ class IrQWeb(models.AbstractModel): key = el.attrib.pop('t-snippet') el.set('t-call', key) el.set('t-options', f"{{'snippet-key': {key!r}}}") - view = self.env['ir.ui.view']._get_view(key).sudo() + view = self.env['ir.ui.view']._get(key).sudo() name = view.name thumbnail = el.attrib.pop('t-thumbnail', "oe-thumbnail") div = '