|
|
@@ -0,0 +1,129 @@
|
|
|
+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 != "sale.order":
|
|
|
+ raise ValidationError("Es necesario asignar una regla relacionada a las ordenes de venta.")
|
|
|
+ elif self.env.context.get("purchase_import") and self.sudo().rule_id.main_model_id.model != "purchase.order":
|
|
|
+ raise ValidationError("Es necesario asignar una regla relacionada a las ordenes de compra.")
|
|
|
+
|
|
|
+ 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
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|