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
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
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, {}
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
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, {}
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, {}
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, {}
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
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
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
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
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], }
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
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
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, {}
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, {}
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
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, {}
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
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
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)
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
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
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
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
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
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
def definition(self, model, language): encoder = PYSONEncoder() definition = super().definition(model, language) definition['digits'] = encoder.encode(self.digits) return definition
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
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
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
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
def get_pyson_menu(self, name): encoder = PYSONEncoder() return encoder.encode(self.menu.get_action_value())
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
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
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
def definition(self, model, language): encoder = PYSONEncoder() definition = super().definition(model, language) definition['format'] = encoder.encode(self.format) return definition
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
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
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