import_layout.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. from odoo import api, fields, models
  2. from odoo.exceptions import ValidationError
  3. import pandas as pd
  4. import os
  5. import base64
  6. class ImportLayput(models.TransientModel):
  7. _name = 'import.layout'
  8. _description = 'Importación de layout'
  9. _rec_name = "rule_id"
  10. rule_id = fields.Many2one(comodel_name="import.layout.rule", string="Plantilla")
  11. file_data = fields.Binary(string="Archivo")
  12. file_name = fields.Char(string="Nombre del archivo")
  13. company_id = fields.Many2one(comodel_name="res.company", string="Empresa", default=lambda self: self.env.company)
  14. def read_excel(self):
  15. # Validar la extensión
  16. self.extension_validator(self.file_name)
  17. # Validar que se cargue el modelo correspondiente al menú
  18. self.validate_model_id()
  19. # Lectura del excel
  20. data_decode = base64.b64decode(self.file_data)
  21. df = pd.read_excel(data_decode)
  22. group_line_id = self.rule_id.main_columns_ids.filtered(lambda line: line.group_by)
  23. df_group_by = df.groupby(group_line_id.name)
  24. move_ids = self.get_data(df_group_by)
  25. if move_ids:
  26. return {
  27. 'type': 'ir.actions.client',
  28. 'tag': 'display_notification',
  29. 'params': {
  30. 'type': 'success',
  31. 'message': (f'Se crearon los siguientes movimientos {move_ids}.'),
  32. 'next': {'type': 'ir.actions.act_window_close'},
  33. }
  34. }
  35. def validate_model_id(self):
  36. if self.env.context.get("sale_import") and self.sudo().rule_id.main_model_id.model not in ("sale.order", "purchase.order", "account.move"):
  37. raise ValidationError("Es necesario asignar una regla relacionada al modelo seleccionado")
  38. def extension_validator(self, file_name):
  39. name, extension = os.path.splitext(file_name)
  40. valid = True if str(extension).upper() == '.XLSX' or str(extension).upper() == '.XLS' else False
  41. if not valid:
  42. raise ValidationError(
  43. "La extensión del archivo no es valida con el formato de excel, esta debe ser .xlsx o xls")
  44. def get_data(self, df):
  45. try:
  46. main_name = []
  47. for ciudad, grupo in df:
  48. main_data = dict()
  49. data_list = []
  50. # Obtencion de los datos del cabecero
  51. for column in self.rule_id.main_columns_ids:
  52. value = self.get_field_info(column.field_id, grupo.loc[grupo.index[0], column.name])
  53. main_data[f"{column.field_id.name}"] = value
  54. # Creación del cabecero
  55. if main_data:
  56. main_id = self.env[self.rule_id.main_model_id.model].sudo().create(main_data)
  57. main_name.append(main_id.name)
  58. # Obtenciónd de los datos de las lineas de la orden
  59. for line_index in range(grupo.shape[0]):
  60. data = {}
  61. for column in self.rule_id.column_ids:
  62. value = self.get_field_info(column.field_id,
  63. grupo.loc[grupo.index[line_index], column.name])
  64. data[f"{column.field_id.name}"] = value
  65. main_field = self.env[self.rule_id.model_id.model].fields_get()
  66. related_field = next((campo for campo, datos in main_field.items() if
  67. datos.get('relation') == f'{self.rule_id.main_model_id.model}'), None)
  68. # Relación de las lineas con su llave primaria
  69. data[f"{related_field}"] = main_id.id
  70. if data:
  71. data_list.append(data)
  72. # Creación de las lineas de las ordenes
  73. if data_list:
  74. line_ids = self.env[self.rule_id.model_id.model].sudo().create(data_list)
  75. return main_name if main_name else False
  76. except Exception as e:
  77. raise ValidationError(
  78. 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}")
  79. # Obtener los valores de los campos dependiendo del tipo de campo
  80. def get_field_info(self, field_id, value):
  81. if field_id.ttype in ["many2one", "many2one_reference"]:
  82. if str(value).isnumeric():
  83. if len(str(value)) <= 9:
  84. field_value = self.env[field_id.relation].sudo().search([("id", "=", int(value))], limit=1)
  85. else:
  86. field_value = False
  87. if not field_value and field_id.relation in ['product.product', 'product.template']:
  88. field_value = self.env[field_id.relation].sudo().search(["|",("default_code", "=", value),("barcode","=",value)], limit=1)
  89. if not field_value:
  90. raise ValidationError(
  91. f"No se encontro un registro en el modelo de {field_id.relation} con el id {value}")
  92. elif not field_value:
  93. raise ValidationError(
  94. f"No se encontro un registro en el modelo de {field_id.relation} con el código {value}")
  95. value = field_value.id
  96. elif field_id.relation in ['product.product', 'product.template']:
  97. field_value = self.env[field_id.relation].sudo().search(["|",("default_code", "=", value),("barcode","=",value)], limit=1)
  98. if not field_value:
  99. field_value = self.env[field_id.relation].sudo().search([("name", "=", value)], limit=1)
  100. if not field_value:
  101. raise ValidationError(
  102. f"No se encontro un registro en el modelo de {field_id.relation} con el código {value}")
  103. value = field_value.id
  104. else:
  105. field_value = self.env[field_id.relation].sudo().search([("name", "=", value)], limit=1)
  106. if not field_value:
  107. raise ValidationError(
  108. f"No se encontro un registro en el modelo de {field_id.relation} con el nombre {value}")
  109. value = field_value.id
  110. return value