fix: se crea una nueva pestaña en detalle de expediente para visualizar los archivos de errores devueltos por ventanilla unica.

This commit is contained in:
2026-01-29 07:53:10 -07:00
parent 5e4d498a3c
commit 34eb8ed7d9
4 changed files with 109 additions and 9 deletions

View File

@@ -61,7 +61,7 @@ class Pedimento(models.Model):
db_table = 'pedimento'
ordering = ['pedimento']
unique_together = [
['organizacion', 'pedimento'],
# ['organizacion', 'pedimento'],
['organizacion', 'pedimento_app']
]

View File

@@ -15,13 +15,21 @@ class Document(models.Model):
extension = models.CharField(max_length=60, blank=True, null=True)
size = models.PositiveIntegerField()
fuente = models.ForeignKey('Fuente', on_delete=models.CASCADE, related_name='documents', blank=True, null=True)
vu = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def save(self, *args, **kwargs):
is_new = self._state.adding
# Calcular automáticamente el campo vu
if self.document_type_id:
# rango de IDs que indican documentos VU
self.vu = 13 <= self.document_type_id <= 26
else:
self.vu = False
# Usar get_or_create en lugar de get para manejar el caso cuando no existe
uso_almacenamiento, created = UsoAlmacenamiento.objects.get_or_create(
organizacion=self.organizacion,

View File

@@ -13,7 +13,7 @@ class DocumentSerializer(serializers.ModelSerializer):
fuente = serializers.PrimaryKeyRelatedField(queryset=Fuente.objects.all())
class Meta:
model = Document
fields = ('id', 'organizacion', 'pedimento', 'pedimento_numero', 'archivo', 'document_type', 'size', 'extension', 'fuente','fuente_nombre','created_at', 'updated_at')
fields = ('id', 'organizacion', 'pedimento', 'pedimento_numero', 'archivo', 'document_type', 'size', 'extension', 'fuente','fuente_nombre','created_at', 'updated_at','vu')
read_only_fields = ('id', 'size', 'extension', 'created_at', 'updated_at', 'pedimento_numero')
def get_pedimento_numero(self, obj):

View File

@@ -313,6 +313,85 @@ class DocumentViewSet(viewsets.ModelViewSet, DocumentosFiltradosMixin):
uso.save()
instance.delete()
@action(detail=False, methods=['get'], url_path='vu-documentos-errores')
def vu_documentos_errores(self, request):
"""
Endpoint para obtener los documentos VU de error obtenidoss.
Filtra documentos cuyo document_type está en el rango de IDs de documentos VU (13-26).
"""
queryset = self.get_queryset().filter(vu=True)
pedimento_id = request.query_params.get('pedimentoId')
filtroExtension = request.query_params.get('extension')
filtroArchivo = request.query_params.get('archivo__icontains')
filtroFechaCreacion = request.query_params.get('created_at__date')
filtroTipoError = request.query_params.get('tipo_error')
filtroFuente = request.query_params.get('fuente')
document_type_ids = request.query_params.get('document_type_id')
if pedimento_id:
try:
pedimento_obj = Pedimento.objects.get(id=pedimento_id)
queryset = queryset.filter(pedimento_id=pedimento_id)
except Pedimento.DoesNotExist:
return Response(
{"error": "No se encontró el pedimento especificado"},
status=status.HTTP_404_NOT_FOUND
)
if filtroArchivo:
try:
queryset = queryset.filter(archivo__icontains=filtroArchivo)
except ValueError:
return Response(
{"error": "El parámetro Archivo debe ser caracteres válidos"},
status=status.HTTP_400_BAD_REQUEST
)
if filtroExtension:
try:
queryset = queryset.filter(extension__iexact=filtroExtension)
except ValueError:
return Response(
{"error": "El parámetro extension debe ser una extensión válida"},
status=status.HTTP_400_BAD_REQUEST
)
if filtroFechaCreacion:
from django.utils.dateparse import parse_date
fecha = parse_date(filtroFechaCreacion)
if not fecha:
return Response(
{"error": "El parámetro created_at__date debe tener el formato YYYY-MM-DD"},
status=status.HTTP_400_BAD_REQUEST
)
queryset = queryset.filter(created_at__date=fecha)
if filtroTipoError:
try:
ids = [int(i) for i in filtroTipoError.split(',')]
queryset = queryset.filter(document_type_id__in=ids)
except ValueError:
return Response(
{"error": "El parámetro document_type_id debe ser una lista de IDs separados por comas"},
status=status.HTTP_400_BAD_REQUEST
)
if filtroFuente:
try:
ids = [int(i) for i in filtroFuente.split(',')]
queryset = queryset.filter(fuente_id__in=ids)
except ValueError:
return Response(
{"error": "El parámetro fuente debe ser una lista de IDs separados por comas"},
status=status.HTTP_400_BAD_REQUEST
)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
@action(detail=False, methods=['post'], url_path='bulk-delete')
def bulk_delete(self, request):
"""
@@ -424,10 +503,23 @@ class DocumentViewSet(viewsets.ModelViewSet, DocumentosFiltradosMixin):
except UsoAlmacenamiento.DoesNotExist:
# Si no existe el registro, no hay nada que actualizar
pass
# Eliminar los documentos
deleted_count = existing_documents.count()
existing_documents.delete()
# Eliminar los documentos (archivos físicos y registros de BD)
archivos_eliminados = 0
for doc in existing_documents:
try:
# Eliminar archivo físico
if doc.archivo and doc.archivo.storage.exists(doc.archivo.name):
doc.archivo.delete(save=False) # save=False para no intentar guardar el modelo
# Eliminar registro de la base de datos
doc.delete()
archivos_eliminados += 1
except Exception as e:
errors.append(f"No se pudo eliminar el documento {doc.id}: {str(e)}")
failed_ids.append(str(doc.id))
deleted_count = archivos_eliminados
except Exception as e:
return Response(
@@ -437,7 +529,7 @@ class DocumentViewSet(viewsets.ModelViewSet, DocumentosFiltradosMixin):
# Agregar errores para IDs no encontrados
if failed_ids:
errors = [f"No se encontró el documento con ID {id} o no pertenece a su organización" for id in failed_ids]
errors.extend([f"No se encontró el documento con ID {id} o no pertenece a su organización" for id in failed_ids])
# Convertir bytes a MB para la respuesta
space_freed_mb = round(total_space_freed / (1024 * 1024), 2)
@@ -449,7 +541,7 @@ class DocumentViewSet(viewsets.ModelViewSet, DocumentosFiltradosMixin):
"space_freed_mb": space_freed_mb
}
if failed_ids:
if errors or failed_ids:
response_data.update({
"message": "Algunos documentos no pudieron ser eliminados",
"failed_ids": failed_ids,