def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): """ Override to set the `inventory_quantity` field if we're in "inventory mode" as well as to compute the sum of the `available_quantity` field. """ if 'available_quantity' in fields: if 'quantity' not in fields: fields.append('quantity') if 'reserved_quantity' not in fields: fields.append('reserved_quantity') result = super(StockQuant, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) for group in result: if self._is_inventory_mode(): group['inventory_quantity'] = group.get('quantity', 0) if 'available_quantity' in fields: group['available_quantity'] = group['quantity'] - group[ 'reserved_quantity'] return result
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): if all('on_time_rate' not in field for field in fields): res = super().read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) return res for field in fields: if 'on_time_rate' not in field: continue fields.remove(field) agg = field.split(':')[1:] if agg and agg[0] != 'sum': raise NotImplementedError('Aggregate functions other than \':sum\' are not allowed.') qty_total = field.replace('on_time_rate', 'qty_total') if qty_total not in fields: fields.append(qty_total) qty_on_time = field.replace('on_time_rate', 'qty_on_time') if qty_on_time not in fields: fields.append(qty_on_time) break res = super().read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) for group in res: if group['qty_total'] == 0: on_time_rate = 100 else: on_time_rate = group['qty_on_time'] / group['qty_total'] * 100 group.update({'on_time_rate': on_time_rate}) return res
def _generate_order_by(self, order_spec, query): ''' replace sort field, if sort by key. replace on sort by prefix, number ''' new_order_spec = order_spec if order_spec: fields = [] for order_part in order_spec.split(','): order_split = order_part.strip().split(' ') order_field = order_split[0].strip() order_direction = order_split[1].strip().upper() if len(order_split) == 2 else '' fields.append((order_field, order_direction)) key_field = [x for x in fields if x[0] == 'key'] if key_field: direction = key_field[0][1] fields.remove(key_field[0]) fields.extend([('prefix', direction), ('number', direction)]) fields = map(lambda x: ' '.join(x), fields) new_order_spec = ','.join(fields) order_by = super(Task, self)._generate_order_by(new_order_spec, query) return order_by
def get_allowed_items(self, params): fields = ['id', 'display_name', 'name'] is_project = False domain = [('name', 'ilike', params['search'])] if params['model'] == 'project.project': fields.append('privacy_visibility') fields.append('message_is_follower') is_project = True if len(self.env['ir.model.fields'].search([ ('model', '=', params['model']), ('name', '=', 'display_name'), ('store', '=', True) ])): domain = [('display_name', 'ilike', params['search'])] sr_items = self.env[params['model']].search_read(domain, fields, limit=10) allowed_items = [] for sr_i in sr_items: if is_project: # if sr_i['privacy_visibility'] != 'employees': if not sr_i['message_is_follower']: continue del sr_i['privacy_visibility'] del sr_i['message_is_follower'] allowed_items.append(sr_i) return allowed_items
def _address_fields(self): """ Returns the list of address fields that are synced from the parent when the `use_parent_address` flag is set. """ fields = super(ResPartner, self)._address_fields() fields.append('company') return fields
def search_panel_select_range(self, field_name): """ Return possible values of the field field_name (case select="one") and the parent field (if any) used to hierarchize them. :param field_name: the name of a many2one category field :return: { 'parent_field': parent field on the comodel of field, or False 'values': array of dictionaries containing some info on the records available on the comodel of the field 'field_name'. The display name (and possibly parent_field) are fetched. } """ field = self._fields[field_name] supported_types = ['many2one'] if field.type not in supported_types: raise UserError( _('Only types %(supported_types)s are supported for category (found type %(field_type)s)' ) % ({ 'supported_types': supported_types, 'field_type': field.type })) Comodel = self.env[field.comodel_name] fields = ['display_name'] parent_name = Comodel._parent_name if Comodel._parent_name in Comodel._fields else False if parent_name: fields.append(parent_name) return { 'parent_field': parent_name, 'values': Comodel.with_context(hierarchical_naming=False).search_read( [], fields), }
def read(self, fields=None, load='_classic_read'): if fields == [ 'name', 'sequence', 'parent_id', 'action', 'web_icon', 'web_icon_data' ]: fields.append('x_menu_category_id') return super(IrUiMenu, self).read(fields, load)
def read(self, fields=None, load='_classic_read'): """ Override to explicitely call check_access_rule, that is not called by the ORM. It instead directly fetches ir.rules and apply them. """ if fields and 'ks_msg_edit' not in fields: fields.append('ks_msg_edit') return super(KsChatDelete, self).read(fields=fields, load=load)
def _get_print_field(self): fields = [] static_properties_obj = self.env['product.properties.static'] dinamic_properties_obj = self.env['product.properties.category'] for categ in dinamic_properties_obj.search([]): for line in categ.lines_ids: for g in line.with_context(lang="en"): fields.append('print_' + g.name.name.lower().replace(" ", "_") + "_%d" % g.name.id) for record in self.print_properties: for g in filter( lambda r: r not in static_properties_obj.ignore_fields(), static_properties_obj.with_context(lang="en")._fields): setattr(self, 'print_' + g.lower().replace(" ", "_"), record.print) for field in fields: parts = field.split("_") if record.name == parts[1] and record.name.id == int(parts[2]): setattr(self, field, record.print) # @api.multi # def read(self, fields=None, load='_classic_read'): #static_properties_obj = self.env['product.properties.static'] #dinamic_properties_obj = self.env['product.properties.category'] #pfields = [] #for categ in dinamic_properties_obj.search([]): # for line in categ.lines_ids: # for g in line.with_context(lang="en"): # pfields.append('print_' + g.name.name.lower().replace(" ", "_")+"_%d" % g.name.id) #fields1 = fields or list(self.fields_get()) # #_logger.info("FIELDS %s" % list(self.fields_get())) other_fields = {}
def search_panel_select_range(self, field_name): """ Return possible values of the field field_name (case select="one") and the parent field (if any) used to hierarchize them. :param field_name: the name of a many2one category field :return: { 'parent_field': parent field on the comodel of field, or False 'values': array of dictionaries containing some info on the records available on the comodel of the field 'field_name'. The display name (and possibly parent_field) are fetched. } """ field = self._fields[field_name] supported_types = ['many2one'] if field.type not in supported_types: raise UserError(_('Only types %(supported_types)s are supported for category (found type %(field_type)s)') % ({ 'supported_types': supported_types, 'field_type': field.type})) Comodel = self.env[field.comodel_name] fields = ['display_name'] parent_name = Comodel._parent_name if Comodel._parent_name in Comodel._fields else False if parent_name: fields.append(parent_name) return { 'parent_field': parent_name, 'values': Comodel.with_context(hierarchical_naming=False).search_read([], fields), }
def _get_eshop_fields(self): fields = super()._get_eshop_fields() for field in fields: if "image" in field: fields.remove(field) fields.append("image_write_date") fields.append("image_write_date_hash") return fields
def default_get(self, fields): res = super(ResPartnerIdNumber, self).default_get(fields) # It seems to be a bug in native odoo that the field partner_id # is not in the fields list by default. A workaround is required # to force this. if "default_partner_id" in self._context and "partner_id" not in fields: fields.append("partner_id") res["partner_id"] = self._context.get("default_partner_id") return res
def onchange(self, values, field_name, field_onchange): """ Fix this issue https://github.com/ingadhoc/account-payment/issues/189 """ fields = [] for field in field_onchange.keys(): if field.startswith(('to_pay_move_line_ids.')): fields.append(field) for field in fields: del field_onchange[field] return super().onchange(values, field_name, field_onchange)
def _get_invoice_line_key_cols(self): fields = [ 'name', 'origin', 'discount', 'invoice_line_tax_ids', 'price_unit', 'product_id', 'account_id', 'account_analytic_id', 'uom_id', 'sale_line_ids' ] for field in ['analytics_id']: if field in self.env['account.invoice.line']._fields: fields.append(field) return fields
def _sms_get_partner_fields(self): """ This method returns the fields to use to find the contact to link whensending an SMS. Having partner is not necessary, having only phone number fields is possible. However it gives more flexibility to notifications management when having partners. """ fields = [] if hasattr(self, 'partner_id'): fields.append('partner_id') if hasattr(self, 'partner_ids'): fields.append('partner_ids') return fields
def onchange(self, values, field_name, field_onchange): """Necesitamos hacer esto porque los onchange que agregan lineas, cuando se va a guardar el registro, terminan creando registros. """ fields = [] for field in field_onchange.keys(): if field.startswith(('move_line_ids.')): fields.append(field) for field in fields: del field_onchange[field] return super().onchange(values, field_name, field_onchange)
def check_update_fields(self, vals): """this method is call from the write methods of selected model whose records is updated example: product.product and product.template""" if self.id: fields = [] for f in self.elastic_index_id.field_ids: fields.append(f.name) intersectionSet = set(vals).intersection(fields) else: intersectionSet = False return intersectionSet
def _convert_import_data(self, fields, options): data, fields = super(BaseImport, self)._convert_import_data(fields, options) if self._context.get('import_order_line'): import_field = options.get('import_field') order_id = options.get('order_id') if import_field and order_id: fields.append(import_field) for row in data: row.append(order_id) return data, fields
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None): if not fields: fields = [] fields.append('editable') return super(Meeting, self).search_read(domain, fields, offset, limit, order)
def _get_fields(self, fields=None, model=None): for field in model.field_id: if field.ttype != 'one2many': if field.is_report: fields.append(field.id) else: model = self.env['ir.model'].search( [('model', '=', field.relation)], limit=1) if model.is_report and field.relation != self.report_id.model_id.model: self._get_fields(fields=fields if fields else [], model=model) return fields
def get_cn23(self, record, values, package): article = [] for line in package.quant_ids: price = 1 if record.sale_id: price = record.env["sale.order.line"].search( [('order_id', '=', record.sale_id.id), ('product_id', '=', line.product_id.id)], limit=1).price_unit or line.product_id.lst_price product = { "description": line.product_id.name, "quantity": int(line.quantity), "weight": line.product_id.weight, "value": price, "hsCode": line.product_id.hs_code, # todo : gestion des pays origine "originCountry": 'FR', } article.append(product) cn23 = { "includeCustomsDeclarations": 1, "contents": { "article": article, "category": { "value": 3 } }, } values["letter"]["customsDeclarations"] = cn23 # set delivery price if not set if record.sale_id: delivery_price = record.get_delivery_price() values["letter"]["service"]["totalAmount"] = int(delivery_price * 100) values["letter"]["service"]["returnTypeChoice"] = 3 field = { 'key': 'EORI', 'value': record.env.company.phi_eori_number, } custom_fields = [] fields = [] custom_fields.append(field) fields.append(field) fields = { "customField": custom_fields, "field": custom_fields, } values["fields"] = fields return values
def _prepare_user_group_ids_from_default_get(self): ResGroups = self.env["res.groups"] ResUsers = self.env["res.users"] res1 = ResGroups.get_groups_by_application() fields = [] for item in res1: if item[1] == "boolean": for group in item[2]: fields.append(name_boolean_group(group.id)) elif item[1] == "selection": fields.append(name_selection_groups(item[2].ids)) res2 = ResUsers.default_get(fields) return res2["groups_id"][0][2]
def _prepare_user_group_ids_from_default_get(self): group_obj = self.env['res.groups'] user_obj = self.env['res.users'] res1 = group_obj.get_groups_by_application() fields = [] for item in res1: if item[1] == 'boolean': for group in item[2]: fields.append(name_boolean_group(group.id)) elif item[1] == 'selection': fields.append(name_selection_groups(item[2].ids)) res2 = user_obj.default_get(fields) return res2['groups_id'][0][2]
def _get_bindings(self, model_name, debug=False): """ Retrieve the list of actions bound to the given model. :return: a dict mapping binding types to a list of dict describing actions, where the latter is given by calling the method ``read`` on the action record. """ cr = self.env.cr IrModelAccess = self.env['ir.model.access'] # discard unauthorized actions, and read action definitions result = defaultdict(list) user_groups = self.env.user.groups_id if not debug: user_groups -= self.env.ref('base.group_no_one') self.flush() cr.execute( """ SELECT a.id, a.type, a.binding_type FROM ir_actions a JOIN ir_model m ON a.binding_model_id = m.id WHERE m.model = %s ORDER BY a.id """, [model_name]) for action_id, action_model, binding_type in cr.fetchall(): try: action = self.env[action_model].sudo().browse(action_id) action_groups = getattr(action, 'groups_id', ()) action_model = getattr(action, 'res_model', False) if action_groups and not action_groups & user_groups: # the user may not perform this action continue if action_model and not IrModelAccess.check( action_model, mode='read', raise_exception=False): # the user won't be able to read records continue fields = ['name', 'binding_view_types'] if 'sequence' in action._fields: fields.append('sequence') result[binding_type].append(action.read(fields)[0]) except (AccessError, MissingError): continue # sort actions by their sequence if sequence available if result.get('action'): result['action'] = sorted(result['action'], key=lambda vals: vals.get('sequence', 0)) return result
def _form_fieldsets(self): fields = [ { 'id': 'flyers', 'fields': ['flyer_number'] }, ] if not self.large_picture: fields.append({ 'id': 'picture', 'description': _( "Please upload a large image of good quality which " "will be used to be printed on your material."), 'fields': ['large_picture'] })
def find_field_belong_model(nodes): fields = [] for node in nodes: attr = {} if node.tag == 'field': attr.update(node.attrib) if node.find('tree'): attr.update(node.find('tree').attrib) fields.append(attr) continue if node.getchildren(): field = find_field_belong_model(node) fields.extend(field) continue return fields
def search_read(self, domain=None, fields=None, offset=0, limit=None, order=None): """ Performs a ``search()`` followed by a ``read()``. :param domain: Search domain, see ``args`` parameter in ``search()``. Defaults to an empty domain that will match all records. :param fields: List of fields to read, see ``fields`` parameter in ``read()``. Defaults to all fields. :param offset: Number of records to skip, see ``offset`` parameter in ``search()``. Defaults to 0. :param limit: Maximum number of records to return, see ``limit`` parameter in ``search()``. Defaults to no limit. :param order: Columns to sort result, see ``order`` parameter in ``search()``. Defaults to no sort. :return: List of dictionaries containing the asked fields. :rtype: List of dictionaries. """ records = self.search(domain or [], offset=offset, limit=limit, order=order) if not records: return [] if fields and fields == ['id']: # shortcut read if we only want the ids return [{'id': record.id} for record in records] # read() ignores active_test, but it would forward it to any downstream search call # (e.g. for x2m or function fields), and this is not the desired behavior, the flag # was presumably only meant for the main search(). # TODO: Move this to read() directly? if 'active_test' in self._context: context = dict(self._context) del context['active_test'] records = records.with_context(context) fields.append('editable') result = records.read(fields) if len(result) <= 1: return result # reorder read index = {vals['id']: vals for vals in result} return [index[record.id] for record in records if record.id in index]
def _form_fieldsets(self): fields = [ { "id": "flyers", "fields": ["flyer_number", "form_id"] }, ] if not self.large_picture: fields.append({ "id": "picture", "description": _("Please upload a large image of good quality which " "will be used to be printed on your material."), "fields": ["large_picture"], }) return fields
def yodlee_add_update_provider_account(self, values, site_id, name=None): # Setting values entered by user into json fields = [] if type(values) != list: # most call to /providerAccounts only needs a dict with id, value keys # only exception is for type: questionAndAnswer which require a special format # the case is handle in javascript and js pass a dict as values instead of a list # in that particular case data = json.dumps({'loginForm': values}) else: for element in values: if element.get('required', True) == 'false' and element['value'] == '': raise UserError(_('Please fill all required fields')) if element['value'] != '': fields.append({'id': element['field_id'], 'value': element['value']}) data = json.dumps({'field': fields}) if len(fields) > 0 else [] params = {'providerId': site_id} # If we have an id, it means that provider_account already exists and that it is an update if len(self) > 0 and self.id: params = {'providerAccountIds': self.provider_account_identifier} resp_json = self.yodlee_fetch('/providerAccounts', params, data, 'PUT') return self.id else: resp_json = self.yodlee_fetch('/providerAccounts', params, data, 'POST') refresh_info = resp_json.get('providerAccount', {}).get('refreshInfo') provider_account_identifier = resp_json.get('providerAccount', {}).get('id') vals = {'name': name or 'Online institution', 'provider_account_identifier': provider_account_identifier, 'provider_identifier': site_id, 'status': refresh_info.get('status'), 'yodlee_additional_status': refresh_info.get('additionalStatus'), 'status_code': refresh_info.get('statusCode'), 'message': refresh_info.get('statusMessage'), 'action_required': refresh_info.get('actionRequired', False), 'last_refresh': self.convert_date_from_yodlee(refresh_info.get('lastRefreshed')), 'yodlee_last_attempted_refresh': self.convert_date_from_yodlee(refresh_info.get('lastRefreshAttempt')), 'provider_type': 'yodlee', } # We create a new object if there isn't one with the same provider_account_identifier new_provider_account = self.search([('provider_account_identifier', '=', provider_account_identifier), ('company_id', '=', self.env.user.company_id.id)], limit=1) if len(new_provider_account) == 0: with self.pool.cursor() as cr: new_provider_account = self.with_env(self.env(cr=cr)).create(vals) return new_provider_account.id
def import_order_line_data(self): product_tmpl_obj = self.env['product.template'] order_line_obj = self.env['purchase.order.line'] product_obj = self.env['product.product'] if self.import_option == 'csv': data = base64.b64decode(self.file) file_input = cStringIO.StringIO(data) file_input.seek(0) reader = csv.reader(file_input, delimiter=',', lineterminator='\r\n') reader_info = [] try: reader_info.extend(reader) except Exception: raise exceptions.Warning(_("Not a valid file!")) fields = [] for i in range(1, len(reader_info)): try: field = map(str, reader_info[i]) fields.append(field) except ValueError: raise exceptions.Warning( _("Dont Use Character only use numbers")) self.create_order_line(fields, product_tmpl_obj, order_line_obj, product_obj) else: fp = tempfile.NamedTemporaryFile(suffix=".xlsx") fp.write(binascii.a2b_base64(self.file)) fp.seek(0) workbook = xlrd.open_workbook(fp.name) sheet = workbook.sheet_by_index(0) fields = [] for row_no in range(1, sheet.nrows): # print ".........row_no ", row_no field = map(lambda row: row.value, sheet.row(row_no)) if field: fields.append(field) self.create_order_line(fields, product_tmpl_obj, order_line_obj, product_obj)
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True): if 'on_time_rate' not in fields: res = super().read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) return res fields.remove('on_time_rate') if 'qty_total' not in fields: fields.append('qty_total') if 'qty_on_time' not in fields: fields.append('qty_on_time') res = super().read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy) for group in res: if group['qty_total'] == 0: on_time_rate = 100 else: on_time_rate = group['qty_on_time'] / group['qty_total'] * 100 group.update({'on_time_rate': on_time_rate}) return res
def products_autocomplete(self, term, options={}, **kwargs): """ Returns list of products according to the term and product options Params: term (str): search term written by the user options (dict) - 'limit' (int), default to 5: number of products to consider - 'display_description' (bool), default to True - 'display_price' (bool), default to True - 'order' (str) - 'max_nb_chars' (int): max number of characters for the description if returned Returns: dict (or False if no result) - 'products' (list): products (only their needed field values) note: the prices will be strings properly formatted and already containing the currency - 'products_count' (int): the number of products in the database that matched the search query """ ProductTemplate = request.env['product.template'] display_description = options.get('display_description', True) display_price = options.get('display_price', True) order = self._get_search_order(options) max_nb_chars = options.get('max_nb_chars', 999) category = options.get('category') attrib_values = options.get('attrib_values') domain = self._get_search_domain(term, category, attrib_values, display_description) products = ProductTemplate.search( domain, limit=min(20, options.get('limit', 5)), order=order ) fields = ['id', 'name', 'website_url'] if display_description: fields.append('description_sale') res = { 'products': products.read(fields), 'products_count': ProductTemplate.search_count(domain), } if display_description: for res_product in res['products']: desc = res_product['description_sale'] if desc and len(desc) > max_nb_chars: res_product['description_sale'] = "%s..." % desc[:(max_nb_chars - 3)] if display_price: FieldMonetary = request.env['ir.qweb.field.monetary'] monetary_options = { 'display_currency': request.website.get_current_pricelist().currency_id, } for res_product, product in zip(res['products'], products): combination_info = product._get_combination_info(only_template=True) res_product.update(combination_info) res_product['list_price'] = FieldMonetary.value_to_html(res_product['list_price'], monetary_options) res_product['price'] = FieldMonetary.value_to_html(res_product['price'], monetary_options) return res