import_layout.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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 != "sale.order":
  37. raise ValidationError("Es necesario asignar una regla relacionada a las ordenes de venta.")
  38. elif self.env.context.get("purchase_import") and self.sudo().rule_id.main_model_id.model != "purchase.order":
  39. raise ValidationError("Es necesario asignar una regla relacionada a las ordenes de compra.")
  40. def extension_validator(self, file_name):
  41. name, extension = os.path.splitext(file_name)
  42. valid = True if str(extension).upper() == '.XLSX' or str(extension).upper() == '.XLS' else False
  43. if not valid:
  44. raise ValidationError(
  45. "La extensión del archivo no es valida con el formato de excel, esta debe ser .xlsx o xls")
  46. def get_data(self, df):
  47. try:
  48. main_name = []
  49. for ciudad, grupo in df:
  50. main_data = dict()
  51. data_list = []
  52. # Obtencion de los datos del cabecero
  53. for column in self.rule_id.main_columns_ids:
  54. value = self.get_field_info(column.field_id, grupo.loc[grupo.index[0], column.name])
  55. main_data[f"{column.field_id.name}"] = value
  56. # Creación del cabecero
  57. if main_data:
  58. main_id = self.env[self.rule_id.main_model_id.model].sudo().create(main_data)
  59. main_name.append(main_id.name)
  60. # Obtenciónd de los datos de las lineas de la orden
  61. for line_index in range(grupo.shape[0]):
  62. data = {}
  63. for column in self.rule_id.column_ids:
  64. value = self.get_field_info(column.field_id,
  65. grupo.loc[grupo.index[line_index], column.name])
  66. data[f"{column.field_id.name}"] = value
  67. main_field = self.env[self.rule_id.model_id.model].fields_get()
  68. related_field = next((campo for campo, datos in main_field.items() if
  69. datos.get('relation') == f'{self.rule_id.main_model_id.model}'), None)
  70. # Relación de las lineas con su llave primaria
  71. data[f"{related_field}"] = main_id.id
  72. if data:
  73. data_list.append(data)
  74. # Creación de las lineas de las ordenes
  75. if data_list:
  76. line_ids = self.env[self.rule_id.model_id.model].sudo().create(data_list)
  77. return main_name if main_name else False
  78. except Exception as e:
  79. raise ValidationError(
  80. 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}")
  81. # Obtener los valores de los campos dependiendo del tipo de campo
  82. def get_field_info(self, field_id, value):
  83. if field_id.ttype in ["many2one", "many2one_reference"]:
  84. if str(value).isnumeric():
  85. if len(str(value)) <= 9:
  86. field_value = self.env[field_id.relation].sudo().search([("id", "=", int(value))], limit=1)
  87. else:
  88. field_value = False
  89. if not field_value and field_id.relation in ['product.product', 'product.template']:
  90. field_value = self.env[field_id.relation].sudo().search(["|",("default_code", "=", value),("barcode","=",value)], limit=1)
  91. if not field_value:
  92. raise ValidationError(
  93. f"No se encontro un registro en el modelo de {field_id.relation} con el id {value}")
  94. elif not field_value:
  95. raise ValidationError(
  96. f"No se encontro un registro en el modelo de {field_id.relation} con el código {value}")
  97. value = field_value.id
  98. elif field_id.relation in ['product.product', 'product.template']:
  99. field_value = self.env[field_id.relation].sudo().search(["|",("default_code", "=", value),("barcode","=",value)], limit=1)
  100. if not field_value:
  101. field_value = self.env[field_id.relation].sudo().search([("name", "=", value)], limit=1)
  102. if not field_value:
  103. raise ValidationError(
  104. f"No se encontro un registro en el modelo de {field_id.relation} con el código {value}")
  105. value = field_value.id
  106. else:
  107. field_value = self.env[field_id.relation].sudo().search([("name", "=", value)], limit=1)
  108. if not field_value:
  109. raise ValidationError(
  110. f"No se encontro un registro en el modelo de {field_id.relation} con el nombre {value}")
  111. value = field_value.id
  112. return value