from odoo import api, fields, models from odoo.exceptions import ValidationError import pandas as pd import os import base64 class ImportLayput(models.TransientModel): _name = 'import.layout' _description = 'Importación de layout' _rec_name = "rule_id" rule_id = fields.Many2one(comodel_name="import.layout.rule", string="Plantilla") file_data = fields.Binary(string="Archivo") file_name = fields.Char(string="Nombre del archivo") company_id = fields.Many2one(comodel_name="res.company", string="Empresa", default=lambda self: self.env.company) def read_excel(self): # Validar la extensión self.extension_validator(self.file_name) # Validar que se cargue el modelo correspondiente al menú self.validate_model_id() # Lectura del excel data_decode = base64.b64decode(self.file_data) df = pd.read_excel(data_decode) group_line_id = self.rule_id.main_columns_ids.filtered(lambda line: line.group_by) df_group_by = df.groupby(group_line_id.name) move_ids = self.get_data(df_group_by) if move_ids: return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'type': 'success', 'message': (f'Se crearon los siguientes movimientos {move_ids}.'), 'next': {'type': 'ir.actions.act_window_close'}, } } def validate_model_id(self): if self.env.context.get("sale_import") and self.sudo().rule_id.main_model_id.model not in ("sale.order", "purchase.order", "account.move"): raise ValidationError("Es necesario asignar una regla relacionada al modelo seleccionado") def extension_validator(self, file_name): name, extension = os.path.splitext(file_name) valid = True if str(extension).upper() == '.XLSX' or str(extension).upper() == '.XLS' else False if not valid: raise ValidationError( "La extensión del archivo no es valida con el formato de excel, esta debe ser .xlsx o xls") def get_data(self, df): try: main_name = [] for ciudad, grupo in df: main_data = dict() data_list = [] # Obtencion de los datos del cabecero for column in self.rule_id.main_columns_ids: value = self.get_field_info(column.field_id, grupo.loc[grupo.index[0], column.name]) main_data[f"{column.field_id.name}"] = value # Creación del cabecero if main_data: main_id = self.env[self.rule_id.main_model_id.model].sudo().create(main_data) main_name.append(main_id.name) # Obtenciónd de los datos de las lineas de la orden for line_index in range(grupo.shape[0]): data = {} for column in self.rule_id.column_ids: value = self.get_field_info(column.field_id, grupo.loc[grupo.index[line_index], column.name]) data[f"{column.field_id.name}"] = value main_field = self.env[self.rule_id.model_id.model].fields_get() related_field = next((campo for campo, datos in main_field.items() if datos.get('relation') == f'{self.rule_id.main_model_id.model}'), None) # Relación de las lineas con su llave primaria data[f"{related_field}"] = main_id.id if data: data_list.append(data) # Creación de las lineas de las ordenes if data_list: line_ids = self.env[self.rule_id.model_id.model].sudo().create(data_list) return main_name if main_name else False except Exception as e: raise ValidationError( f"Hay algun problema con la configuración de la regla, posiblemente el nombre de las columnas no coincidan con el archivo, como por ejemplo: {e}") # Obtener los valores de los campos dependiendo del tipo de campo def get_field_info(self, field_id, value): if field_id.ttype in ["many2one", "many2one_reference"]: if str(value).isnumeric(): if len(str(value)) <= 9: field_value = self.env[field_id.relation].sudo().search([("id", "=", int(value))], limit=1) else: field_value = False if not field_value and field_id.relation in ['product.product', 'product.template']: field_value = self.env[field_id.relation].sudo().search(["|",("default_code", "=", value),("barcode","=",value)], limit=1) if not field_value: raise ValidationError( f"No se encontro un registro en el modelo de {field_id.relation} con el id {value}") elif not field_value: raise ValidationError( f"No se encontro un registro en el modelo de {field_id.relation} con el código {value}") value = field_value.id elif field_id.relation in ['product.product', 'product.template']: field_value = self.env[field_id.relation].sudo().search(["|",("default_code", "=", value),("barcode","=",value)], limit=1) if not field_value: field_value = self.env[field_id.relation].sudo().search([("name", "=", value)], limit=1) if not field_value: raise ValidationError( f"No se encontro un registro en el modelo de {field_id.relation} con el código {value}") value = field_value.id else: field_value = self.env[field_id.relation].sudo().search([("name", "=", value)], limit=1) if not field_value: raise ValidationError( f"No se encontro un registro en el modelo de {field_id.relation} con el nombre {value}") value = field_value.id return value