Example #1
0
 def definition(self, model, language):
     encoder = PYSONEncoder()
     definition = super().definition(model, language)
     definition['datetime_field'] = self.datetime_field
     definition['search_context'] = encoder.encode(self.search_context)
     definition['search_order'] = encoder.encode(self.search_order)
     return definition
Example #2
0
    def definition(self, model, language):
        pool = Pool()
        Translation = pool.get('ir.translation')
        encoder = PYSONEncoder()
        definition = {
            'context': encoder.encode(self.context),
            'loading': self.loading,
            'name': self.name,
            'on_change': list(self.on_change),
            'on_change_with': list(self.on_change_with),
            'readonly': self.readonly,
            'required': self.required,
            'states': encoder.encode(self.states),
            'type': self._type,
            'domain': encoder.encode(self.domain),
            'searchable': hasattr(model, 'search'),
            'sortable': hasattr(model, 'search'),
        }

        # Add id to on_change's if they are not cached
        # Not having the id increase the efficiency of the cache
        for method in ['on_change', 'on_change_with']:
            changes = definition[method]
            if changes:
                method_name = method + '_' + self.name
                if not model.__rpc__[method_name].cache:
                    changes.append('id')

        name = '%s,%s' % (model.__name__, self.name)
        for attr, ttype in [('string', 'field'), ('help', 'help')]:
            definition[attr] = ''
            for source in getattr(self, attr):
                definition[attr] += (Translation.get_source(
                    name, ttype, language, source) or source)
        return definition
Example #3
0
 def do_open_(self, action):
     encoder = PYSONEncoder()
     action['pyson_context'] = encoder.encode(self.get_context())
     action['pyson_search_value'] = encoder.encode(self.get_search_value())
     action['pyson_domain'] = encoder.encode(self.get_domain())
     action['name'] += '(' + self.record.rec_name + ')'
     return action, {}
Example #4
0
    def definition(self, model, language):
        pool = Pool()
        Translation = pool.get('ir.translation')
        encoder = PYSONEncoder()
        definition = {
            'context': encoder.encode(self.context),
            'loading': self.loading,
            'name': self.name,
            'depends': self.depends,
            'on_change': list(self.on_change),
            'on_change_with': list(self.on_change_with),
            'readonly': self.readonly,
            'required': self.required,
            'states': encoder.encode(self.states),
            'type': self._type,
            'domain': encoder.encode(self.domain),
            'searchable': hasattr(model, 'search'),
            'sortable': hasattr(model, 'search'),
            }

        # Add id to on_change's if they are not cached
        # Not having the id increase the efficiency of the cache
        for method in ['on_change', 'on_change_with']:
            changes = definition[method]
            if changes:
                method_name = method + '_' + self.name
                if not model.__rpc__[method_name].cache:
                    changes.append('id')

                for name in changes:
                    target = model
                    if '.' in name:
                        prefix, _ = name.rsplit('.', 1)
                        prefix += '.'
                    else:
                        prefix = ''
                    while name.startswith('_parent_'):
                        field, name = name.split('.', 1)
                        target = target._fields[field[8:]].get_target()
                    field = target._fields[name]
                    if field and field.context:
                        eval_fields = get_eval_fields(field.context)
                        for context_field_name in eval_fields:
                            prefix_ctx_field_name = (
                                prefix + context_field_name)
                            if (context_field_name in field.depends
                                    and prefix_ctx_field_name not in changes):
                                changes.append(prefix_ctx_field_name)

        name = '%s,%s' % (model.__name__, self.name)
        for attr, ttype in [('string', 'field'), ('help', 'help')]:
            definition[attr] = ''
            for source in getattr(self, attr):
                if not isinstance(source, LazyString):
                    source = (
                        Translation.get_source(name, ttype, language, source)
                        or source)
                definition[attr] += source
        return definition
Example #5
0
 def do_open_(self, action):
     encoder = PYSONEncoder()
     action['pyson_context'] = '{}'
     action['pyson_search_value'] = encoder.encode([('date', '>=',
                                                     self.record.date)])
     action['pyson_domain'] = encoder.encode([('product', '=',
                                               str(self.record.product))])
     action['name'] += ' (' + self.record.rec_name + ')'
     return action, {}
Example #6
0
 def do_create_(self, action):
     pool = Pool()
     Commission = pool.get('commission')
     commissions = Commission.search(self.get_domain(),
                                     order=[('agent', 'DESC'),
                                            ('date', 'DESC')])
     Commission.invoice(commissions)
     invoice_ids = list({c.invoice_line.invoice.id for c in commissions})
     encoder = PYSONEncoder()
     action['pyson_domain'] = encoder.encode([('id', 'in', invoice_ids)])
     action['pyson_search_value'] = encoder.encode([])
     return action, {}
Example #7
0
 def do_create_(self, action):
     pool = Pool()
     Commission = pool.get('commission')
     commissions = Commission.search(self.get_domain(),
         order=[('agent', 'DESC'), ('date', 'DESC')])
     Commission.invoice(commissions)
     invoice_ids = list({c.invoice_line.invoice.id for c in commissions})
     encoder = PYSONEncoder()
     action['pyson_domain'] = encoder.encode(
         [('id', 'in', invoice_ids)])
     action['pyson_search_value'] = encoder.encode([])
     return action, {}
Example #8
0
    def analytic_accounts_fields_get(cls, field, fields_names=None,
            states=None, required_states=None):
        res = {}
        if fields_names is None:
            fields_names = []
        if states is None:
            states = {}

        encoder = PYSONEncoder()

        root_accounts = cls.search([
                ('parent', '=', None),
                ])
        for account in root_accounts:
            name = 'analytic_account_' + str(account.id)
            if name in fields_names or not fields_names:
                res[name] = field.copy()
                field_states = states.copy()
                if account.mandatory:
                    if required_states:
                        field_states['required'] = required_states
                    else:
                        field_states['required'] = True
                res[name]['states'] = encoder.encode(field_states)
                res[name]['string'] = account.name
                res[name]['relation'] = cls.__name__
                res[name]['domain'] = PYSONEncoder().encode([
                    ('root', '=', account.id),
                    ('type', '=', 'normal')])
        return res
Example #9
0
 def definition(self, model, language):
     encoder = PYSONEncoder()
     definition = super().definition(model, language)
     if self.add_remove is not None:
         definition['add_remove'] = encoder.encode(self.add_remove)
     definition['datetime_field'] = self.datetime_field
     if self.filter:
         definition['domain'] = encoder.encode(
             ['AND', self.domain, self.filter])
     definition['relation'] = self.get_target().__name__
     definition['search_context'] = encoder.encode(self.search_context)
     definition['search_order'] = encoder.encode(self.search_order)
     definition['sortable'] &= hasattr(model, 'order_' + self.name)
     if self.size is not None:
         definition['size'] = encoder.encode(self.size)
     return definition
Example #10
0
    def fields_get(cls, fields_names=None, group=0, level=0):
        Model = Pool().get('ir.model')
        Data = Pool().get('lims.interface.data')
        res = super().fields_get(fields_names)

        table = cls.get_table()
        readonly = Transaction().context.get('lims_interface_readonly', False)
        encoder = PYSONEncoder()

        for field in table.grouped_fields_:
            if field.group != group:
                continue
            res[field.name] = {
                'name': field.name,
                'string': field.string,
                'type': FIELD_TYPE_TRYTON[field.type],
                'readonly': bool(readonly or field.formula or field.readonly),
                'help': field.help,
                'domain': field.domain,
                'states': '{}',
                }
            if field.type == 'many2one':
                res[field.name]['relation'] = (field.related_model.model if
                    field.related_model else None)
            if field.type == 'selection':
                selection = [tuple(v.split(':', 1))
                    for v in field.selection.splitlines() if v]
                res[field.name]['selection'] = selection
                res[field.name]['selection_change_with'] = []
                res[field.name]['sort'] = False
            if field.type == 'reference':
                selection = []
                for model in Model.search([]):
                    selection.append((model.model, model.name))
                res[field.name]['selection'] = selection
            if field.type in ['date', 'time', 'datetime', 'timestamp']:
                res[field.name]['format'] = PYSONEncoder().encode(
                    '%H:%M:%S.%f')
            if field.type in ['float', 'numeric']:
                res[field.name]['digits'] = encoder.encode((16, field.digits))
            if field.inputs:
                res[field.name]['on_change_with'] = field.inputs.split() + [
                    'data']
                cls.add_on_change_with_method(field)
                func_name = '%s_%s' % ('on_change_with', field.name)
                cls.__rpc__.setdefault(func_name, RPC(instantiate=0))

        res['data'] = {
            'name': 'data',
            'string': 'Data',
            'type': 'many2one',
            'readonly': True,
            'help': '',
            'states': '{}',
            'relation': 'lims.interface.data',
            'relation_field': 'group_%s' % group,
            'relation_fields': (Data.fields_get(level=level - 1)
                if level > 0 else []),
            }
        return res
Example #11
0
    def get_buttons(self, wizard, state_name):
        '''
        Returns button definitions translated
        '''
        Translation = Pool().get('ir.translation')

        def translation_key(button):
            return (','.join(
                (wizard.__name__, state_name, button.state)), 'wizard_button',
                    Transaction().language, button.string)

        translation_keys = [translation_key(button) for button in self.buttons]
        translations = Translation.get_sources(translation_keys)
        encoder = PYSONEncoder()
        result = []
        for button in self.buttons:
            validate = (button.validate if button.validate is not None else
                        button.state != wizard.end_state)
            result.append({
                'state':
                button.state,
                'icon':
                button.icon,
                'default':
                button.default,
                'validate':
                validate,
                'string': (translations.get(translation_key(button))
                           or button.string),
                'states':
                encoder.encode(button.states),
            })
        return result
Example #12
0
    def do_create_order(self, action):
        pool = Pool()
        Sale = pool.get('sale.sale')

        address = self._get_address()
        visit = self._get_visit()

        sale = Sale()
        sale.party = address.party
        sale.invoice_address = address
        sale.shipment_address = address
        if visit:
            sale.sale_date = visit.time.date()
            sale.origin = visit
        sale.save()

        encoder = PYSONEncoder()
        action['views'].reverse()
        action['domains'] = []
        action['pyson_domain'] = encoder.encode([
            ('id', '=', sale.id),
        ])
        return action, {
            'res_id': [sale.id],
        }
Example #13
0
 def _ModelView__view_look_dom(
         cls, element, type, fields_width=None, _fields_attrs=None):
     result = super()._ModelView__view_look_dom(
         element, type, fields_width, _fields_attrs)
     if element.get('name') == 'update_totp_secret':
         encoder = PYSONEncoder()
         states = cls._buttons['update_totp_secret']
         element.set('states', encoder.encode(states))
     return result
Example #14
0
    def definition(self, model, language):
        encoder = PYSONEncoder()

        target = self.get_target()
        relation_fields = [
            fname for fname, field in target._fields.items()
            if field._type == 'one2many' and field.model_name == model.__name__
            and field.field == self.name
        ]

        definition = super().definition(model, language)
        definition['datetime_field'] = self.datetime_field
        definition['relation'] = target.__name__
        if len(relation_fields) == 1:
            definition['relation_field'], = relation_fields
        definition['search_context'] = encoder.encode(self.search_context)
        definition['search_order'] = encoder.encode(self.search_order)
        return definition
Example #15
0
 def do_open_(self, action):
     pool = Pool()
     Work = pool.get('project.work')
     works = Work.search([
             ('parent', 'child_of', Transaction().context['active_ids']),
             ])
     invoice_ids = set()
     for work in works:
         if work.invoice_line and work.invoice_line.invoice:
             invoice_ids.add(work.invoice_line.invoice.id)
         for timesheet_line in work.work.timesheet_lines:
             if (timesheet_line.invoice_line
                     and timesheet_line.invoice_line.invoice):
                 invoice_ids.add(timesheet_line.invoice_line.invoice.id)
     encoder = PYSONEncoder()
     action['pyson_domain'] = encoder.encode(
         [('id', 'in', list(invoice_ids))])
     action['pyson_search_value'] = encoder.encode([])
     return action, {}
Example #16
0
 def do_open_(self, action):
     pool = Pool()
     Work = pool.get('project.work')
     works = Work.search([
         ('parent', 'child_of', Transaction().context['active_ids']),
     ])
     invoice_ids = set()
     for work in works:
         if work.invoice_line and work.invoice_line.invoice:
             invoice_ids.add(work.invoice_line.invoice.id)
         for timesheet_line in work.work.timesheet_lines:
             if (timesheet_line.invoice_line
                     and timesheet_line.invoice_line.invoice):
                 invoice_ids.add(timesheet_line.invoice_line.invoice.id)
     encoder = PYSONEncoder()
     action['pyson_domain'] = encoder.encode([('id', 'in',
                                               list(invoice_ids))])
     action['pyson_search_value'] = encoder.encode([])
     return action, {}
Example #17
0
 def _ModelView__view_look_dom(
         cls, element, type, fields_width=None, _fields_attrs=None):
     result = super()._ModelView__view_look_dom(
         element, type, fields_width, _fields_attrs)
     name = element.get('name')
     if name in {'clear_totp_secret', 'setup_totp_secret'}:
         encoder = PYSONEncoder()
         states = cls._buttons[name]
         element.set('states', encoder.encode(states))
     return result
Example #18
0
 def do_open_(self, action):
     works = self.model.search([
         ('parent', 'child_of', list(map(int, self.records))),
     ])
     invoice_ids = set()
     for work in works:
         if work.invoice_line and work.invoice_line.invoice:
             invoice_ids.add(work.invoice_line.invoice.id)
         for twork in work.timesheet_works:
             for timesheet_line in twork.timesheet_lines:
                 if (timesheet_line.invoice_line
                         and timesheet_line.invoice_line.invoice):
                     invoice_ids.add(timesheet_line.invoice_line.invoice.id)
         if work.invoiced_progress:
             for progress in work.invoiced_progress:
                 invoice_ids.add(progress.invoice_line.invoice.id)
     encoder = PYSONEncoder()
     action['pyson_domain'] = encoder.encode([('id', 'in',
                                               list(invoice_ids))])
     action['pyson_search_value'] = encoder.encode([])
     return action, {}
Example #19
0
 def _get_window_domains(cls, types):
     key = tuple(sorted(types))
     domains = cls._get_window_domains_cache.get(key)
     if domains is not None:
         return domains
     encoder = PYSONEncoder()
     domains = []
     for status in cls.search([('types', 'in', types)]):
         domain = encoder.encode([('status', '=', status.id)])
         domains.append((status.name, domain, status.count))
     if domains:
         domains.append(
             (gettext('project.msg_domain_all'), '[]', False))
     cls._get_window_domains_cache.set(key, domains)
     return domains
Example #20
0
    def fields_get(cls, fields_names=None):
        """
        Return the definition of each field on the model.
        """
        definition = {}
        pool = Pool()
        Translation = pool.get('ir.translation')
        FieldAccess = pool.get('ir.model.field.access')
        ModelAccess = pool.get('ir.model.access')

        # Add translation to cache
        language = Transaction().language
        trans_args = []
        for fname, field in cls._fields.items():
            if fields_names and fname not in fields_names:
                continue
            trans_args.extend(field.definition_translations(cls, language))
        Translation.get_sources(trans_args)

        encoder = PYSONEncoder()
        decoder = PYSONDecoder(noeval=True)

        accesses = FieldAccess.get_access([cls.__name__])[cls.__name__]
        for fname, field in cls._fields.items():
            if fields_names and fname not in fields_names:
                continue
            definition[fname] = field.definition(cls, language)
            if not accesses.get(fname, {}).get('write', True):
                definition[fname]['readonly'] = True
                states = decoder.decode(definition[fname]['states'])
                states.pop('readonly', None)
                definition[fname]['states'] = encoder.encode(states)
            for right in ['create', 'delete']:
                definition[fname][right] = accesses.get(fname,
                                                        {}).get(right, True)

        for fname in list(definition.keys()):
            # filter out fields which aren't in the fields_names list
            if fields_names:
                if fname not in fields_names:
                    del definition[fname]
            elif not ModelAccess.check_relation(
                    cls.__name__, fname, mode='read'):
                del definition[fname]
        return definition
Example #21
0
 def parse_view(cls, tree, type, *args, **kwargs):
     pool = Pool()
     Product = pool.get('product.product')
     Template = pool.get('product.template')
     context = Transaction().context
     if kwargs.get('view_depends') is None:
         view_depends = []
     else:
         view_depends = kwargs['view_depends'].copy()
     kwargs['view_depends'] = view_depends
     if type == 'graph':
         encoder = PYSONEncoder()
         if context.get('product_template') is not None:
             product_template = context['product_template']
             if isinstance(product_template, int):
                 product_template = [product_template]
             records = Template.browse(product_template)
         elif context.get('product'):
             product = context['product']
             if product is None:
                 product = -1
             if isinstance(product, int):
                 product = [product]
             records = Product.browse(product)
         else:
             records = []
         if len(records) > 1:
             quantity_node, = tree.xpath('//y/field[@name="quantity"]')
             parent = quantity_node.getparent()
             parent.remove(quantity_node)
             for record in records:
                 node = deepcopy(quantity_node)
                 node.set('key', str(record.id))
                 node.set('string', record.rec_name)
                 node.set('domain',
                          encoder.encode(Eval('product') == str(record)))
                 node.set('fill', '0')
                 parent.append(node)
             graph, = tree.xpath('/graph')
             graph.set('legend', '1')
         view_depends.append('product')
     return super().parse_view(tree, type, *args, **kwargs)
Example #22
0
 def get_pyson(cls, windows, name):
     pool = Pool()
     encoder = PYSONEncoder()
     pysons = {}
     field = name[6:]
     defaults = {
         'domain': '[]',
         'context': '{}',
         'search_value': '[]',
     }
     for window in windows:
         if not window.order and field == 'order':
             if window.res_model:
                 defaults['order'] = encoder.encode(
                     getattr(pool.get(window.res_model), '_order', 'null'))
             else:
                 defaults['order'] = 'null'
         pysons[window.id] = (getattr(window, field)
                              or defaults.get(field, 'null'))
     return pysons
Example #23
0
    def get_buttons(self, wizard, state_name):
        '''
        Returns button definitions translated
        '''
        Translation = Pool().get('ir.translation')

        def translation_key(button):
            return (','.join((wizard.__name__, state_name, button.state)),
                'wizard_button', Transaction().language, button.string)
        translation_keys = [translation_key(button) for button in self.buttons]
        translations = Translation.get_sources(translation_keys)
        encoder = PYSONEncoder()
        result = []
        for button in self.buttons:
            result.append({
                    'state': button.state,
                    'icon': button.icon,
                    'default': button.default,
                    'string': (translations.get(translation_key(button))
                        or button.string),
                    'states': encoder.encode(button.states),
                    })
        return result
Example #24
0
    def fields_get(cls, fields_names=None, level=0):
        """
        Return the definition of each field on the model.
        """
        definition = {}
        pool = Pool()
        Translation = pool.get('ir.translation')
        FieldAccess = pool.get('ir.model.field.access')
        ModelAccess = pool.get('ir.model.access')

        # Add translation to cache
        language = Transaction().language
        trans_args = []
        for fname, field in cls._fields.items():
            if fields_names and fname not in fields_names:
                continue
            trans_args.extend(field.definition_translations(cls, language))
        Translation.get_sources(trans_args)

        encoder = PYSONEncoder()
        decoder = PYSONDecoder(noeval=True)

        accesses = FieldAccess.get_access([cls.__name__])[cls.__name__]
        for fname, field in cls._fields.items():
            if fields_names and fname not in fields_names:
                continue
            definition[fname] = field.definition(cls, language)
            if not accesses.get(fname, {}).get('write', True):
                definition[fname]['readonly'] = True
                states = decoder.decode(definition[fname]['states'])
                states.pop('readonly', None)
                definition[fname]['states'] = encoder.encode(states)
            for right in ['create', 'delete']:
                definition[fname][right] = accesses.get(fname,
                                                        {}).get(right, True)
            if level > 0:
                relation = definition[fname].get('relation')
                if relation:
                    Relation = pool.get(relation)
                    relation_fields = Relation.fields_get(level=level - 1)
                    definition[fname]['relation_fields'] = relation_fields
                    for name, props in relation_fields.items():
                        # Convert selection into list
                        if isinstance(props.get('selection'), str):
                            change_with = props.get('selection_change_with')
                            if change_with:
                                selection = getattr(Relation(),
                                                    props['selection'])()
                            else:
                                selection = getattr(Relation,
                                                    props['selection'])()
                            props['selection'] = selection
                schema = definition[fname].get('schema_model')
                if schema:
                    Schema = pool.get(schema)
                    definition[fname]['relation_fields'] = (
                        Schema.get_relation_fields())

        for fname in list(definition.keys()):
            # filter out fields which aren't in the fields_names list
            if fields_names:
                if fname not in fields_names:
                    del definition[fname]
            elif not ModelAccess.check_relation(
                    cls.__name__, fname, mode='read'):
                del definition[fname]
        return definition
Example #25
0
    def __view_look_dom(cls,
                        element,
                        type,
                        fields_width=None,
                        fields_attrs=None):
        pool = Pool()
        Translation = pool.get('ir.translation')
        ModelData = pool.get('ir.model.data')
        ModelAccess = pool.get('ir.model.access')
        Button = pool.get('ir.model.button')
        User = pool.get('res.user')

        if fields_width is None:
            fields_width = {}
        if not fields_attrs:
            fields_attrs = {}
        else:
            fields_attrs = copy.deepcopy(fields_attrs)

        def set_view_ids(element):
            view_ids = []
            if element.get('view_ids'):
                for view_id in element.get('view_ids').split(','):
                    try:
                        view_ids.append(int(view_id))
                    except ValueError:
                        view_ids.append(ModelData.get_id(*view_id.split('.')))
                element.attrib['view_ids'] = ','.join(map(str, view_ids))
            return view_ids

        def get_relation(field):
            if hasattr(field, 'model_name'):
                return field.model_name
            elif hasattr(field, 'get_target'):
                return field.get_target().__name__

        def get_views(relation, view_ids, mode):
            Relation = pool.get(relation)
            views = {}
            if field._type in ['one2many', 'many2many']:
                # Prefetch only the first view to prevent infinite loop
                if view_ids:
                    for view_id in view_ids:
                        view = Relation.fields_view_get(view_id=view_id)
                        views[str(view_id)] = view
                        break
                else:
                    for view_type in mode:
                        views[view_type] = (Relation.fields_view_get(
                            view_type=view_type))
                        break
            return views

        for attr in ('name', 'icon'):
            if not element.get(attr):
                continue
            fields_attrs.setdefault(element.get(attr), {})

        if element.tag == 'field' and type in ['tree', 'form']:
            for attr in ('name', 'icon'):
                fname = element.get(attr)
                if not fname:
                    continue
                view_ids = set_view_ids(element)
                if type != 'form':
                    continue
                field = cls._fields[fname]
                relation = get_relation(field)
                if not relation:
                    continue
                mode = (element.attrib.pop('mode', None)
                        or 'tree,form').split(',')
                views = get_views(relation, view_ids, mode)
                element.attrib['mode'] = ','.join(mode)
                fields_attrs[fname].setdefault('views', {}).update(views)

            if type == 'tree' and element.get('name') in fields_width:
                element.set('width', str(fields_width[element.get('name')]))

        encoder = PYSONEncoder()
        if element.tag == 'button':
            button_name = element.attrib['name']
            if button_name in cls._buttons:
                states = cls._buttons[button_name]
            else:
                states = {}
            groups = set(User.get_groups())
            button_groups = Button.get_groups(cls.__name__, button_name)
            if ((button_groups and not groups & button_groups)
                    or (not button_groups and not ModelAccess.check(
                        cls.__name__, 'write', raise_exception=False))):
                states = states.copy()
                states['readonly'] = True
            element.set('states', encoder.encode(states))

            button_rules = Button.get_rules(cls.__name__, button_name)
            if button_rules:
                element.set('rule', '1')

            change = cls.__change_buttons[button_name]
            if change:
                element.set('change', encoder.encode(list(change)))
            if not is_instance_method(cls, button_name):
                element.set('type', 'class')
            else:
                element.set('type', 'instance')

        # translate view
        if Transaction().language != 'en':
            for attr in ('string', 'sum', 'confirm', 'help'):
                if element.get(attr):
                    trans = Translation.get_source(cls.__name__, 'view',
                                                   Transaction().language,
                                                   element.get(attr))
                    if trans:
                        element.set(attr, trans)

        if element.tag == 'tree' and element.get('sequence'):
            fields_attrs.setdefault(element.get('sequence'), {})

        if element.tag == 'calendar':
            for attr in ['dtstart', 'dtend', 'color', 'background_color']:
                if element.get(attr):
                    fields_attrs.setdefault(element.get(attr), {})

        for field in element:
            fields_attrs = cls.__view_look_dom(field,
                                               type,
                                               fields_width=fields_width,
                                               fields_attrs=fields_attrs)
        return fields_attrs
Example #26
0
    def _view_look_dom_arch(cls, tree, type, field_children=None):
        pool = Pool()
        ModelAccess = pool.get('ir.model.access')
        FieldAccess = pool.get('ir.model.field.access')

        encoder = PYSONEncoder()
        for xpath, attribute, value in cls.view_attributes():
            for element in tree.xpath(xpath):
                element.set(attribute, encoder.encode(value))

        fields_width = {}
        tree_root = tree.getroottree().getroot()

        # Find field without read access
        fread_accesses = FieldAccess.check(cls.__name__,
                                           cls._fields.keys(),
                                           'read',
                                           access=True)
        fields_to_remove = list(x for x, y in fread_accesses.iteritems()
                                if not y)

        # Find relation field without read access
        for name, field in cls._fields.iteritems():
            if not ModelAccess.check_relation(cls.__name__, name, mode='read'):
                fields_to_remove.append(name)

        for name, field in cls._fields.iteritems():
            for field_to_remove in fields_to_remove:
                if field_to_remove in field.depends:
                    fields_to_remove.append(name)

        # Remove field without read access
        for field in fields_to_remove:
            xpath = (
                '//field[@name="%(field)s"] | //label[@name="%(field)s"]'
                ' | //page[@name="%(field)s"] | //group[@name="%(field)s"]'
                ' | //separator[@name="%(field)s"]') % {
                    'field': field
                }
            for i, element in enumerate(tree.xpath(xpath)):
                if type == 'tree' or element.tag == 'page':
                    parent = element.getparent()
                    parent.remove(element)
                elif type == 'form':
                    element.tag = 'label'
                    colspan = element.attrib.get('colspan')
                    element.attrib.clear()
                    element.attrib['id'] = 'hidden %s-%s' % (field, i)
                    if colspan is not None:
                        element.attrib['colspan'] = colspan

        if type == 'tree':
            ViewTreeWidth = pool.get('ir.ui.view_tree_width')
            viewtreewidth_ids = ViewTreeWidth.search([
                ('model', '=', cls.__name__),
                ('user', '=', Transaction().user),
            ])
            for viewtreewidth in ViewTreeWidth.browse(viewtreewidth_ids):
                if viewtreewidth.width > 0:
                    fields_width[viewtreewidth.field] = viewtreewidth.width

        fields_def = cls.__view_look_dom(tree_root,
                                         type,
                                         fields_width=fields_width)

        if field_children:
            fields_def.setdefault(field_children, {'name': field_children})
            if field_children in cls._fields:
                field = cls._fields[field_children]
                if hasattr(field, 'field'):
                    fields_def.setdefault(field.field, {'name': field.field})

        for field_name in fields_def.keys():
            if field_name in cls._fields:
                field = cls._fields[field_name]
            else:
                continue
            for depend in field.depends:
                fields_def.setdefault(depend, {'name': depend})

        if 'active' in cls._fields:
            fields_def.setdefault('active', {'name': 'active'})

        arch = etree.tostring(tree, encoding='utf-8',
                              pretty_print=False).decode('utf-8')
        fields2 = cls.fields_get(fields_def.keys())
        for field in fields_def:
            if field in fields2:
                fields2[field].update(fields_def[field])
        return arch, fields2
Example #27
0
    def fields_get(self, fields_names=None):
        """
        Return the definition of each field on the model.

        :param fields_names: a list of field names or None for all fields
        :return: a dictionary with field name as key and definition as value
        """
        res = {}
        pool = Pool()
        translation_obj = pool.get('ir.translation')
        model_access_obj = pool.get('ir.model.access')
        field_access_obj = pool.get('ir.model.field.access')

        for parent in self._inherits:
            res.update(pool.get(parent).fields_get(fields_names))
        write_access = model_access_obj.check(self._name, 'write',
                raise_exception=False)

        #Add translation to cache
        language = Transaction().language
        trans_args = []
        for field in (x for x in self._columns.keys()
                if ((not fields_names) or x in fields_names)):
            trans_args.append((self._name + ',' + field, 'field', language,
                None))
            trans_args.append((self._name + ',' + field, 'help', language,
                None))
            if hasattr(self._columns[field], 'selection'):
                if isinstance(self._columns[field].selection, (tuple, list)) \
                        and ((hasattr(self._columns[field],
                            'translate_selection') \
                            and self._columns[field].translate_selection) \
                            or not hasattr(self._columns[field],
                                'translate_selection')):
                    sel = self._columns[field].selection
                    for (key, val) in sel:
                        trans_args.append((self._name + ',' + field,
                            'selection', language, val))
        translation_obj.get_sources(trans_args)

        encoder = PYSONEncoder()

        fwrite_accesses = field_access_obj.check(self._name, fields_names or
                self._columns.keys(), 'write', access=True)
        for field in (x for x in self._columns.keys()
                if ((not fields_names) or x in fields_names)):
            res[field] = {
                'type': self._columns[field]._type,
                'name': field,
                }
            for arg in (
                    'string',
                    'readonly',
                    'states',
                    'size',
                    'required',
                    'translate',
                    'help',
                    'select',
                    'on_change',
                    'add_remove',
                    'on_change_with',
                    'autocomplete',
                    'sort',
                    'datetime_field',
                    'loading',
                    'filename',
                    ):
                if getattr(self._columns[field], arg, None) is not None:
                    res[field][arg] = copy.copy(getattr(self._columns[field],
                        arg))
            if not write_access or not fwrite_accesses.get(field, True):
                res[field]['readonly'] = True
                if res[field].get('states') and \
                        'readonly' in res[field]['states']:
                    del res[field]['states']['readonly']
            for arg in ('digits', 'invisible'):
                if hasattr(self._columns[field], arg) \
                        and getattr(self._columns[field], arg):
                    res[field][arg] = copy.copy(getattr(self._columns[field],
                        arg))
            if isinstance(self._columns[field],
                    (fields.Function, fields.One2Many)) \
                    and not self._columns[field].order_field:
                res[field]['sortable'] = False
            if ((isinstance(self._columns[field], fields.Function)
                    and not self._columns[field].searcher)
                    or self._columns[field]._type in ('binary', 'sha')):
                res[field]['searchable'] = False
            else:
                res[field]['searchable'] = True

            if Transaction().context.get('language'):
                # translate the field label
                res_trans = translation_obj.get_source(
                        self._name + ',' + field, 'field',
                        Transaction().context['language'])
                if res_trans:
                    res[field]['string'] = res_trans
                help_trans = translation_obj.get_source(
                        self._name + ',' + field, 'help',
                        Transaction().context['language'])
                if help_trans:
                    res[field]['help'] = help_trans

            if hasattr(self._columns[field], 'selection'):
                if isinstance(self._columns[field].selection, (tuple, list)):
                    sel = copy.copy(self._columns[field].selection)
                    if Transaction().context.get('language') and \
                            ((hasattr(self._columns[field],
                                'translate_selection') \
                                and self._columns[field].translate_selection) \
                                or not hasattr(self._columns[field],
                                    'translate_selection')):
                        # translate each selection option
                        sel2 = []
                        for (key, val) in sel:
                            val2 = translation_obj.get_source(
                                    self._name + ',' + field, 'selection',
                                    language, val)
                            sel2.append((key, val2 or val))
                        sel = sel2
                    res[field]['selection'] = sel
                else:
                    # call the 'dynamic selection' function
                    res[field]['selection'] = copy.copy(
                            self._columns[field].selection)
            if res[field]['type'] in (
                    'one2many',
                    'many2many',
                    'many2one',
                    'one2one',
                    ):
                if hasattr(self._columns[field], 'model_name'):
                    relation = copy.copy(self._columns[field].model_name)
                else:
                    relation = copy.copy(
                        self._columns[field].get_target()._name)
                res[field]['relation'] = relation
                res[field]['domain'] = copy.copy(self._columns[field].domain)
                res[field]['context'] = copy.copy(self._columns[field].context)
            if res[field]['type'] == 'one2many' \
                    and hasattr(self._columns[field], 'field'):
                res[field]['relation_field'] = copy.copy(
                        self._columns[field].field)

            # convert attributes into pyson
            for attr in ('states', 'domain', 'context', 'digits',
                    'add_remove'):
                if attr in res[field]:
                    res[field][attr] = encoder.encode(res[field][attr])

        if fields_names:
            # filter out fields which aren't in the fields_names list
            for i in res.keys():
                if i not in fields_names:
                    del res[i]
        return res
Example #28
0
 def definition(self, model, language):
     encoder = PYSONEncoder()
     definition = super().definition(model, language)
     definition['digits'] = encoder.encode(self.digits)
     return definition
Example #29
0
    def __view_look_dom(cls, element, type, fields_width=None, fields_attrs=None):
        pool = Pool()
        Translation = pool.get("ir.translation")
        ModelData = pool.get("ir.model.data")
        Button = pool.get("ir.model.button")
        User = pool.get("res.user")

        if fields_width is None:
            fields_width = {}
        if not fields_attrs:
            fields_attrs = {}
        else:
            fields_attrs = copy.deepcopy(fields_attrs)
        childs = True

        if element.tag in ("field", "label", "separator", "group", "suffix", "prefix"):
            for attr in ("name", "icon"):
                if element.get(attr):
                    fields_attrs.setdefault(element.get(attr), {})
                    try:
                        field = cls._fields[element.get(attr)]
                        if hasattr(field, "model_name"):
                            relation = field.model_name
                        else:
                            relation = field.get_target().__name__
                    except Exception:
                        relation = False
                    if relation and element.tag == "field":
                        childs = False
                        views = {}
                        mode = (element.attrib.pop("mode", None) or "tree,form").split(",")
                        view_ids = []
                        if element.get("view_ids"):
                            for view_id in element.get("view_ids").split(","):
                                try:
                                    view_ids.append(int(view_id))
                                except ValueError:
                                    view_ids.append(ModelData.get_id(*view_id.split(".")))
                        Relation = pool.get(relation)
                        if not len(element) and type == "form" and field._type in ("one2many", "many2many"):
                            # Prefetch only the first view to prevent infinite
                            # loop
                            if view_ids:
                                for view_id in view_ids:
                                    view = Relation.fields_view_get(view_id=view_id)
                                    views[str(view_id)] = view
                                    break
                            else:
                                for view_type in mode:
                                    views[view_type] = Relation.fields_view_get(view_type=view_type)
                                    break
                        element.attrib["mode"] = ",".join(mode)
                        element.attrib["view_ids"] = ",".join(map(str, view_ids))
                        fields_attrs[element.get(attr)].setdefault("views", {}).update(views)
            if element.get("name") in fields_width:
                element.set("width", str(fields_width[element.get("name")]))

        # convert attributes into pyson
        encoder = PYSONEncoder()
        for attr in ("states", "domain", "context", "digits", "add_remove", "spell", "colors"):
            if element.get(attr):
                element.set(attr, encoder.encode(safe_eval(element.get(attr), CONTEXT)))

        if element.tag == "button":
            button_name = element.attrib["name"]
            if button_name in cls._buttons:
                states = cls._buttons[button_name]
            else:
                states = {}
            groups = set(User.get_groups())
            button_groups = Button.get_groups(cls.__name__, button_name)
            if button_groups and not groups & button_groups:
                states = states.copy()
                states["readonly"] = True
            element.set("states", encoder.encode(states))

        # translate view
        if Transaction().language != "en_US":
            for attr in ("string", "sum", "confirm", "help"):
                if element.get(attr):
                    trans = Translation.get_source(cls.__name__, "view", Transaction().language, element.get(attr))
                    if trans:
                        element.set(attr, trans)

        # Set header string
        if element.tag in ("form", "tree", "graph"):
            element.set("string", cls.view_header_get(element.get("string") or "", view_type=element.tag))

        if element.tag == "tree" and element.get("sequence"):
            fields_attrs.setdefault(element.get("sequence"), {})

        if childs:
            for field in element:
                fields_attrs = cls.__view_look_dom(field, type, fields_width=fields_width, fields_attrs=fields_attrs)
        return fields_attrs
Example #30
0
    def __view_look_dom(cls,
                        element,
                        type,
                        fields_width=None,
                        fields_attrs=None):
        pool = Pool()
        Translation = pool.get('ir.translation')
        ModelData = pool.get('ir.model.data')
        Button = pool.get('ir.model.button')
        User = pool.get('res.user')

        if fields_width is None:
            fields_width = {}
        if not fields_attrs:
            fields_attrs = {}
        else:
            fields_attrs = copy.deepcopy(fields_attrs)
        childs = True

        if element.tag in ('field', 'label', 'separator', 'group', 'suffix',
                           'prefix'):
            for attr in ('name', 'icon'):
                if element.get(attr):
                    fields_attrs.setdefault(element.get(attr), {})
                    try:
                        field = cls._fields[element.get(attr)]
                        if hasattr(field, 'model_name'):
                            relation = field.model_name
                        else:
                            relation = field.get_target().__name__
                    except Exception:
                        relation = False
                    if relation and element.tag == 'field':
                        childs = False
                        views = {}
                        mode = (element.attrib.pop('mode', None)
                                or 'tree,form').split(',')
                        view_ids = []
                        if element.get('view_ids'):
                            for view_id in element.get('view_ids').split(','):
                                try:
                                    view_ids.append(int(view_id))
                                except ValueError:
                                    view_ids.append(
                                        ModelData.get_id(*view_id.split('.')))
                        Relation = pool.get(relation)
                        if (not len(element) and type == 'form'
                                and field._type in ('one2many', 'many2many')):
                            # Prefetch only the first view to prevent infinite
                            # loop
                            if view_ids:
                                for view_id in view_ids:
                                    view = Relation.fields_view_get(
                                        view_id=view_id)
                                    views[str(view_id)] = view
                                    break
                            else:
                                for view_type in mode:
                                    views[view_type] = \
                                        Relation.fields_view_get(
                                            view_type=view_type)
                                    break
                        element.attrib['mode'] = ','.join(mode)
                        element.attrib['view_ids'] = ','.join(
                            map(str, view_ids))
                        fields_attrs[element.get(attr)].setdefault(
                            'views', {}).update(views)
            if element.get('name') in fields_width:
                element.set('width', str(fields_width[element.get('name')]))

        encoder = PYSONEncoder()
        if element.tag == 'button':
            button_name = element.attrib['name']
            if button_name in cls._buttons:
                states = cls._buttons[button_name]
            else:
                states = {}
            groups = set(User.get_groups())
            button_groups = Button.get_groups(cls.__name__, button_name)
            if button_groups and not groups & button_groups:
                states = states.copy()
                states['readonly'] = True
            element.set('states', encoder.encode(states))

            change = cls.__change_buttons[button_name]
            if change:
                element.set('change', encoder.encode(list(change)))
            if not is_instance_method(cls, button_name):
                element.set('type', 'class')
            else:
                element.set('type', 'instance')

        # translate view
        if Transaction().language != 'en_US':
            for attr in ('string', 'sum', 'confirm', 'help'):
                if element.get(attr):
                    trans = Translation.get_source(cls.__name__, 'view',
                                                   Transaction().language,
                                                   element.get(attr))
                    if trans:
                        element.set(attr, trans)

        # Set header string
        if element.tag in ('form', 'tree', 'graph'):
            element.set(
                'string',
                cls.view_header_get(element.get('string') or '',
                                    view_type=element.tag))

        if element.tag == 'tree' and element.get('sequence'):
            fields_attrs.setdefault(element.get('sequence'), {})

        if element.tag == 'calendar':
            for attr in ('dtstart', 'dtend'):
                if element.get(attr):
                    fields_attrs.setdefault(element.get(attr), {})

        if childs:
            for field in element:
                fields_attrs = cls.__view_look_dom(field,
                                                   type,
                                                   fields_width=fields_width,
                                                   fields_attrs=fields_attrs)
        return fields_attrs
Example #31
0
    def __parse_fields(cls,
                       element,
                       type,
                       fields_width=None,
                       fields_optional=None,
                       _fields_attrs=None):
        pool = Pool()
        Translation = pool.get('ir.translation')
        ModelData = pool.get('ir.model.data')
        ModelAccess = pool.get('ir.model.access')
        Button = pool.get('ir.model.button')
        User = pool.get('res.user')
        ActionWindow = pool.get('ir.action.act_window')

        if fields_width is None:
            fields_width = {}
        if fields_optional is None:
            fields_optional = {}
        if _fields_attrs is None:
            fields_attrs = {}
        else:
            fields_attrs = _fields_attrs

        def set_view_ids(element):
            view_ids = []
            if element.get('view_ids'):
                for view_id in element.get('view_ids').split(','):
                    try:
                        view_ids.append(int(view_id))
                    except ValueError:
                        view_ids.append(ModelData.get_id(*view_id.split('.')))
                element.attrib['view_ids'] = ','.join(map(str, view_ids))
            return view_ids

        def get_relation(field):
            if hasattr(field, 'model_name'):
                return field.model_name
            elif hasattr(field, 'get_target'):
                return field.get_target().__name__

        def get_views(relation, widget, view_ids, mode):
            Relation = pool.get(relation)
            views = {}
            if widget in {'one2many', 'many2many'}:
                # Prefetch only the first view to prevent infinite loop
                if view_ids:
                    for view_id in view_ids:
                        view = Relation.fields_view_get(view_id=view_id)
                        views[str(view_id)] = view
                        break
                else:
                    for view_type in mode:
                        views[view_type] = (Relation.fields_view_get(
                            view_type=view_type))
                        break
            return views

        for attr in ('name', 'icon', 'symbol'):
            if not element.get(attr):
                continue
            fields_attrs.setdefault(element.get(attr), {})

        if element.tag == 'field' and type in ['tree', 'form']:
            for attr in ('name', 'icon'):
                fname = element.get(attr)
                if not fname:
                    continue
                view_ids = set_view_ids(element)
                if type != 'form':
                    continue
                field = cls._fields[fname]
                relation = get_relation(field)
                if not relation:
                    continue
                mode = (element.attrib.pop('mode', None)
                        or 'tree,form').split(',')
                widget = element.attrib.get('widget', field._type)
                views = get_views(relation, widget, view_ids, mode)
                element.attrib['mode'] = ','.join(mode)
                fields_attrs[fname].setdefault('views', {}).update(views)

            if type == 'tree':
                if element.get('name') in fields_width:
                    element.set('width',
                                str(fields_width[element.get('name')]))
                if element.get('optional'):
                    if element.get('name') in fields_optional:
                        optional = str(
                            int(fields_optional[element.get('name')]))
                        element.set('optional', optional)

        encoder = PYSONEncoder()
        if element.tag == 'button':
            button_name = element.attrib['name']
            if button_name in cls._buttons:
                states = cls._buttons[button_name]
            else:
                states = {}
            groups = set(User.get_groups())
            button_attr = Button.get_view_attributes(cls.__name__, button_name)
            for attr, value in button_attr.items():
                if not element.get(attr):
                    element.set(attr, value or '')
            button_groups = Button.get_groups(cls.__name__, button_name)
            if ((button_groups and not groups & button_groups)
                    or (not button_groups and not ModelAccess.check(
                        cls.__name__, 'write', raise_exception=False))):
                states = states.copy()
                states['readonly'] = True
            element.set('states', encoder.encode(states))

            button_rules = Button.get_rules(cls.__name__, button_name)
            if button_rules:
                element.set('rule', '1')

            change = cls.__change_buttons[button_name]
            if change:
                change = list(change)
                # Add id to change if the button is not cached
                # Not having the id increase the efficiency of the cache
                if cls.__rpc__[button_name].cache:
                    change.append('id')
                element.set('change', encoder.encode(change))
            if not is_instance_method(cls, button_name):
                element.set('type', 'class')
            else:
                element.set('type', 'instance')

            for depend in states.get('depends', []):
                fields_attrs.setdefault(depend, {})

        if element.tag == 'link':
            link_name = element.attrib['name']
            action_id = ModelData.get_id(*link_name.split('.'))
            try:
                with Transaction().set_context(_check_access=True):
                    action, = ActionWindow.search([('id', '=', action_id)])
            except ValueError:
                action = None
            if (not action or not action.res_model or not ModelAccess.check(
                    action.res_model, 'read', raise_exception=False)):
                element.tag = 'label'
                colspan = element.attrib.get('colspan')
                link_name = element.attrib['name']
                element.attrib.clear()
                element.attrib['id'] = link_name
                if colspan is not None:
                    element.attrib['colspan'] = colspan
            else:
                element.attrib['id'] = str(action.action.id)

        # translate view
        if Transaction().language != 'en':
            for attr in ('string', 'sum', 'confirm', 'help'):
                if element.get(attr):
                    trans = Translation.get_source(cls.__name__, 'view',
                                                   Transaction().language,
                                                   element.get(attr))
                    if trans:
                        element.set(attr, trans)

        if element.tag == 'tree' and element.get('sequence'):
            fields_attrs.setdefault(element.get('sequence'), {})

        if element.tag == 'calendar':
            for attr in ['dtstart', 'dtend', 'color', 'background_color']:
                if element.get(attr):
                    fields_attrs.setdefault(element.get(attr), {})

        for field in element:
            fields_attrs = cls.__parse_fields(field,
                                              type,
                                              fields_width=fields_width,
                                              fields_optional=fields_optional,
                                              _fields_attrs=fields_attrs)
        return fields_attrs
Example #32
0
    def parse_view(cls,
                   tree,
                   type,
                   view_id=None,
                   field_children=None,
                   level=0,
                   view_depends=None):
        """
        Return sanitized XML and the corresponding fields definition
        """
        pool = Pool()
        ModelAccess = pool.get('ir.model.access')
        FieldAccess = pool.get('ir.model.field.access')

        tree_root = tree.getroottree().getroot()
        readonly_view = (tree_root.tag == 'board' or
                         (tree_root.tag == 'tree'
                          and not int(tree_root.attrib.get('editable', '0'))))

        encoder = PYSONEncoder()
        if view_depends is None:
            view_depends = []
        else:
            view_depends = view_depends.copy()
        with Transaction().set_context(view_id=view_id):
            for xpath, attribute, value, *extra in cls.view_attributes():
                if readonly_view and attribute in {'required', 'readonly'}:
                    continue
                depends = []
                if extra:
                    depends, = extra
                nodes = tree.xpath(xpath)
                for element in nodes:
                    element.set(attribute, encoder.encode(value))
                if nodes and depends:
                    view_depends.extend(depends)

        fields_width = {}
        fields_optional = {}
        tree_root = tree.getroottree().getroot()

        # Find field without read access
        fread_accesses = FieldAccess.check(cls.__name__,
                                           list(cls._fields.keys()),
                                           'read',
                                           access=True)
        fields_to_remove = set(x for x, y in fread_accesses.items() if not y)

        # Find relation field without read access
        for name, field in cls._fields.items():
            if not ModelAccess.check_relation(cls.__name__, name, mode='read'):
                fields_to_remove.add(name)

        checked = set()
        while checked < fields_to_remove:
            to_check = fields_to_remove - checked
            for name, field in cls._fields.items():
                for field_to_remove in to_check:
                    if field_to_remove in field.depends:
                        fields_to_remove.add(name)
            checked |= to_check

        buttons_to_remove = set()
        for name, definition in cls._buttons.items():
            if fields_to_remove & set(definition.get('depends', [])):
                buttons_to_remove.add(name)

        field_xpath = (
            '//field[@name="%(name)s"]'
            '| //label[@name="%(name)s"] | //page[@name="%(name)s"]'
            '| //group[@name="%(name)s"] | //separator[@name="%(name)s"]')
        button_xpath = '//button[@name="%(name)s"]'
        # Remove field and button without read acces
        for xpath, names in (
            (field_xpath, fields_to_remove),
            (button_xpath, buttons_to_remove),
        ):
            for name in names:
                path = xpath % {'name': name}
                for i, element in enumerate(tree.xpath(path)):
                    if type == 'tree' or element.tag == 'page':
                        parent = element.getparent()
                        parent.remove(element)
                    elif type == 'form':
                        element.tag = 'label'
                        colspan = element.attrib.get('colspan')
                        element.attrib.clear()
                        element.attrib['id'] = 'hidden %s-%s' % (name, i)
                        if colspan is not None:
                            element.attrib['colspan'] = colspan

        # Remove empty pages
        if type == 'form':
            for page in tree.xpath('//page[not(descendant::*)]'):
                page.getparent().remove(page)

        if type == 'tree':
            user = Transaction().user
            if Transaction().context.get('view_tree_width'):
                ViewTreeWidth = pool.get('ir.ui.view_tree_width')
                viewtreewidths = ViewTreeWidth.search([
                    ('model', '=', cls.__name__),
                    ('user', '=', user),
                ])
                for viewtreewidth in viewtreewidths:
                    if viewtreewidth.width > 0:
                        fields_width[viewtreewidth.field] = viewtreewidth.width

            if view_id:
                ViewTreeOptional = pool.get('ir.ui.view_tree_optional')
                viewtreeoptionals = ViewTreeOptional.search([
                    ('view_id', '=', view_id),
                    ('user', '=', user),
                ])
                fields_optional = {o.field: o.value for o in viewtreeoptionals}

        fields_def = cls.__parse_fields(tree_root,
                                        type,
                                        fields_width=fields_width,
                                        fields_optional=fields_optional)

        if hasattr(cls, 'active'):
            fields_def.setdefault('active', {'name': 'active'})

        if field_children:
            fields_def.setdefault(field_children, {'name': field_children})
            if field_children in cls._fields:
                field = cls._fields[field_children]
                if hasattr(field, 'field'):
                    fields_def.setdefault(field.field, {'name': field.field})

        for depend in view_depends:
            if depend not in fields_to_remove:
                fields_def.setdefault(depend, {'name': depend})

        field_names = list(fields_def.keys())

        for field_name in field_names:
            if field_name not in cls._fields:
                continue
            field = cls._fields[field_name]
            field_depends = field.display_depends.copy()
            if not readonly_view:
                field_depends |= field.edition_depends
            if 'context' in field_depends and 'context' not in cls._fields:
                field_depends.discard('context')
            for depend in field_depends:
                if depend not in fields_def:
                    fields_def[depend] = {'name': depend}
                    field_names.append(depend)

        arch = etree.tostring(tree, encoding='utf-8',
                              pretty_print=False).decode('utf-8')
        # Do not call fields_def without fields as it returns all fields
        if fields_def:
            fields2 = cls.fields_get(list(fields_def.keys()), level=level)
        else:
            fields2 = {}
        for field in fields_def:
            if field in fields2:
                fields2[field].update(fields_def[field])
        return arch, fields2
Example #33
0
 def get_pyson_menu(self, name):
     encoder = PYSONEncoder()
     return encoder.encode(self.menu.get_action_value())
Example #34
0
    def __view_look_dom(cls, element, type, fields_width=None,
            fields_attrs=None):
        pool = Pool()
        Translation = pool.get('ir.translation')
        ModelData = pool.get('ir.model.data')
        Button = pool.get('ir.model.button')
        User = pool.get('res.user')

        if fields_width is None:
            fields_width = {}
        if not fields_attrs:
            fields_attrs = {}
        else:
            fields_attrs = copy.deepcopy(fields_attrs)

        def set_view_ids(element):
            view_ids = []
            if element.get('view_ids'):
                for view_id in element.get('view_ids').split(','):
                    try:
                        view_ids.append(int(view_id))
                    except ValueError:
                        view_ids.append(ModelData.get_id(*view_id.split('.')))
                element.attrib['view_ids'] = ','.join(map(str, view_ids))
            return view_ids

        def get_relation(field):
            if hasattr(field, 'model_name'):
                return field.model_name
            elif hasattr(field, 'get_target'):
                return field.get_target().__name__

        def get_views(relation, view_ids, mode):
            Relation = pool.get(relation)
            views = {}
            if field._type in ['one2many', 'many2many']:
                # Prefetch only the first view to prevent infinite loop
                if view_ids:
                    for view_id in view_ids:
                        view = Relation.fields_view_get(view_id=view_id)
                        views[str(view_id)] = view
                        break
                else:
                    for view_type in mode:
                        views[view_type] = (
                            Relation.fields_view_get(view_type=view_type))
                        break
            return views

        for attr in ('name', 'icon'):
            if not element.get(attr):
                continue
            fields_attrs.setdefault(element.get(attr), {})

        if element.tag == 'field' and type in ['tree', 'form']:
            for attr in ('name', 'icon'):
                fname = element.get(attr)
                if not fname:
                    continue
                view_ids = set_view_ids(element)
                if type != 'form':
                    continue
                field = cls._fields[fname]
                relation = get_relation(field)
                if not relation:
                    continue
                mode = (
                    element.attrib.pop('mode', None) or 'tree,form').split(',')
                views = get_views(relation, view_ids, mode)
                element.attrib['mode'] = ','.join(mode)
                fields_attrs[fname].setdefault('views', {}).update(views)

            if type == 'tree' and element.get('name') in fields_width:
                element.set('width', str(fields_width[element.get('name')]))

        encoder = PYSONEncoder()
        if element.tag == 'button':
            button_name = element.attrib['name']
            if button_name in cls._buttons:
                states = cls._buttons[button_name]
            else:
                states = {}
            groups = set(User.get_groups())
            button_groups = Button.get_groups(cls.__name__, button_name)
            if button_groups and not groups & button_groups:
                states = states.copy()
                states['readonly'] = True
            element.set('states', encoder.encode(states))

            change = cls.__change_buttons[button_name]
            if change:
                element.set('change', encoder.encode(list(change)))
            if not is_instance_method(cls, button_name):
                element.set('type', 'class')
            else:
                element.set('type', 'instance')

        # translate view
        if Transaction().language != 'en_US':
            for attr in ('string', 'sum', 'confirm', 'help'):
                if element.get(attr):
                    trans = Translation.get_source(cls.__name__, 'view',
                            Transaction().language, element.get(attr))
                    if trans:
                        element.set(attr, trans)

        # Set header string
        if element.tag in ('form', 'tree', 'graph'):
            element.set('string', cls.view_header_get(
                element.get('string') or '', view_type=element.tag))

        if element.tag == 'tree' and element.get('sequence'):
            fields_attrs.setdefault(element.get('sequence'), {})

        if element.tag == 'calendar':
            for attr in ('dtstart', 'dtend'):
                if element.get(attr):
                    fields_attrs.setdefault(element.get(attr), {})

        for field in element:
            fields_attrs = cls.__view_look_dom(field, type,
                fields_width=fields_width, fields_attrs=fields_attrs)
        return fields_attrs
Example #35
0
    def _view_look_dom_arch(cls, tree, type, field_children=None):
        pool = Pool()
        ModelAccess = pool.get('ir.model.access')
        FieldAccess = pool.get('ir.model.field.access')

        encoder = PYSONEncoder()
        for xpath, attribute, value in cls.view_attributes():
            for element in tree.xpath(xpath):
                element.set(attribute, encoder.encode(value))

        fields_width = {}
        tree_root = tree.getroottree().getroot()

        # Find field without read access
        fread_accesses = FieldAccess.check(cls.__name__,
                cls._fields.keys(), 'read', access=True)
        fields_to_remove = list(x for x, y in fread_accesses.iteritems()
                if not y)

        # Find relation field without read access
        for name, field in cls._fields.iteritems():
            if not ModelAccess.check_relation(cls.__name__, name, mode='read'):
                fields_to_remove.append(name)

        for name, field in cls._fields.iteritems():
            for field_to_remove in fields_to_remove:
                if field_to_remove in field.depends:
                    fields_to_remove.append(name)

        # Remove field without read access
        for field in fields_to_remove:
            xpath = ('//field[@name="%(field)s"] | //label[@name="%(field)s"]'
                ' | //page[@name="%(field)s"] | //group[@name="%(field)s"]'
                ' | //separator[@name="%(field)s"]') % {'field': field}
            for i, element in enumerate(tree.xpath(xpath)):
                if type == 'tree' or element.tag == 'page':
                    parent = element.getparent()
                    parent.remove(element)
                elif type == 'form':
                    element.tag = 'label'
                    element.attrib.clear()
                    element.attrib['id'] = 'hidden %s-%s' % (field, i)

        if type == 'tree':
            ViewTreeWidth = pool.get('ir.ui.view_tree_width')
            viewtreewidth_ids = ViewTreeWidth.search([
                ('model', '=', cls.__name__),
                ('user', '=', Transaction().user),
                ])
            for viewtreewidth in ViewTreeWidth.browse(viewtreewidth_ids):
                if viewtreewidth.width > 0:
                    fields_width[viewtreewidth.field] = viewtreewidth.width

        fields_def = cls.__view_look_dom(tree_root, type,
                fields_width=fields_width)

        if field_children:
            fields_def.setdefault(field_children, {'name': field_children})
            if field_children in cls._fields:
                field = cls._fields[field_children]
                if hasattr(field, 'field'):
                    fields_def.setdefault(field.field, {'name': field.field})

        for field_name in fields_def.keys():
            if field_name in cls._fields:
                field = cls._fields[field_name]
            else:
                continue
            for depend in field.depends:
                fields_def.setdefault(depend, {'name': depend})

        if 'active' in cls._fields:
            fields_def.setdefault('active', {'name': 'active'})

        arch = etree.tostring(
            tree, encoding='utf-8', pretty_print=False).decode('utf-8')
        fields2 = cls.fields_get(fields_def.keys())
        for field in fields_def:
            if field in fields2:
                fields2[field].update(fields_def[field])
        return arch, fields2
Example #36
0
    def fields_get(cls, fields_names=None):
        """
        Return the definition of each field on the model.
        """
        res = {}
        pool = Pool()
        Translation = pool.get('ir.translation')
        FieldAccess = pool.get('ir.model.field.access')

        #Add translation to cache
        language = Transaction().language
        trans_args = []
        for field in (x for x in cls._fields.keys()
                if ((not fields_names) or x in fields_names)):
            trans_args.append((cls.__name__ + ',' + field, 'field', language,
                None))
            trans_args.append((cls.__name__ + ',' + field, 'help', language,
                None))
            if hasattr(cls._fields[field], 'selection'):
                if (isinstance(cls._fields[field].selection, (tuple, list))
                        and ((hasattr(cls._fields[field],
                                    'translate_selection')
                                and cls._fields[field].translate_selection)
                            or not hasattr(cls._fields[field],
                                'translate_selection'))):
                    sel = cls._fields[field].selection
                    for (key, val) in sel:
                        trans_args.append((cls.__name__ + ',' + field,
                            'selection', language, val))
        Translation.get_sources(trans_args)

        encoder = PYSONEncoder()

        accesses = FieldAccess.get_access([cls.__name__])[cls.__name__]
        for field in (x for x in cls._fields.keys()
                if ((not fields_names) or x in fields_names)):
            res[field] = {
                'type': cls._fields[field]._type,
                'name': field,
                }
            for arg in (
                    'string',
                    'readonly',
                    'states',
                    'size',
                    'required',
                    'translate',
                    'help',
                    'select',
                    'on_change',
                    'add_remove',
                    'on_change_with',
                    'autocomplete',
                    'sort',
                    'datetime_field',
                    'loading',
                    'filename',
                    'selection_change_with',
                    'srid',
                    ):
                if getattr(cls._fields[field], arg, None) is not None:
                    res[field][arg] = copy.copy(getattr(cls._fields[field],
                        arg))
            if not accesses.get(field, {}).get('write', True):
                res[field]['readonly'] = True
                if res[field].get('states') and \
                        'readonly' in res[field]['states']:
                    del res[field]['states']['readonly']
            for arg in ('digits', 'invisible'):
                if hasattr(cls._fields[field], arg) \
                        and getattr(cls._fields[field], arg):
                    res[field][arg] = copy.copy(getattr(cls._fields[field],
                        arg))
            if isinstance(cls._fields[field],
                    (fields.Function, fields.One2Many)) \
                    and not cls._fields[field].order_field:
                res[field]['sortable'] = False
            if ((isinstance(cls._fields[field], fields.Function)
                    and not cls._fields[field].searcher)
                    or cls._fields[field]._type in ('binary', 'sha')):
                res[field]['searchable'] = False
            else:
                res[field]['searchable'] = True

            if Transaction().context.get('language'):
                # translate the field label
                res_trans = Translation.get_source(
                    cls.__name__ + ',' + field, 'field',
                    Transaction().context['language'])
                if res_trans:
                    res[field]['string'] = res_trans
                help_trans = Translation.get_source(
                    cls.__name__ + ',' + field, 'help',
                    Transaction().context['language'])
                if help_trans:
                    res[field]['help'] = help_trans

            if hasattr(cls._fields[field], 'selection'):
                if isinstance(cls._fields[field].selection, (tuple, list)):
                    sel = copy.copy(cls._fields[field].selection)
                    if (Transaction().context.get('language')
                            and ((hasattr(cls._fields[field],
                                        'translate_selection')
                                    and cls._fields[field].translate_selection)
                                or not hasattr(cls._fields[field],
                                    'translate_selection'))):
                        # translate each selection option
                        sel2 = []
                        for (key, val) in sel:
                            val2 = Translation.get_source(
                                cls.__name__ + ',' + field, 'selection',
                                language, val)
                            sel2.append((key, val2 or val))
                        sel = sel2
                    res[field]['selection'] = sel
                else:
                    # call the 'dynamic selection' function
                    res[field]['selection'] = copy.copy(
                            cls._fields[field].selection)
            if res[field]['type'] in (
                    'one2many',
                    'many2many',
                    'many2one',
                    'one2one',
                    ):
                if hasattr(cls._fields[field], 'model_name'):
                    relation = copy.copy(cls._fields[field].model_name)
                else:
                    relation = copy.copy(
                        cls._fields[field].get_target().__name__)
                res[field]['relation'] = relation
                res[field]['domain'] = copy.copy(cls._fields[field].domain)
                res[field]['context'] = copy.copy(cls._fields[field].context)
                res[field]['create'] = accesses.get(field, {}).get('create',
                    True)
                res[field]['delete'] = accesses.get(field, {}).get('delete',
                    True)
            if res[field]['type'] == 'one2many' \
                    and hasattr(cls._fields[field], 'field'):
                res[field]['relation_field'] = copy.copy(
                        cls._fields[field].field)
            if res[field]['type'] in ('datetime', 'time'):
                res[field]['format'] = copy.copy(cls._fields[field].format)
            if res[field]['type'] == 'selection':
                res[field]['context'] = copy.copy(cls._fields[field].context)
            if res[field]['type'] == 'dict':
                res[field]['schema_model'] = cls._fields[field].schema_model
                res[field]['domain'] = copy.copy(cls._fields[field].domain)
                res[field]['context'] = copy.copy(cls._fields[field].context)
                res[field]['create'] = accesses.get(field, {}).get('create',
                    True)
                res[field]['delete'] = accesses.get(field, {}).get('delete',
                    True)

            # convert attributes into pyson
            for attr in ('states', 'domain', 'context', 'digits', 'size',
                    'add_remove', 'format'):
                if attr in res[field]:
                    res[field][attr] = encoder.encode(res[field][attr])

        if fields_names:
            # filter out fields which aren't in the fields_names list
            for i in res.keys():
                if i not in fields_names:
                    del res[i]
        return res
Example #37
0
 def definition(self, model, language):
     encoder = PYSONEncoder()
     definition = super().definition(model, language)
     definition['format'] = encoder.encode(self.format)
     return definition
Example #38
0
    def fields_get(cls, fields_names=None):
        """
        Return the definition of each field on the model.
        """
        res = {}
        pool = Pool()
        Translation = pool.get('ir.translation')
        FieldAccess = pool.get('ir.model.field.access')
        ModelAccess = pool.get('ir.model.access')

        # Add translation to cache
        language = Transaction().language
        trans_args = []
        for field in (x for x in cls._fields.keys()
                      if ((not fields_names) or x in fields_names)):
            trans_args.append(
                (cls.__name__ + ',' + field, 'field', language, None))
            trans_args.append(
                (cls.__name__ + ',' + field, 'help', language, None))
            if hasattr(cls._fields[field], 'selection'):
                if (isinstance(cls._fields[field].selection, (tuple, list)) and
                    ((hasattr(cls._fields[field], 'translate_selection')
                      and cls._fields[field].translate_selection) or
                     not hasattr(cls._fields[field], 'translate_selection'))):
                    sel = cls._fields[field].selection
                    for (key, val) in sel:
                        trans_args.append((cls.__name__ + ',' + field,
                                           'selection', language, val))
        Translation.get_sources(trans_args)

        encoder = PYSONEncoder()

        accesses = FieldAccess.get_access([cls.__name__])[cls.__name__]
        for field in (x for x in cls._fields.keys()
                      if ((not fields_names) or x in fields_names)):
            res[field] = {
                'type': cls._fields[field]._type,
                'name': field,
            }
            for arg in (
                    'string',
                    'readonly',
                    'states',
                    'size',
                    'required',
                    'translate',
                    'help',
                    'select',
                    'on_change',
                    'add_remove',
                    'on_change_with',
                    'autocomplete',
                    'sort',
                    'datetime_field',
                    'loading',
                    'filename',
                    'selection_change_with',
                    'domain',
                    'converter',
            ):
                if getattr(cls._fields[field], arg, None) is not None:
                    value = getattr(cls._fields[field], arg)
                    if isinstance(value, set):
                        value = list(value)
                    else:
                        value = copy.copy(value)
                    res[field][arg] = value
            if not accesses.get(field, {}).get('write', True):
                res[field]['readonly'] = True
                if res[field].get('states') and \
                        'readonly' in res[field]['states']:
                    del res[field]['states']['readonly']
            for arg in ('digits', 'invisible'):
                if hasattr(cls._fields[field], arg) \
                        and getattr(cls._fields[field], arg):
                    res[field][arg] = copy.copy(
                        getattr(cls._fields[field], arg))
            if (isinstance(
                    cls._fields[field],
                (fields.Function, fields.One2Many, fields.Many2Many))
                    and not getattr(cls, 'order_%s' % field, None)):
                res[field]['sortable'] = False
            if ((isinstance(cls._fields[field], fields.Function)
                 and not (cls._fields[field].searcher
                          or getattr(cls, 'domain_%s' % field, None)))
                    or (cls._fields[field]._type in ('binary', 'sha'))):
                res[field]['searchable'] = False
            else:
                res[field]['searchable'] = True

            if Transaction().context.get('language'):
                # translate the field label
                res_trans = Translation.get_source(
                    cls.__name__ + ',' + field, 'field',
                    Transaction().context['language'])
                if res_trans:
                    res[field]['string'] = res_trans
                help_trans = Translation.get_source(
                    cls.__name__ + ',' + field, 'help',
                    Transaction().context['language'])
                if help_trans:
                    res[field]['help'] = help_trans

            if hasattr(cls._fields[field], 'selection'):
                if isinstance(cls._fields[field].selection, (tuple, list)):
                    sel = copy.copy(cls._fields[field].selection)
                    if (Transaction().context.get('language') and
                        ((hasattr(cls._fields[field], 'translate_selection')
                          and cls._fields[field].translate_selection)
                         or not hasattr(cls._fields[field],
                                        'translate_selection'))):
                        # translate each selection option
                        sel2 = []
                        for (key, val) in sel:
                            val2 = Translation.get_source(
                                cls.__name__ + ',' + field, 'selection',
                                language, val)
                            sel2.append((key, val2 or val))
                        sel = sel2
                    res[field]['selection'] = sel
                else:
                    # call the 'dynamic selection' function
                    res[field]['selection'] = copy.copy(
                        cls._fields[field].selection)
            if res[field]['type'] in (
                    'one2many',
                    'many2many',
                    'many2one',
                    'one2one',
            ):
                if hasattr(cls._fields[field], 'model_name'):
                    relation = copy.copy(cls._fields[field].model_name)
                else:
                    relation = copy.copy(
                        cls._fields[field].get_target().__name__)
                res[field]['relation'] = relation
                res[field]['context'] = copy.copy(cls._fields[field].context)
                res[field]['create'] = accesses.get(field,
                                                    {}).get('create', True)
                res[field]['delete'] = accesses.get(field,
                                                    {}).get('delete', True)
            if res[field]['type'] == 'one2many' \
                    and getattr(cls._fields[field], 'field', None):
                res[field]['relation_field'] = copy.copy(
                    cls._fields[field].field)
            if res[field]['type'] == 'many2one':
                target = cls._fields[field].get_target()
                relation_fields = []
                for target_name, target_field in target._fields.iteritems():
                    if (target_field._type == 'one2many'
                            and target_field.model_name == cls.__name__
                            and target_field.field == field):
                        relation_fields.append(target_name)
                # Set relation_field only if there is no ambiguity
                if len(relation_fields) == 1:
                    res[field]['relation_field'], = relation_fields
            if res[field]['type'] in ('datetime', 'time'):
                res[field]['format'] = copy.copy(cls._fields[field].format)
            if res[field]['type'] == 'selection':
                res[field]['context'] = copy.copy(cls._fields[field].context)
            if res[field]['type'] == 'dict':
                res[field]['schema_model'] = cls._fields[field].schema_model
                res[field]['domain'] = copy.copy(cls._fields[field].domain)
                res[field]['context'] = copy.copy(cls._fields[field].context)
                res[field]['create'] = accesses.get(field,
                                                    {}).get('create', True)
                res[field]['delete'] = accesses.get(field,
                                                    {}).get('delete', True)
            filter_ = getattr(cls._fields[field], 'filter', None)
            if filter_:
                res[field]['domain'] = ['AND', res[field]['domain'], filter_]

            # convert attributes into pyson
            for attr in ('states', 'domain', 'context', 'digits', 'size',
                         'add_remove', 'format'):
                if attr in res[field]:
                    res[field][attr] = encoder.encode(res[field][attr])

        for i in res.keys():
            # filter out fields which aren't in the fields_names list
            if fields_names:
                if i not in fields_names:
                    del res[i]
            elif not ModelAccess.check_relation(cls.__name__, i, mode='read'):
                del res[i]
        return res
Example #39
0
    def _view_look_dom_arch(cls, tree, type, field_children=None):
        pool = Pool()
        ModelAccess = pool.get('ir.model.access')
        FieldAccess = pool.get('ir.model.field.access')

        encoder = PYSONEncoder()
        for xpath, attribute, value in cls.view_attributes():
            for element in tree.xpath(xpath):
                element.set(attribute, encoder.encode(value))

        fields_width = {}
        tree_root = tree.getroottree().getroot()

        # Find field without read access
        fread_accesses = FieldAccess.check(cls.__name__,
                                           list(cls._fields.keys()),
                                           'read',
                                           access=True)
        fields_to_remove = set(x for x, y in fread_accesses.items() if not y)

        # Find relation field without read access
        for name, field in cls._fields.items():
            if not ModelAccess.check_relation(cls.__name__, name, mode='read'):
                fields_to_remove.add(name)

        checked = set()
        while checked < fields_to_remove:
            to_check = fields_to_remove - checked
            for name, field in cls._fields.items():
                for field_to_remove in to_check:
                    if field_to_remove in field.depends:
                        fields_to_remove.add(name)
            checked |= to_check

        buttons_to_remove = set()
        for name, definition in cls._buttons.items():
            if fields_to_remove & set(definition.get('depends', [])):
                buttons_to_remove.add(name)

        field_xpath = (
            '//field[@name="%(name)s"]'
            '| //label[@name="%(name)s"] | //page[@name="%(name)s"]'
            '| //group[@name="%(name)s"] | //separator[@name="%(name)s"]')
        button_xpath = '//button[@name="%(name)s"]'
        # Remove field and button without read acces
        for xpath, names in (
            (field_xpath, fields_to_remove),
            (button_xpath, buttons_to_remove),
        ):
            for name in names:
                path = xpath % {'name': name}
                for i, element in enumerate(tree.xpath(path)):
                    if type == 'tree' or element.tag == 'page':
                        parent = element.getparent()
                        parent.remove(element)
                    elif type == 'form':
                        element.tag = 'label'
                        colspan = element.attrib.get('colspan')
                        element.attrib.clear()
                        element.attrib['id'] = 'hidden %s-%s' % (name, i)
                        if colspan is not None:
                            element.attrib['colspan'] = colspan

        # Remove empty pages
        if type == 'form':
            for page in tree.xpath('//page[not(descendant::*)]'):
                page.getparent().remove(page)

        if type == 'tree':
            ViewTreeWidth = pool.get('ir.ui.view_tree_width')
            viewtreewidth_ids = ViewTreeWidth.search([
                ('model', '=', cls.__name__),
                ('user', '=', Transaction().user),
            ])
            for viewtreewidth in ViewTreeWidth.browse(viewtreewidth_ids):
                if viewtreewidth.width > 0:
                    fields_width[viewtreewidth.field] = viewtreewidth.width

        fields_def = cls.__view_look_dom(tree_root,
                                         type,
                                         fields_width=fields_width)

        if hasattr(cls, 'active'):
            fields_def.setdefault('active', {'name': 'active'})

        if field_children:
            fields_def.setdefault(field_children, {'name': field_children})
            if field_children in cls._fields:
                field = cls._fields[field_children]
                if hasattr(field, 'field'):
                    fields_def.setdefault(field.field, {'name': field.field})

        for field_name in list(fields_def.keys()):
            if field_name in cls._fields:
                field = cls._fields[field_name]
            else:
                continue
            for depend in field.depends:
                fields_def.setdefault(depend, {'name': depend})

        arch = etree.tostring(tree, encoding='utf-8',
                              pretty_print=False).decode('utf-8')
        # Do not call fields_def without fields as it returns all fields
        if fields_def:
            fields2 = cls.fields_get(list(fields_def.keys()))
        else:
            fields2 = {}
        for field in fields_def:
            if field in fields2:
                fields2[field].update(fields_def[field])
        return arch, fields2
Example #40
0
    def __view_look_dom(cls, element, type, fields_width=None,
            fields_attrs=None):
        pool = Pool()
        Translation = pool.get('ir.translation')
        ModelData = pool.get('ir.model.data')
        Button = pool.get('ir.model.button')
        User = pool.get('res.user')

        if fields_width is None:
            fields_width = {}
        if not fields_attrs:
            fields_attrs = {}
        else:
            fields_attrs = copy.deepcopy(fields_attrs)
        childs = True

        if element.tag in ('field', 'label', 'separator', 'group', 'suffix',
                'prefix'):
            for attr in ('name', 'icon', 'geometry'):
                if element.get(attr):
                    fields_attrs.setdefault(element.get(attr), {})
                    try:
                        field = cls._fields[element.get(attr)]
                        if hasattr(field, 'model_name'):
                            relation = field.model_name
                        else:
                            relation = field.get_target().__name__
                    except Exception:
                        relation = False
                    if relation and element.tag == 'field':
                        childs = False
                        views = {}
                        mode = (element.attrib.pop('mode', None)
                            or 'tree,form').split(',')
                        view_ids = []
                        if element.get('view_ids'):
                            for view_id in element.get('view_ids').split(','):
                                try:
                                    view_ids.append(int(view_id))
                                except ValueError:
                                    view_ids.append(ModelData.get_id(
                                            *view_id.split('.')))
                        Relation = pool.get(relation)
                        if (not len(element)
                                and type == 'form'
                                and field._type in ('one2many', 'many2many')):
                            # Prefetch only the first view to prevent infinite
                            # loop
                            if view_ids:
                                for view_id in view_ids:
                                    view = Relation.fields_view_get(
                                        view_id=view_id)
                                    views[str(view_id)] = view
                                    break
                            else:
                                for view_type in mode:
                                    views[view_type] = \
                                        Relation.fields_view_get(
                                            view_type=view_type)
                                    break
                        element.attrib['mode'] = ','.join(mode)
                        element.attrib['view_ids'] = ','.join(
                            map(str, view_ids))
                        fields_attrs[element.get(attr)].setdefault('views', {}
                            ).update(views)
            if element.get('name') in fields_width:
                element.set('width', str(fields_width[element.get('name')]))

        # convert attributes into pyson
        encoder = PYSONEncoder()
        for attr in ('states', 'domain', 'spell', 'colors'):
            if element.get(attr):
                element.set(attr, encoder.encode(safe_eval(element.get(attr),
                    CONTEXT)))

        if element.tag == 'button':
            button_name = element.attrib['name']
            if button_name in cls._buttons:
                states = cls._buttons[button_name]
            else:
                states = {}
            groups = set(User.get_groups())
            button_groups = Button.get_groups(cls.__name__, button_name)
            if button_groups and not groups & button_groups:
                states = states.copy()
                states['readonly'] = True
            element.set('states', encoder.encode(states))

        # translate view
        if Transaction().language != 'en_US':
            for attr in ('string', 'sum', 'confirm', 'help'):
                if element.get(attr):
                    trans = Translation.get_source(cls.__name__, 'view',
                            Transaction().language, element.get(attr))
                    if trans:
                        element.set(attr, trans)

        # Set header string
        if element.tag in ('form', 'tree', 'graph'):
            element.set('string', cls.view_header_get(
                element.get('string') or '', view_type=element.tag))

        if element.tag == 'tree' and element.get('sequence'):
            fields_attrs.setdefault(element.get('sequence'), {})

        if childs:
            for field in element:
                fields_attrs = cls.__view_look_dom(field, type,
                    fields_width=fields_width, fields_attrs=fields_attrs)
        return fields_attrs
    def __view_look_dom(self, element, type, fields_width=None):
        pool = Pool()
        translation_obj = pool.get("ir.translation")
        model_data_obj = pool.get("ir.model.data")
        button_obj = pool.get("ir.model.button")
        user_obj = pool.get("res.user")

        if fields_width is None:
            fields_width = {}
        fields_attrs = {}
        childs = True

        if element.tag in ("field", "label", "separator", "group"):
            for attr in ("name", "icon"):
                if element.get(attr):
                    attrs = {}
                    try:
                        if element.get(attr) in self._columns:
                            field = self._columns[element.get(attr)]
                        else:
                            field = self._inherit_fields[element.get(attr)][2]
                        if hasattr(field, "model_name"):
                            relation = field.model_name
                        else:
                            relation = field.get_target()._name
                    except Exception:
                        relation = False
                    if relation and element.tag == "field":
                        childs = False
                        views = {}
                        mode = (element.attrib.pop("mode", None) or "tree,form").split(",")
                        view_ids = []
                        if element.get("view_ids"):
                            for view_id in element.get("view_ids").split(","):
                                try:
                                    view_ids.append(int(view_id))
                                except ValueError:
                                    view_ids.append(model_data_obj.get_id(*view_id.split(".")))
                        relation_obj = pool.get(relation)
                        if not len(element) and type == "form" and field._type in ("one2many", "many2many"):
                            # Prefetch only the first view to prevent infinite
                            # loop
                            if view_ids:
                                for view_id in view_ids:
                                    view = relation_obj.fields_view_get(view_id=view_id)
                                    views[view["type"]] = view
                                    break
                            else:
                                for view_type in mode:
                                    views[view_type] = relation_obj.fields_view_get(view_type=view_type)
                                    break
                        element.attrib["mode"] = ",".join(mode)
                        element.attrib["view_ids"] = ",".join(map(str, view_ids))
                        attrs = {"views": views}
                    fields_attrs[element.get(attr)] = attrs
            if element.get("name") in fields_width:
                element.set("width", str(fields_width[element.get("name")]))

        # convert attributes into pyson
        encoder = PYSONEncoder()
        for attr in ("states", "domain", "context", "digits", "add_remove", "spell", "colors"):
            if element.get(attr):
                element.set(attr, encoder.encode(safe_eval(element.get(attr), CONTEXT)))

        if element.tag == "button":
            if element.get("type", "object") == "object":
                assert not element.get("states")
                button_name = element.attrib["name"]
                if button_name in self._buttons:
                    states = self._buttons[button_name]
                else:
                    states = {}
                groups = set(user_obj.get_groups())
                button_groups = button_obj.get_groups(self._name, button_name)
                if button_groups and not groups & button_groups:
                    states = states.copy()
                    states["readonly"] = True
                element.set("states", encoder.encode(states))

        # translate view
        if Transaction().language != "en_US":
            for attr in ("string", "sum", "confirm", "help"):
                if element.get(attr):
                    trans = translation_obj.get_source(self._name, "view", Transaction().language, element.get(attr))
                    if trans:
                        element.set(attr, trans)

        # Set header string
        if element.tag in ("form", "tree", "graph"):
            element.set("string", self.view_header_get(element.get("string") or "", view_type=element.tag))

        if element.tag == "tree" and element.get("sequence"):
            fields_attrs.setdefault(element.get("sequence"), {})

        if childs:
            for field in element:
                fields_attrs.update(self.__view_look_dom(field, type, fields_width=fields_width))
        return fields_attrs