feature/T2026-05-016 implementar cargas de tareas en background e implementar y corregir auditoria para datastages
This commit is contained in:
@@ -84,7 +84,9 @@ class Registro501(models.Model):
|
||||
organizacion = models.ForeignKey('organization.Organizacion', on_delete=models.CASCADE, related_name='registro501s', null=True, blank=True)
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro501s', null=True, blank=True)
|
||||
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro501'
|
||||
|
||||
@@ -104,6 +106,8 @@ class Registro502(models.Model):
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro502s', null=True, blank=True)
|
||||
patente = models.CharField(max_length=50, null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro502'
|
||||
|
||||
@@ -120,6 +124,8 @@ class Registro503(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro503s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro503'
|
||||
|
||||
@@ -136,6 +142,8 @@ class Registro504(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro504s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro504'
|
||||
|
||||
@@ -165,6 +173,8 @@ class Registro505(models.Model):
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro505s', null=True, blank=True)
|
||||
patente = models.CharField(max_length=50, null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro505'
|
||||
|
||||
@@ -181,6 +191,8 @@ class Registro506(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro506s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro506'
|
||||
|
||||
@@ -199,6 +211,8 @@ class Registro507(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro507s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro507'
|
||||
|
||||
@@ -223,6 +237,8 @@ class Registro508(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro508s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro508'
|
||||
|
||||
@@ -241,6 +257,8 @@ class Registro509(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro509s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro509'
|
||||
|
||||
@@ -261,6 +279,8 @@ class Registro510(models.Model):
|
||||
forma_pago = models.CharField(max_length=3, null=True, blank=True)
|
||||
importe_pago = models.CharField(max_length=12, null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro510'
|
||||
|
||||
@@ -278,6 +298,8 @@ class Registro511(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro511s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro511'
|
||||
|
||||
@@ -301,6 +323,8 @@ class Registro512(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro512s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro512'
|
||||
|
||||
@@ -363,6 +387,8 @@ class Registro551(models.Model):
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro551s', null=True, blank=True)
|
||||
entidad_fed_destino = models.CharField(max_length=50, null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro551'
|
||||
|
||||
@@ -381,6 +407,8 @@ class Registro552(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro552s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro552'
|
||||
|
||||
@@ -402,6 +430,8 @@ class Registro553(models.Model):
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro553s', null=True, blank=True)
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro553'
|
||||
|
||||
@@ -421,6 +451,8 @@ class Registro554(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro554s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro554'
|
||||
|
||||
@@ -446,6 +478,8 @@ class Registro555(models.Model):
|
||||
created_by = models.IntegerField(null=True, blank=True)
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro555'
|
||||
|
||||
@@ -465,6 +499,8 @@ class Registro556(models.Model):
|
||||
fraccion = models.CharField(max_length=8, null=True, blank=True)
|
||||
secuencia_fraccion = models.CharField(max_length=50, null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro556'
|
||||
|
||||
@@ -484,6 +520,8 @@ class Registro557(models.Model):
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro557s', null=True, blank=True)
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro557'
|
||||
|
||||
@@ -502,6 +540,8 @@ class Registro558(models.Model):
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro558s', null=True, blank=True)
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro558'
|
||||
|
||||
@@ -522,6 +562,8 @@ class RegistroSel(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro_sel', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro_sel'
|
||||
|
||||
@@ -546,6 +588,8 @@ class Registro701(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro701s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro701'
|
||||
|
||||
@@ -564,6 +608,8 @@ class Registro702(models.Model):
|
||||
consulta = models.CharField(max_length=50, null=True, blank=True)
|
||||
datastage = models.ForeignKey(DataStage, on_delete=models.CASCADE, related_name='registro702s', null=True, blank=True)
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
db_table = 'registro702'
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import zipfile
|
||||
import re
|
||||
from api.utils.storage_service import storage_service
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@shared_task
|
||||
def procesar_datastage_task(datastage_id, user_organizacion_id=None):
|
||||
import traceback
|
||||
@@ -167,15 +169,22 @@ def procesar_archivo_asc_task(datastage_id, user_organizacion_id, asc_name):
|
||||
continue
|
||||
|
||||
if first:
|
||||
field_names = [f for f in line_decoded.split('|')]
|
||||
field_names = line_decoded.split('|')
|
||||
# Eliminar columnas vacías del final (líneas terminan con |)
|
||||
while field_names and field_names[-1] == '':
|
||||
field_names.pop()
|
||||
field_names_snake = [to_snake_case(f) for f in field_names]
|
||||
first = False
|
||||
continue
|
||||
|
||||
|
||||
values = line_decoded.split('|')
|
||||
while values and values[-1] == '':
|
||||
values.pop()
|
||||
if len(values) != len(field_names_snake):
|
||||
logger.debug(
|
||||
"%s línea %d: esperados %d campos, recibidos %d — se omite",
|
||||
asc_name, line_count, len(field_names_snake), len(values)
|
||||
)
|
||||
continue
|
||||
|
||||
data = dict(zip(field_names_snake, values))
|
||||
@@ -185,28 +194,36 @@ def procesar_archivo_asc_task(datastage_id, user_organizacion_id, asc_name):
|
||||
if hasattr(Model, 'datastage_id'):
|
||||
data['datastage_id'] = datastage.id
|
||||
|
||||
# Limpiar fechas vacías
|
||||
# Parsear y normalizar todos los campos de fecha/datetime
|
||||
for field in Model._meta.get_fields():
|
||||
if hasattr(field, 'get_internal_type') and field.get_internal_type() in ["DateField", "DateTimeField"]:
|
||||
if data.get(field.name) == "":
|
||||
data[field.name] = None
|
||||
|
||||
# Convertir fecha_pago_real
|
||||
if 'fecha_pago_real' in data and data['fecha_pago_real']:
|
||||
fecha_val = data['fecha_pago_real']
|
||||
if isinstance(fecha_val, str):
|
||||
try:
|
||||
dt = datetime.datetime.strptime(fecha_val, '%Y-%m-%d %H:%M:%S')
|
||||
except ValueError:
|
||||
if not hasattr(field, 'get_internal_type'):
|
||||
continue
|
||||
field_type = field.get_internal_type()
|
||||
val = data.get(field.name)
|
||||
if val == '' or val is None:
|
||||
data[field.name] = None
|
||||
continue
|
||||
if field_type == 'DateTimeField' and isinstance(val, str):
|
||||
dt = None
|
||||
for fmt in ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d'):
|
||||
try:
|
||||
dt = datetime.datetime.strptime(fecha_val, '%Y-%m-%d')
|
||||
except Exception:
|
||||
dt = None
|
||||
dt = datetime.datetime.strptime(val, fmt)
|
||||
break
|
||||
except ValueError:
|
||||
continue
|
||||
if dt and timezone.is_naive(dt):
|
||||
dt = timezone.make_aware(dt)
|
||||
if dt:
|
||||
data['fecha_pago_real'] = dt
|
||||
data[field.name] = dt
|
||||
|
||||
# Filtrar data para solo incluir campos válidos del modelo
|
||||
valid_fields = set()
|
||||
for f in Model._meta.get_fields():
|
||||
if hasattr(f, 'name'):
|
||||
valid_fields.add(f.name)
|
||||
if hasattr(f, 'attname'):
|
||||
valid_fields.add(f.attname)
|
||||
data = {k: v for k, v in data.items() if k in valid_fields}
|
||||
|
||||
try:
|
||||
obj = Model(**data)
|
||||
objects_to_create.append(obj)
|
||||
@@ -284,8 +301,9 @@ def procesar_archivo_asc_task(datastage_id, user_organizacion_id, asc_name):
|
||||
try:
|
||||
Pedimento.objects.create(**pedimento_data)
|
||||
except Exception as ped_exc:
|
||||
pass
|
||||
logger.warning("No se pudo crear Pedimento %s: %s", pedimento_app, ped_exc)
|
||||
except Exception as e:
|
||||
logger.error("%s línea %d: error creando objeto %s: %s", asc_name, line_count, model_name, e)
|
||||
continue
|
||||
|
||||
# Bulk create
|
||||
|
||||
Reference in New Issue
Block a user