diff --git a/cosiap_api/dynamic_forms/migrations/0005_verbose_name_dynamicformat_dynamicform.py b/cosiap_api/dynamic_forms/migrations/0005_verbose_name_dynamicformat_dynamicform.py new file mode 100644 index 0000000000000000000000000000000000000000..311b1ba779643aad312ccd429aee9b9f098f64b7 --- /dev/null +++ b/cosiap_api/dynamic_forms/migrations/0005_verbose_name_dynamicformat_dynamicform.py @@ -0,0 +1,20 @@ +# Generated by Django 5.0.7 on 2024-08-31 03:16 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dynamic_formats', '0001_initial'), + ('dynamic_forms', '0004_registro_formulario_foreignkey'), + ] + + operations = [ + migrations.AlterField( + model_name='elemento', + name='formato', + field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dynamic_formats.dynamicformat', verbose_name='Formato'), + ), + ] diff --git a/cosiap_api/dynamic_forms/models.py b/cosiap_api/dynamic_forms/models.py index def86c1f9f17b03cca47a2360b17aa2152660e60..2d6b294b1e756c4f1ea0bd17503b9ba1ac6694cd 100644 --- a/cosiap_api/dynamic_forms/models.py +++ b/cosiap_api/dynamic_forms/models.py @@ -53,7 +53,7 @@ class Elemento(models.Model): max_digits = models.IntegerField(default=10, verbose_name='Máximo de dígitos') opciones = models.ManyToManyField(Opcion, through='ElementosOpciones', verbose_name='Opciones', blank=True) - formato = models.ForeignKey(DynamicFormat, on_delete=models.SET_NULL, verbose_name='Elemento', default=None, null=True, blank=True) + formato = models.ForeignKey(DynamicFormat, on_delete=models.SET_NULL, verbose_name='Formato', default=None, null=True, blank=True) class Meta: verbose_name_plural = '05. Elementos' diff --git a/cosiap_api/dynamic_tables/views.py b/cosiap_api/dynamic_tables/views.py index 64cee79762a5d6f74e43983e8500471f7c0a2008..da67c206daf8d8027c8c922adbd9abfdbd5a29f3 100644 --- a/cosiap_api/dynamic_tables/views.py +++ b/cosiap_api/dynamic_tables/views.py @@ -39,11 +39,10 @@ class DynamicTableAPIView(BasePermissionAPIView): dynamic_form_exist = False - def check_user_permissions(self, request, pk): + def check_user_permissions(self, user, pk): ''' Verificamos el acceso de un usuario a una instancia en específico ''' - user = request.user if not user.is_staff: solicitante = Solicitante.objects.get(id=user.id) @@ -110,13 +109,17 @@ class DynamicTableAPIView(BasePermissionAPIView): ''' response_data = {} + user = request.user + print(user.is_staff) if pk is not None: try: - instance = self.check_user_permissions(request, pk) + instance = self.check_user_permissions(user, pk) if instance is not None: if self.dynamic_form_exist: serializer = DynamicTableDynamicForm(model_class=self.model_class) + instance_data = serializer.retrieve_instance_data(instance) + return Response(instance_data, status=status.HTTP_200_OK) else: serializer = DynamicTable(model_class=self.model_class) instance_data = serializer.retrieve_instance_data(instance) @@ -153,11 +156,12 @@ class DynamicTableAPIView(BasePermissionAPIView): Permite a un admin modificar manualmente varias columnas de una fila en la tabla dinámica. ''' response_data = {} + user = request.user instance = None # Obtener la instancia del modelo por el id proporcionado en la URL o un 404 en caso de no existir if pk is not None: try: - instance = self.check_user_permissions(request, pk) + instance = self.check_user_permissions(user, pk) if instance is None: Mensaje.error(response_data, 'No tienes permisos para realizar esta acción.') return Response(response_data, status = status.HTTP_400_BAD_REQUEST) diff --git a/cosiap_api/solicitudes/migrations/0005_verbose_name_dynamicformat_dynamicform.py b/cosiap_api/solicitudes/migrations/0005_verbose_name_dynamicformat_dynamicform.py new file mode 100644 index 0000000000000000000000000000000000000000..d2f9d0617f9a5fb9cd050c9240c1c3cf54da07c8 --- /dev/null +++ b/cosiap_api/solicitudes/migrations/0005_verbose_name_dynamicformat_dynamicform.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.7 on 2024-08-31 03:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('solicitudes', '0004_solicitud_status_choices'), + ] + + operations = [ + migrations.AlterField( + model_name='solicitud', + name='status', + field=models.CharField(choices=[('Pendiente', 'En revisión'), ('Aprobado', 'Aprobado'), ('Rechazado', 'Rechazado')], max_length=255, verbose_name='Status'), + ), + ] diff --git a/cosiap_api/solicitudes/models.py b/cosiap_api/solicitudes/models.py index 5bb62a63be7e8df8e3873a75514b4c5022c4a540..c7a10d112661aa450686aae69aff510e5d12f26c 100644 --- a/cosiap_api/solicitudes/models.py +++ b/cosiap_api/solicitudes/models.py @@ -108,9 +108,9 @@ class Solicitud(models.Model): """ STATUS_CHOICES = [ - ('1', 'En revisión'), - ('2', 'Aprobado'), - ('3', 'Rechazado'), + ('Pendiente', 'En revisión'), + ('Aprobado', 'Aprobado'), + ('Rechazado', 'Rechazado'), ] status = models.CharField(verbose_name='Status', max_length=255, choices= STATUS_CHOICES) diff --git a/cosiap_api/solicitudes/urls.py b/cosiap_api/solicitudes/urls.py index 0d1eae7d6fa95ea684196ae318bfafdcdcf56fd1..9dcf2f82b9d729711671c2489ed7cf0bcb9cbe86 100644 --- a/cosiap_api/solicitudes/urls.py +++ b/cosiap_api/solicitudes/urls.py @@ -15,4 +15,5 @@ urlpatterns = [ path('reportes//', views.ReportesSolicitudesAPIView.as_view(), name='reportes_solicitudes_pk'), path('reportes/exportar/', views.ExportarReporteSolicitudes.as_view(), name='exportar_reportes'), path('reportes/exportar//', views.ExportarReporteSolicitudes.as_view(), name='exportar_reportes_pk'), + path('calificar//', views.CalificarDocumento.as_view(), name='calificar_documentos'), ] \ No newline at end of file diff --git a/cosiap_api/solicitudes/views.py b/cosiap_api/solicitudes/views.py index f03f6f96d24137c51bab9ec3ace158f810682201..db5e5c83941e2a6c562a059cc979679e28667c4c 100644 --- a/cosiap_api/solicitudes/views.py +++ b/cosiap_api/solicitudes/views.py @@ -25,14 +25,15 @@ from django.db import transaction from .respuestas_serializer import RespuestaSerializer from django.utils import timezone from dynamic_forms.serializers import RespuestaFormularioSerializer -from dynamic_forms.models import Elemento, RegistroFormulario, RegistroSeccion, Respuesta +from dynamic_forms.models import Elemento, RegistroFormulario, RegistroSeccion, Respuesta, RDocumento +from django.core.exceptions import ValidationError class SolicitudAPIView(DynamicTableAPIView): ''' Clase para el manejo de la lista de solicitudes y la aplicación de sus filtros - ''' - + ''' + model_class = Solicitud model_name = 'Solicitud' columns = '__all__' @@ -117,7 +118,7 @@ class SolicitarAPIView(BasePermissionAPIView): solicitante=solicitante, monto_solicitado=monto_solicitado, modalidad=modalidad, - status='1' + status='Pendiente' ) nueva_solicitud.solicitud_n = nueva_solicitud.id nueva_solicitud.save() @@ -163,7 +164,7 @@ class SolicitarAPIView(BasePermissionAPIView): with transaction.atomic(): solicitud.monto_solicitado = monto_solicitado - solicitud.status = '1' + solicitud.status = 'Pendiente' solicitud.save() registro_formulario = solicitud.registro_formulario @@ -265,3 +266,58 @@ class ExportarReporteSolicitudes(Exportar_CSV): ''' model_class = Solicitud + +class CalificarDocumento(BasePermissionAPIView): + ''' + APIView para dar retroalimentación a un documento enviado a la solicitud. + ''' + permission_classes_update = [IsAuthenticated, es_admin] + + def put(self, request, *args, **kwargs): + ''' + Método para calificar uno o varios documentos a la vez de una solicitud. + + Espera una lista de dicts en el formato check_documents = [{"id_respuesta":"n","nuevo_status":"status" }] + ''' + data = {} + + try: + id_solicitud = kwargs['pk'] + respuestas_calificar = request.data.get('check_documents') + if not respuestas_calificar: + raise ValueError("No se proporcionaron documentos para calificar.") + + # Obtener el registro_formulario de la solicitud + solicitud = get_object_or_404(Solicitud, pk=id_solicitud) + registro_formulario_solicitud = solicitud.registro_formulario + + for respuesta_data in respuestas_calificar: + id_respuesta = respuesta_data.get("id_respuesta") + nuevo_status = respuesta_data.get("nuevo_status") + + # Verificar que los datos necesarios están presentes + if not id_respuesta or not nuevo_status: + raise ValueError("El 'id_respuesta' y 'nuevo_status' son obligatorios para cada documento.") + + # Obtener la respuesta del documento + respuesta = get_object_or_404(RDocumento, pk=id_respuesta) + + # Validar que la respuesta pertenece a la solicitud dada + if respuesta.registro_seccion.registro_formulario != registro_formulario_solicitud: + raise ValidationError("La respuesta no pertenece a la solicitud proporcionada.") + + # Validar el nuevo status + if nuevo_status not in RDocumento.Status.values: + raise ValueError(f"El status '{nuevo_status}' no es válido.") + + # Actualizar el status del documento + respuesta.status = nuevo_status + respuesta.save() + + data['mensaje'] = "Documentos calificados correctamente." + return Response(data, status=status.HTTP_200_OK) + + except Exception as e: + Mensaje.error(data, str(e)) + return Response(data, status=status.HTTP_400_BAD_REQUEST) +