Spaces:
Sleeping
Sleeping
Merge branch 'dev'
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- tecnicas/admin.py +9 -15
- tecnicas/controllers/__init__.py +41 -10
- tecnicas/controllers/api_controller/rating_cata_controller.py +78 -0
- tecnicas/controllers/api_controller/rating_napping_controller.py +367 -0
- tecnicas/controllers/api_controller/rating_pf_list_controller.py +221 -0
- tecnicas/controllers/{views_controller/api_rating_controller.py → api_controller/rating_sacales_controller.py} +2 -2
- tecnicas/controllers/api_controller/rating_sort_controller.py +67 -0
- tecnicas/controllers/models_controller/calificacion_controller.py +1 -1
- tecnicas/controllers/models_controller/dato_controller.py +36 -14
- tecnicas/controllers/models_controller/escala_controller.py +19 -13
- tecnicas/controllers/models_controller/particiapacion_controller.py +3 -13
- tecnicas/controllers/models_controller/sesion_controller.py +3 -8
- tecnicas/controllers/models_controller/tecnica_controller.py +1 -1
- tecnicas/controllers/views_controller/create_session/panel_basic_controller.py +106 -13
- tecnicas/controllers/views_controller/create_session/panel_codes_controller.py +38 -9
- tecnicas/controllers/views_controller/create_session/panel_tags_controller.py +2 -2
- tecnicas/controllers/views_controller/create_session/panel_words_controller.py +1 -1
- tecnicas/controllers/views_controller/create_session/panels_create/panel_create_cata_controller.py +137 -0
- tecnicas/controllers/views_controller/create_session/panels_create/panel_create_controller.py +17 -0
- tecnicas/controllers/views_controller/create_session/{panel_create_controller.py → panels_create/panel_create_escalas_controller.py} +7 -284
- tecnicas/controllers/views_controller/create_session/panels_create/panel_create_napping_controller.py +114 -0
- tecnicas/controllers/views_controller/create_session/panels_create/panel_create_pf_controller.py +105 -0
- tecnicas/controllers/views_controller/create_session/panels_create/panel_create_rata_controller.py +155 -0
- tecnicas/controllers/views_controller/create_session/panels_create/panel_create_sort_controller.py +95 -0
- tecnicas/controllers/views_controller/session_management/{details_rata_controller.py → details/details_cata_controller.py} +36 -20
- tecnicas/controllers/views_controller/session_management/details/details_controller.py +70 -0
- tecnicas/controllers/views_controller/session_management/{details_escala_controller.py → details/details_escala_controller.py} +9 -55
- tecnicas/controllers/views_controller/session_management/details/details_napping_controller.py +508 -0
- tecnicas/controllers/views_controller/session_management/details/details_pf_controller.py +215 -0
- tecnicas/controllers/views_controller/session_management/details/details_rata_controller.py +7 -0
- tecnicas/controllers/views_controller/session_management/details/details_sort_controller.py +91 -0
- tecnicas/controllers/views_controller/session_management/details_controller.py +0 -13
- tecnicas/controllers/views_controller/session_management/{monitor_controller.py → monitor/monitor_controller.py} +21 -12
- tecnicas/controllers/views_controller/session_management/{monitor_escalas_controller.py → monitor/monitor_escalas_controller.py} +1 -17
- tecnicas/controllers/views_controller/session_management/monitor/monitor_napping_controller.py +35 -0
- tecnicas/controllers/views_controller/session_management/monitor/monitor_pf_controller.py +72 -0
- tecnicas/controllers/views_controller/session_management/{monitor_rata_controller.py → monitor/monitor_rata_controller.py} +1 -17
- tecnicas/controllers/views_controller/session_management/monitor/monitor_sort_controller.py +27 -0
- tecnicas/controllers/views_controller/sessions_tester/{init_session_tester_controller.py → init_session/init_session_controller.py} +6 -79
- tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_escalas_controller.py +82 -0
- tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_napping_controller.py +80 -0
- tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_pf_controller.py +144 -0
- tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_rata_controller.py +24 -0
- tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_sort_controller.py +77 -0
- tecnicas/controllers/views_controller/sessions_tester/login_session_tester_controller.py +82 -18
- tecnicas/controllers/views_controller/sessions_tester/tests_forms/general_test_controller.py +28 -0
- tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_cata_controller.py +55 -0
- tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_napping_controller.py +242 -0
- tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_pf_controller.py +174 -0
- tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_rata_controller.py +87 -0
tecnicas/admin.py
CHANGED
|
@@ -1,20 +1,6 @@
|
|
| 1 |
from django.contrib import admin
|
| 2 |
|
| 3 |
-
from .models import CategoriaTecnica, TipoTecnica, TipoEscala, EstiloPalabra
|
| 4 |
-
|
| 5 |
-
from .models import Catador, Presentador
|
| 6 |
-
|
| 7 |
-
from .models import Tecnica, SesionSensorial
|
| 8 |
-
|
| 9 |
-
from .models import EsAtributo, Palabra, Vocabulario
|
| 10 |
-
|
| 11 |
-
from .models import Etiqueta, Escala, EtiquetasEscala
|
| 12 |
-
|
| 13 |
-
from .models import Producto, Participacion
|
| 14 |
-
|
| 15 |
-
from .models import Orden, Posicion
|
| 16 |
-
|
| 17 |
-
from .models import Dato, ValorDecimal, ValorBooleano, Calificacion
|
| 18 |
|
| 19 |
# Register your models here.
|
| 20 |
admin.site.register(CategoriaTecnica)
|
|
@@ -46,3 +32,11 @@ admin.site.register(Dato)
|
|
| 46 |
admin.site.register(ValorDecimal)
|
| 47 |
admin.site.register(ValorBooleano)
|
| 48 |
admin.site.register(Calificacion)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from django.contrib import admin
|
| 2 |
|
| 3 |
+
from .models import CategoriaTecnica, TipoTecnica, TipoEscala, EstiloPalabra, Catador, Presentador, Tecnica, SesionSensorial, EsAtributo, Palabra, Vocabulario, Etiqueta, Escala, EtiquetasEscala, Producto, Participacion, Orden, Posicion, Dato, ValorDecimal, ValorBooleano, Calificacion, ListaPalabras, GrupoProducto, Modalidad, TecnicaModalidad, DatoPunto
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
# Register your models here.
|
| 6 |
admin.site.register(CategoriaTecnica)
|
|
|
|
| 32 |
admin.site.register(ValorDecimal)
|
| 33 |
admin.site.register(ValorBooleano)
|
| 34 |
admin.site.register(Calificacion)
|
| 35 |
+
|
| 36 |
+
admin.site.register(ListaPalabras)
|
| 37 |
+
admin.site.register(GrupoProducto)
|
| 38 |
+
|
| 39 |
+
admin.site.register(Modalidad)
|
| 40 |
+
admin.site.register(TecnicaModalidad)
|
| 41 |
+
|
| 42 |
+
admin.site.register(DatoPunto)
|
tecnicas/controllers/__init__.py
CHANGED
|
@@ -16,22 +16,53 @@ from .views_controller.create_session.panel_basic_controller import PanelBasicCo
|
|
| 16 |
from .views_controller.create_session.panel_tags_controller import PanelTagsController
|
| 17 |
from .views_controller.create_session.panel_codes_controller import PanelCodesController
|
| 18 |
from .views_controller.create_session.panel_words_controller import PanelWordsController
|
| 19 |
-
from .views_controller.create_session.panel_create_controller import PanelCreateController
|
| 20 |
|
| 21 |
-
from .views_controller.
|
| 22 |
-
from .views_controller.
|
| 23 |
-
from .views_controller.
|
| 24 |
-
from .views_controller.
|
| 25 |
-
from .views_controller.
|
| 26 |
-
from .views_controller.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
from .views_controller.sessions_tester.login_session_tester_controller import LoginSessionTesterController
|
| 29 |
-
from .views_controller.sessions_tester.init_session_tester_controller import InitSessionTesterController
|
| 30 |
-
from .views_controller.sessions_tester.convencional_scales_controller import ConvencionalScalesController
|
| 31 |
from .views_controller.sessions_tester.list_sessions_tester_controller import ListSessionsTesterController
|
| 32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
from .views_controller.vocabulary_manage.create_vocabulary_controller import CreateVocabularyController
|
|
|
|
| 34 |
from .views_controller.vocabulary_manage.list_vocabulary_controller import ListVocabularyController
|
| 35 |
|
| 36 |
-
from .
|
|
|
|
|
|
|
| 37 |
from .views_controller.tester_list_controller import TesterListController
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
from .views_controller.create_session.panel_tags_controller import PanelTagsController
|
| 17 |
from .views_controller.create_session.panel_codes_controller import PanelCodesController
|
| 18 |
from .views_controller.create_session.panel_words_controller import PanelWordsController
|
|
|
|
| 19 |
|
| 20 |
+
from .views_controller.create_session.panels_create.panel_create_escalas_controller import PanelCreateEscalasController
|
| 21 |
+
from .views_controller.create_session.panels_create.panel_create_rata_controller import PanelCreateRataController
|
| 22 |
+
from .views_controller.create_session.panels_create.panel_create_cata_controller import PanelCreateCataController
|
| 23 |
+
from .views_controller.create_session.panels_create.panel_create_pf_controller import PanelCreatePFController
|
| 24 |
+
from .views_controller.create_session.panels_create.panel_create_sort_controller import PanelCreateSortController
|
| 25 |
+
from .views_controller.create_session.panels_create.panel_create_napping_controller import PanelCreateNappingController
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
from .views_controller.session_management.details.details_controller import DetallesController
|
| 29 |
+
from .views_controller.session_management.details.details_escala_controller import DetallesEscalasController
|
| 30 |
+
from .views_controller.session_management.details.details_rata_controller import DetallesRATAController
|
| 31 |
+
from .views_controller.session_management.details.details_cata_controller import DetallesCATAController
|
| 32 |
+
from .views_controller.session_management.details.details_pf_controller import DetallesPFController
|
| 33 |
+
from .views_controller.session_management.details.details_sort_controller import DetallesSortController
|
| 34 |
+
from .views_controller.session_management.details.details_napping_controller import DetallesNappingController
|
| 35 |
+
|
| 36 |
+
from .views_controller.session_management.monitor.monitor_escalas_controller import MonitorEscalasController
|
| 37 |
+
from .views_controller.session_management.monitor.monitor_rata_controller import MonitorRATAController
|
| 38 |
+
from .views_controller.session_management.monitor.monitor_pf_controller import MonitorPFController
|
| 39 |
+
from .views_controller.session_management.monitor.monitor_sort_controller import MonitorSortController
|
| 40 |
+
from .views_controller.session_management.monitor.monitor_napping_controller import MonitorNappingController
|
| 41 |
|
| 42 |
from .views_controller.sessions_tester.login_session_tester_controller import LoginSessionTesterController
|
|
|
|
|
|
|
| 43 |
from .views_controller.sessions_tester.list_sessions_tester_controller import ListSessionsTesterController
|
| 44 |
|
| 45 |
+
from .views_controller.sessions_tester.tests_forms.test_scales_controller import TestScalesController
|
| 46 |
+
from .views_controller.sessions_tester.tests_forms.test_rata_controller import TestRataController
|
| 47 |
+
from .views_controller.sessions_tester.tests_forms.test_cata_controller import TestCataController
|
| 48 |
+
from .views_controller.sessions_tester.tests_forms.test_pf_controller import TestPFController
|
| 49 |
+
from .views_controller.sessions_tester.tests_forms.test_sort_controller import TestSortController
|
| 50 |
+
from .views_controller.sessions_tester.tests_forms.test_napping_controller import TestNappingController
|
| 51 |
+
|
| 52 |
+
from .views_controller.sessions_tester.init_session.init_session_escalas_controller import InitSessionEscalasController
|
| 53 |
+
from .views_controller.sessions_tester.init_session.init_session_rata_controller import InitSessionRATAController
|
| 54 |
+
from .views_controller.sessions_tester.init_session.init_session_pf_controller import InitSessionPFController
|
| 55 |
+
from .views_controller.sessions_tester.init_session.init_session_sort_controller import InitSessionSortController
|
| 56 |
+
from .views_controller.sessions_tester.init_session.init_session_napping_controller import InitSessionNappingController
|
| 57 |
+
|
| 58 |
from .views_controller.vocabulary_manage.create_vocabulary_controller import CreateVocabularyController
|
| 59 |
+
from .views_controller.vocabulary_manage.view_vocabulary_controller import ViewVocabularyController
|
| 60 |
from .views_controller.vocabulary_manage.list_vocabulary_controller import ListVocabularyController
|
| 61 |
|
| 62 |
+
from .api_controller.rating_sacales_controller import RatingScalesController
|
| 63 |
+
from .api_controller.rating_cata_controller import RatingCataController
|
| 64 |
+
from .api_controller.rating_pf_list_controller import RatingPFListController
|
| 65 |
from .views_controller.tester_list_controller import TesterListController
|
| 66 |
+
from .api_controller.rating_sort_controller import RatingSortController
|
| 67 |
+
from .api_controller.rating_napping_controller import RatingNappingController
|
| 68 |
+
|
tecnicas/controllers/api_controller/rating_cata_controller.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import JsonResponse, HttpRequest
|
| 2 |
+
from django.db import transaction
|
| 3 |
+
from tecnicas.models import Calificacion, Dato, ValorBooleano, Participacion, Palabra
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class RatingCataController():
|
| 7 |
+
def __init__(self):
|
| 8 |
+
pass
|
| 9 |
+
|
| 10 |
+
@staticmethod
|
| 11 |
+
def saveRatingWords(request: HttpRequest, data_words: list[dict], data_prodct: dict):
|
| 12 |
+
try:
|
| 13 |
+
with transaction.atomic():
|
| 14 |
+
participation = Participacion.objects.get(
|
| 15 |
+
id=request.session["id_participation"])
|
| 16 |
+
if not participation:
|
| 17 |
+
raise ValueError("No está autorizado en la sesión")
|
| 18 |
+
|
| 19 |
+
ids_words = []
|
| 20 |
+
words_values = {}
|
| 21 |
+
|
| 22 |
+
# Acoplar datos para usar
|
| 23 |
+
for da_wo in data_words:
|
| 24 |
+
ids_words.append(da_wo["id"])
|
| 25 |
+
words_values[da_wo["word"]] = da_wo["is_check"]
|
| 26 |
+
|
| 27 |
+
words_for_rating = Palabra.objects.filter(id__in=ids_words)
|
| 28 |
+
if not words_for_rating:
|
| 29 |
+
raise ValueError("No se han encontrado sus palabras")
|
| 30 |
+
|
| 31 |
+
technique = participation.tecnica
|
| 32 |
+
|
| 33 |
+
# Creando la calificacion
|
| 34 |
+
(rating, creataed) = Calificacion.objects.get_or_create(
|
| 35 |
+
num_repeticion=technique.repeticion,
|
| 36 |
+
id_producto_id=data_prodct["id"],
|
| 37 |
+
id_tecnica=technique,
|
| 38 |
+
id_catador=request.user.user_catador
|
| 39 |
+
)
|
| 40 |
+
if not rating:
|
| 41 |
+
raise ValueError("Problemas al crear la calificación")
|
| 42 |
+
|
| 43 |
+
# Guardando datos
|
| 44 |
+
data_for_save = []
|
| 45 |
+
for word in words_for_rating:
|
| 46 |
+
data_for_save.append(Dato(
|
| 47 |
+
id_palabra=word,
|
| 48 |
+
id_calificacion=rating
|
| 49 |
+
))
|
| 50 |
+
|
| 51 |
+
Dato.objects.bulk_create(data_for_save)
|
| 52 |
+
data_saved = Dato.objects.filter(
|
| 53 |
+
id_calificacion=rating).only("id_palabra")
|
| 54 |
+
if not data_saved:
|
| 55 |
+
raise ValueError("Problemas al crear los datos")
|
| 56 |
+
|
| 57 |
+
# Guardando valores de datos
|
| 58 |
+
values_for_save = []
|
| 59 |
+
for data in data_saved:
|
| 60 |
+
word_for_rating = data.id_palabra.nombre_palabra
|
| 61 |
+
values_for_save.append(
|
| 62 |
+
ValorBooleano(
|
| 63 |
+
id_dato=data,
|
| 64 |
+
valor=words_values[word_for_rating]
|
| 65 |
+
)
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
ValorBooleano.objects.bulk_create(values_for_save)
|
| 69 |
+
values_saves = ValorBooleano.objects.filter(
|
| 70 |
+
id_dato__id_calificacion=rating).count()
|
| 71 |
+
if not values_saves:
|
| 72 |
+
raise ValueError("Error al guardar los datos")
|
| 73 |
+
|
| 74 |
+
return JsonResponse({"message": "Valores guardados"})
|
| 75 |
+
|
| 76 |
+
except ValueError as e:
|
| 77 |
+
print(f"Error de calificacion: {e}")
|
| 78 |
+
return JsonResponse({"error": e}, statusstatus=500)
|
tecnicas/controllers/api_controller/rating_napping_controller.py
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import JsonResponse
|
| 2 |
+
from django.http import HttpRequest
|
| 3 |
+
from django.db import transaction
|
| 4 |
+
from tecnicas.models import Calificacion, DatoPunto, Producto, Participacion, Palabra, GrupoProducto, TecnicaModalidad
|
| 5 |
+
from tecnicas.forms import ListWordsForm
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class RatingNappingController:
|
| 9 |
+
@staticmethod
|
| 10 |
+
def saveRatingCoordinates(request: HttpRequest, data: list | dict):
|
| 11 |
+
participation = Participacion.objects.get(
|
| 12 |
+
id=request.session["id_participation"]
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
name_mod = TecnicaModalidad.objects.get(
|
| 16 |
+
tecnica=participation.tecnica
|
| 17 |
+
).modalidad.nombre.lower()
|
| 18 |
+
|
| 19 |
+
# Branch based on modality
|
| 20 |
+
if name_mod == 'sorting':
|
| 21 |
+
return RatingNappingController.processSortingMode(
|
| 22 |
+
data, participation
|
| 23 |
+
)
|
| 24 |
+
|
| 25 |
+
if name_mod in ['sin modalidad', 'perfil ultra flash']:
|
| 26 |
+
return RatingNappingController.processNappOrPUF(
|
| 27 |
+
data, participation
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
else:
|
| 31 |
+
return JsonResponse({"error": "Modalidad no soportada"})
|
| 32 |
+
|
| 33 |
+
@staticmethod
|
| 34 |
+
def processSortingMode(data: dict, participation):
|
| 35 |
+
try:
|
| 36 |
+
with transaction.atomic():
|
| 37 |
+
# Extract products array (always present)
|
| 38 |
+
products = data.get("products", [])
|
| 39 |
+
if not products:
|
| 40 |
+
return JsonResponse({"error": "No se proporcionaron productos"})
|
| 41 |
+
|
| 42 |
+
existing_ratings_map, products_map = RatingNappingController.savePoints(
|
| 43 |
+
isSorting=True, products=products, participation=participation
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
# Process groups if they exist
|
| 47 |
+
groups = data.get("groups", {})
|
| 48 |
+
if groups:
|
| 49 |
+
RatingNappingController.processGroupsForSorting(
|
| 50 |
+
products, groups, participation, existing_ratings_map, products_map
|
| 51 |
+
)
|
| 52 |
+
else:
|
| 53 |
+
RatingNappingController.deleteAllGroups(participation)
|
| 54 |
+
|
| 55 |
+
return JsonResponse({"message": "Datos guardados exitosamente"})
|
| 56 |
+
|
| 57 |
+
except Exception as e:
|
| 58 |
+
print("ERROR:", e)
|
| 59 |
+
import traceback
|
| 60 |
+
traceback.print_exc()
|
| 61 |
+
return JsonResponse({"error": f"Error al procesar datos: {str(e)}"})
|
| 62 |
+
|
| 63 |
+
@staticmethod
|
| 64 |
+
def processNappOrPUF(data: list, participation):
|
| 65 |
+
try:
|
| 66 |
+
with transaction.atomic():
|
| 67 |
+
existing_ratings_map, products_map = RatingNappingController.savePoints(
|
| 68 |
+
isSorting=False, products=data, participation=participation
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
RatingNappingController.processWordsForRatings(
|
| 72 |
+
data, existing_ratings_map
|
| 73 |
+
)
|
| 74 |
+
|
| 75 |
+
return JsonResponse({"message": "Datos guardados exitosamente"})
|
| 76 |
+
|
| 77 |
+
except Exception as e:
|
| 78 |
+
print("ERROR:", e)
|
| 79 |
+
return JsonResponse({"error": "Error al procesar datos"})
|
| 80 |
+
|
| 81 |
+
@staticmethod
|
| 82 |
+
def processGroupsForSorting(products, groups, participation, existing_ratings_map, products_map):
|
| 83 |
+
"""Process groups for sorting mode
|
| 84 |
+
- Creates/updates GrupoProducto instances
|
| 85 |
+
- Ensures products don't belong to multiple groups
|
| 86 |
+
- Associates words with groups
|
| 87 |
+
"""
|
| 88 |
+
# Build mapping of product_id to group_id from products array
|
| 89 |
+
product_to_group = {}
|
| 90 |
+
for product_item in products:
|
| 91 |
+
group_code = product_item.get("group", "")
|
| 92 |
+
if group_code: # Only if product has a group assigned
|
| 93 |
+
product_id = int(product_item["idProduct"])
|
| 94 |
+
if product_id in product_to_group:
|
| 95 |
+
raise ValueError(
|
| 96 |
+
f"Producto {product_id} pertenece a múltiples grupos")
|
| 97 |
+
product_to_group[product_id] = group_code
|
| 98 |
+
|
| 99 |
+
# Get existing groups for this catador and technique
|
| 100 |
+
existing_groups = GrupoProducto.objects.filter(
|
| 101 |
+
tecnica=participation.tecnica,
|
| 102 |
+
catador=participation.catador
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
# Create a map of existing groups by their product composition
|
| 106 |
+
# We'll identify groups by the set of products they contain
|
| 107 |
+
existing_groups_map = {}
|
| 108 |
+
for group in existing_groups:
|
| 109 |
+
product_ids = set(group.productos.values_list('id', flat=True))
|
| 110 |
+
key = frozenset(product_ids)
|
| 111 |
+
existing_groups_map[key] = group
|
| 112 |
+
|
| 113 |
+
# Build new groups structure
|
| 114 |
+
groups_to_create = []
|
| 115 |
+
groups_to_update = []
|
| 116 |
+
group_products_map = {} # group_id -> [product_ids]
|
| 117 |
+
|
| 118 |
+
# Organize products by group
|
| 119 |
+
for product_id, group_code in product_to_group.items():
|
| 120 |
+
if group_code not in group_products_map:
|
| 121 |
+
group_products_map[group_code] = []
|
| 122 |
+
group_products_map[group_code].append(product_id)
|
| 123 |
+
|
| 124 |
+
# Process each group
|
| 125 |
+
for group_code, product_ids in group_products_map.items():
|
| 126 |
+
product_set = frozenset(product_ids)
|
| 127 |
+
|
| 128 |
+
# Check if this group already exists
|
| 129 |
+
if product_set in existing_groups_map:
|
| 130 |
+
group = existing_groups_map[product_set]
|
| 131 |
+
groups_to_update.append((group, group_code))
|
| 132 |
+
else:
|
| 133 |
+
# Create new group
|
| 134 |
+
group = GrupoProducto(
|
| 135 |
+
tecnica=participation.tecnica,
|
| 136 |
+
catador=participation.catador
|
| 137 |
+
)
|
| 138 |
+
groups_to_create.append((group, product_ids, group_code))
|
| 139 |
+
|
| 140 |
+
# Create new groups
|
| 141 |
+
created_groups = []
|
| 142 |
+
for group, product_ids, group_code in groups_to_create:
|
| 143 |
+
group.save() # Save first to get ID for M2M
|
| 144 |
+
|
| 145 |
+
# Add products to group
|
| 146 |
+
productos = [products_map[pid]
|
| 147 |
+
for pid in product_ids if pid in products_map]
|
| 148 |
+
group.productos.set(productos)
|
| 149 |
+
|
| 150 |
+
created_groups.append((group, group_code))
|
| 151 |
+
|
| 152 |
+
# Combine created and existing groups for word processing
|
| 153 |
+
all_groups_for_words = created_groups + groups_to_update
|
| 154 |
+
|
| 155 |
+
# Delete groups that no longer exist
|
| 156 |
+
current_group_sets = set(frozenset(pids)
|
| 157 |
+
for pids in group_products_map.values())
|
| 158 |
+
for product_set, group in existing_groups_map.items():
|
| 159 |
+
if product_set not in current_group_sets:
|
| 160 |
+
group.delete()
|
| 161 |
+
|
| 162 |
+
# Process words for groups
|
| 163 |
+
if groups:
|
| 164 |
+
RatingNappingController.processWordsForGroups(
|
| 165 |
+
groups, all_groups_for_words
|
| 166 |
+
)
|
| 167 |
+
|
| 168 |
+
@staticmethod
|
| 169 |
+
def deleteAllGroups(participation):
|
| 170 |
+
GrupoProducto.objects.filter(
|
| 171 |
+
tecnica=participation.tecnica,
|
| 172 |
+
catador=participation.catador
|
| 173 |
+
).delete()
|
| 174 |
+
|
| 175 |
+
@staticmethod
|
| 176 |
+
def processWordsForGroups(groups_data, groups_list):
|
| 177 |
+
"""Process and associate words to groups
|
| 178 |
+
- Creates words that don't exist
|
| 179 |
+
- Associates words to GrupoProducto instances
|
| 180 |
+
- Handles concurrency
|
| 181 |
+
"""
|
| 182 |
+
# Collect all unique words from all groups
|
| 183 |
+
all_words = set()
|
| 184 |
+
for group_id, words in groups_data.items():
|
| 185 |
+
if words:
|
| 186 |
+
all_words.update(words)
|
| 187 |
+
|
| 188 |
+
if not all_words:
|
| 189 |
+
# No words to process, just clear existing words from groups
|
| 190 |
+
for grupo, _ in groups_list:
|
| 191 |
+
grupo.palabras.clear()
|
| 192 |
+
return
|
| 193 |
+
|
| 194 |
+
# Get existing words
|
| 195 |
+
existing_words = Palabra.objects.filter(
|
| 196 |
+
nombre_palabra__in=all_words
|
| 197 |
+
)
|
| 198 |
+
existing_words_map = {w.nombre_palabra: w for w in existing_words}
|
| 199 |
+
|
| 200 |
+
# Create missing words with concurrency handling
|
| 201 |
+
word_objects = {}
|
| 202 |
+
for word_name in all_words:
|
| 203 |
+
if word_name in existing_words_map:
|
| 204 |
+
word_objects[word_name] = existing_words_map[word_name]
|
| 205 |
+
else:
|
| 206 |
+
word_obj, created = Palabra.objects.get_or_create(
|
| 207 |
+
nombre_palabra=word_name
|
| 208 |
+
)
|
| 209 |
+
word_objects[word_name] = word_obj
|
| 210 |
+
|
| 211 |
+
# Associate words with groups
|
| 212 |
+
for grupo, group_id in groups_list:
|
| 213 |
+
words = groups_data.get(group_id, [])
|
| 214 |
+
if words:
|
| 215 |
+
words_to_set = [word_objects[word_name]
|
| 216 |
+
for word_name in words if word_name in word_objects]
|
| 217 |
+
grupo.palabras.set(words_to_set)
|
| 218 |
+
else:
|
| 219 |
+
grupo.palabras.clear()
|
| 220 |
+
|
| 221 |
+
@staticmethod
|
| 222 |
+
def savePoints(isSorting: bool, products, participation):
|
| 223 |
+
try:
|
| 224 |
+
with transaction.atomic():
|
| 225 |
+
# Get products map for validation
|
| 226 |
+
products_map = RatingNappingController.getProductsMap(
|
| 227 |
+
participation.tecnica)
|
| 228 |
+
|
| 229 |
+
# Get existing ratings map
|
| 230 |
+
existing_ratings_map = RatingNappingController.getExistingRatingsMap(
|
| 231 |
+
participation.tecnica, participation.catador)
|
| 232 |
+
|
| 233 |
+
if not isSorting:
|
| 234 |
+
validation_result = RatingNappingController.validateWords(
|
| 235 |
+
products)
|
| 236 |
+
if validation_result is not None:
|
| 237 |
+
return validation_result
|
| 238 |
+
|
| 239 |
+
# Create new ratings for products that don't have them
|
| 240 |
+
new_ratings = []
|
| 241 |
+
ids_products = products_map.keys()
|
| 242 |
+
for item in products:
|
| 243 |
+
product_id = int(item["idProduct"])
|
| 244 |
+
if product_id not in existing_ratings_map and product_id in ids_products:
|
| 245 |
+
new_ratings.append(
|
| 246 |
+
Calificacion(
|
| 247 |
+
num_repeticion=0,
|
| 248 |
+
id_producto=products_map[product_id],
|
| 249 |
+
id_tecnica=participation.tecnica,
|
| 250 |
+
id_catador=participation.catador,
|
| 251 |
+
)
|
| 252 |
+
)
|
| 253 |
+
|
| 254 |
+
if new_ratings:
|
| 255 |
+
Calificacion.objects.bulk_create(new_ratings)
|
| 256 |
+
existing_ratings_map = RatingNappingController.getExistingRatingsMap(
|
| 257 |
+
participation.tecnica, participation.catador)
|
| 258 |
+
|
| 259 |
+
# Process DatoPunto instances from products array
|
| 260 |
+
existing_points_map = RatingNappingController.getExistingPointsMap(
|
| 261 |
+
existing_ratings_map.values())
|
| 262 |
+
|
| 263 |
+
points_to_create = []
|
| 264 |
+
points_to_update = []
|
| 265 |
+
|
| 266 |
+
for item in products:
|
| 267 |
+
product_id = int(item["idProduct"])
|
| 268 |
+
rating = existing_ratings_map.get(product_id)
|
| 269 |
+
|
| 270 |
+
if rating:
|
| 271 |
+
if rating.id in existing_points_map:
|
| 272 |
+
point = existing_points_map[rating.id]
|
| 273 |
+
point.x = item["x"]
|
| 274 |
+
point.y = item["y"]
|
| 275 |
+
points_to_update.append(point)
|
| 276 |
+
else:
|
| 277 |
+
points_to_create.append(
|
| 278 |
+
DatoPunto(
|
| 279 |
+
x=item["x"],
|
| 280 |
+
y=item["y"],
|
| 281 |
+
calificacion=rating,
|
| 282 |
+
)
|
| 283 |
+
)
|
| 284 |
+
|
| 285 |
+
if points_to_create:
|
| 286 |
+
DatoPunto.objects.bulk_create(points_to_create)
|
| 287 |
+
|
| 288 |
+
if points_to_update:
|
| 289 |
+
DatoPunto.objects.bulk_update(points_to_update, ['x', 'y'])
|
| 290 |
+
|
| 291 |
+
return (existing_ratings_map, products_map)
|
| 292 |
+
|
| 293 |
+
except Exception as e:
|
| 294 |
+
print(e)
|
| 295 |
+
return JsonResponse({"error": "Error al guardar los puntos"})
|
| 296 |
+
|
| 297 |
+
@staticmethod
|
| 298 |
+
def validateWords(data: list):
|
| 299 |
+
for item in data:
|
| 300 |
+
words = item.get("words", [])
|
| 301 |
+
if words:
|
| 302 |
+
dic_words = {}
|
| 303 |
+
for index, word in enumerate(words, start=1):
|
| 304 |
+
dic_words[f"palabra_{index}"] = word
|
| 305 |
+
|
| 306 |
+
form = ListWordsForm(dic_words, new_words=words)
|
| 307 |
+
if not form.is_valid():
|
| 308 |
+
errors = []
|
| 309 |
+
for field, error_list in form.errors.items():
|
| 310 |
+
errors.extend(error_list)
|
| 311 |
+
return JsonResponse({"error": f"Error en validación de palabras: {', '.join(errors)}"})
|
| 312 |
+
return None
|
| 313 |
+
|
| 314 |
+
@staticmethod
|
| 315 |
+
def processWordsForRatings(data: list, existing_ratings_map: dict):
|
| 316 |
+
all_words = set()
|
| 317 |
+
for item in data:
|
| 318 |
+
words = item.get("words", [])
|
| 319 |
+
if words:
|
| 320 |
+
all_words.update(words)
|
| 321 |
+
|
| 322 |
+
if not all_words:
|
| 323 |
+
return
|
| 324 |
+
|
| 325 |
+
existing_words = Palabra.objects.filter(
|
| 326 |
+
nombre_palabra__in=all_words
|
| 327 |
+
)
|
| 328 |
+
existing_words_map = {w.nombre_palabra: w for w in existing_words}
|
| 329 |
+
|
| 330 |
+
word_objects = {}
|
| 331 |
+
for word_name in all_words:
|
| 332 |
+
if word_name in existing_words_map:
|
| 333 |
+
word_objects[word_name] = existing_words_map[word_name]
|
| 334 |
+
else:
|
| 335 |
+
word_obj, created = Palabra.objects.get_or_create(
|
| 336 |
+
nombre_palabra=word_name
|
| 337 |
+
)
|
| 338 |
+
word_objects[word_name] = word_obj
|
| 339 |
+
|
| 340 |
+
for item in data:
|
| 341 |
+
words = item.get("words", [])
|
| 342 |
+
if words:
|
| 343 |
+
product_id = int(item["idProduct"])
|
| 344 |
+
rating = existing_ratings_map.get(product_id)
|
| 345 |
+
|
| 346 |
+
if rating:
|
| 347 |
+
words_to_set = [word_objects[word_name]
|
| 348 |
+
for word_name in words]
|
| 349 |
+
rating.palabras.set(words_to_set)
|
| 350 |
+
|
| 351 |
+
@staticmethod
|
| 352 |
+
def getProductsMap(id_tecnica):
|
| 353 |
+
products_qs = Producto.objects.filter(id_tecnica=id_tecnica)
|
| 354 |
+
return {p.id: p for p in products_qs}
|
| 355 |
+
|
| 356 |
+
@staticmethod
|
| 357 |
+
def getExistingRatingsMap(id_tecnica, id_catador):
|
| 358 |
+
ratings = Calificacion.objects.filter(
|
| 359 |
+
id_tecnica=id_tecnica,
|
| 360 |
+
id_catador=id_catador,
|
| 361 |
+
)
|
| 362 |
+
return {r.id_producto.id: r for r in ratings}
|
| 363 |
+
|
| 364 |
+
@staticmethod
|
| 365 |
+
def getExistingPointsMap(ratings):
|
| 366 |
+
points = DatoPunto.objects.filter(calificacion__in=ratings)
|
| 367 |
+
return {p.calificacion.id: p for p in points}
|
tecnicas/controllers/api_controller/rating_pf_list_controller.py
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import JsonResponse, HttpRequest
|
| 2 |
+
from django.db import transaction, IntegrityError
|
| 3 |
+
from tecnicas.models import Palabra, ListaPalabras, Participacion, Calificacion, Producto, Dato, ValorDecimal
|
| 4 |
+
from tecnicas.forms import ListWordsForm
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class RatingPFListController():
|
| 8 |
+
def __init__(self):
|
| 9 |
+
pass
|
| 10 |
+
|
| 11 |
+
@staticmethod
|
| 12 |
+
def getListWords(request: HttpRequest):
|
| 13 |
+
participation_current_tester = Participacion.objects.get(
|
| 14 |
+
id=request.session["id_participation"])
|
| 15 |
+
|
| 16 |
+
technique = participation_current_tester.tecnica
|
| 17 |
+
|
| 18 |
+
participations_testers = Participacion.objects.exclude(
|
| 19 |
+
catador=participation_current_tester.catador).filter(tecnica=technique)
|
| 20 |
+
|
| 21 |
+
all_testers = [
|
| 22 |
+
participation.catador for participation in participations_testers]
|
| 23 |
+
|
| 24 |
+
list_words_testers = list(ListaPalabras.objects.filter(
|
| 25 |
+
tecnica=technique, catador__in=all_testers, es_final=True))
|
| 26 |
+
|
| 27 |
+
if not list_words_testers:
|
| 28 |
+
return JsonResponse({"error": "Aun no hay listas finales de Catadores"})
|
| 29 |
+
|
| 30 |
+
result = []
|
| 31 |
+
for list_tester in list_words_testers:
|
| 32 |
+
try:
|
| 33 |
+
username = list_tester.catador.user.username
|
| 34 |
+
except Exception:
|
| 35 |
+
username = None
|
| 36 |
+
|
| 37 |
+
finish = [
|
| 38 |
+
participation.finalizado for participation in participations_testers if participation.catador.user.username == username][0]
|
| 39 |
+
|
| 40 |
+
status = "Lista terminada" if finish else "Lista en proceso"
|
| 41 |
+
|
| 42 |
+
words_qs = list_tester.palabras.all()
|
| 43 |
+
words = []
|
| 44 |
+
for p in words_qs:
|
| 45 |
+
nombre = getattr(p, 'nombre_palabra', None)
|
| 46 |
+
words.append({
|
| 47 |
+
'id': getattr(p, 'id', None),
|
| 48 |
+
'nombre_palabra': nombre
|
| 49 |
+
})
|
| 50 |
+
|
| 51 |
+
result.append({
|
| 52 |
+
'username': username,
|
| 53 |
+
'words': words,
|
| 54 |
+
'status': status
|
| 55 |
+
})
|
| 56 |
+
|
| 57 |
+
return JsonResponse({
|
| 58 |
+
"message": "Listas encontradas",
|
| 59 |
+
"lists_words": result
|
| 60 |
+
})
|
| 61 |
+
|
| 62 |
+
@staticmethod
|
| 63 |
+
def saveList(request: HttpRequest, words: list, current_phase: int):
|
| 64 |
+
dic_words = {}
|
| 65 |
+
for index, word in enumerate(words, start=1):
|
| 66 |
+
dic_words[f"palabra_{index}"] = word
|
| 67 |
+
|
| 68 |
+
form = ListWordsForm(dic_words, new_words=words)
|
| 69 |
+
|
| 70 |
+
if form.is_valid():
|
| 71 |
+
participation = Participacion.objects.get(
|
| 72 |
+
id=request.session["id_participation"])
|
| 73 |
+
|
| 74 |
+
if not participation:
|
| 75 |
+
return JsonResponse({"error": "No está autorizado en la sesión"})
|
| 76 |
+
|
| 77 |
+
technique = participation.tecnica
|
| 78 |
+
|
| 79 |
+
list_words_tester: ListaPalabras
|
| 80 |
+
if current_phase == 1:
|
| 81 |
+
(list_words_tester, created) = ListaPalabras.objects.get_or_create(
|
| 82 |
+
tecnica=technique,
|
| 83 |
+
catador=request.user.user_catador,
|
| 84 |
+
es_final=False,
|
| 85 |
+
)
|
| 86 |
+
elif current_phase == 2:
|
| 87 |
+
(list_words_tester, created) = ListaPalabras.objects.get_or_create(
|
| 88 |
+
tecnica=technique,
|
| 89 |
+
catador=request.user.user_catador,
|
| 90 |
+
es_final=True,
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
added_words = RatingPFListController.addWordsToListWordsTester(
|
| 94 |
+
list_words=words, list_tester=list_words_tester)
|
| 95 |
+
|
| 96 |
+
response = JsonResponse({
|
| 97 |
+
"message": "Palabras guardadas con exito",
|
| 98 |
+
"words": [word.nombre_palabra for word in added_words]
|
| 99 |
+
})
|
| 100 |
+
else:
|
| 101 |
+
response = JsonResponse({"error": "Palabras invalidas"})
|
| 102 |
+
|
| 103 |
+
return response
|
| 104 |
+
|
| 105 |
+
@staticmethod
|
| 106 |
+
def addWordsToListWordsTester(list_words: list[str], list_tester: ListaPalabras):
|
| 107 |
+
# Normalizar
|
| 108 |
+
clean_words = [s.strip() for s in list_words if s.strip()]
|
| 109 |
+
|
| 110 |
+
# Obtener existentes
|
| 111 |
+
all_words = Palabra.objects.filter(nombre_palabra__in=clean_words)
|
| 112 |
+
|
| 113 |
+
names_words_exist = set(
|
| 114 |
+
all_words.values_list('nombre_palabra', flat=True))
|
| 115 |
+
|
| 116 |
+
# Ejecutar el query para no sumar palabras repetidas
|
| 117 |
+
all_words = list(all_words)
|
| 118 |
+
|
| 119 |
+
# Determinar faltantes
|
| 120 |
+
missing_words = [
|
| 121 |
+
nombre for nombre in clean_words if nombre not in names_words_exist]
|
| 122 |
+
print("No save words", missing_words)
|
| 123 |
+
|
| 124 |
+
created_words = []
|
| 125 |
+
|
| 126 |
+
# Intentar crear missing_words
|
| 127 |
+
for nombre in missing_words:
|
| 128 |
+
try:
|
| 129 |
+
with transaction.atomic():
|
| 130 |
+
palabra, created = Palabra.objects.get_or_create(
|
| 131 |
+
nombre_palabra=nombre)
|
| 132 |
+
if created:
|
| 133 |
+
created_words.append(palabra)
|
| 134 |
+
except IntegrityError:
|
| 135 |
+
palabra = Palabra.objects.get(nombre_palabra=nombre)
|
| 136 |
+
created_words.append(palabra)
|
| 137 |
+
|
| 138 |
+
# Combinar todas (all_words + created_words)
|
| 139 |
+
all_new_words = all_words + created_words
|
| 140 |
+
|
| 141 |
+
list_tester.palabras.set(all_new_words)
|
| 142 |
+
|
| 143 |
+
return all_new_words
|
| 144 |
+
|
| 145 |
+
@staticmethod
|
| 146 |
+
def saveRatings(request: HttpRequest, word_rating: str, data: list):
|
| 147 |
+
participation = Participacion.objects.get(
|
| 148 |
+
id=request.session["id_participation"])
|
| 149 |
+
|
| 150 |
+
technique = participation.tecnica
|
| 151 |
+
products = Producto.objects.filter(id_tecnica=technique)
|
| 152 |
+
|
| 153 |
+
# Crear o obtener las instancias Calificacion en la repeticion de todos los producutos
|
| 154 |
+
ratings = Calificacion.objects.filter(
|
| 155 |
+
num_repeticion=technique.repeticion,
|
| 156 |
+
id_tecnica=technique,
|
| 157 |
+
id_catador=participation.catador,
|
| 158 |
+
id_producto__in=products
|
| 159 |
+
)
|
| 160 |
+
|
| 161 |
+
existing_dict = {rating.id_producto_id: rating for rating in ratings}
|
| 162 |
+
to_create = []
|
| 163 |
+
|
| 164 |
+
for product in products:
|
| 165 |
+
if product.id not in existing_dict:
|
| 166 |
+
to_create.append(
|
| 167 |
+
Calificacion(
|
| 168 |
+
num_repeticion=technique.repeticion,
|
| 169 |
+
id_producto=product,
|
| 170 |
+
id_tecnica=technique,
|
| 171 |
+
id_catador=participation.catador
|
| 172 |
+
)
|
| 173 |
+
)
|
| 174 |
+
Calificacion.objects.bulk_create(to_create)
|
| 175 |
+
|
| 176 |
+
ratings = Calificacion.objects.filter(
|
| 177 |
+
num_repeticion=technique.repeticion,
|
| 178 |
+
id_tecnica=technique,
|
| 179 |
+
id_catador=participation.catador,
|
| 180 |
+
id_producto__in=products
|
| 181 |
+
)
|
| 182 |
+
|
| 183 |
+
# Guardar datos con ValorDecimal
|
| 184 |
+
word = Palabra.objects.get(nombre_palabra=word_rating)
|
| 185 |
+
try:
|
| 186 |
+
if (
|
| 187 |
+
len(data) != len(products) or
|
| 188 |
+
len(data) != len(ratings) or
|
| 189 |
+
len(products) != len(ratings)
|
| 190 |
+
):
|
| 191 |
+
raise ValueError(
|
| 192 |
+
"Al parecer los datos mandados no corresponden con el total de productos")
|
| 193 |
+
|
| 194 |
+
product_values = {info["product"]["code"]: info["value"] for info in data}
|
| 195 |
+
|
| 196 |
+
datos_to_create = []
|
| 197 |
+
values_to_create = []
|
| 198 |
+
|
| 199 |
+
with transaction.atomic():
|
| 200 |
+
for rating in ratings:
|
| 201 |
+
datos_to_create.append(Dato(
|
| 202 |
+
id_palabra=word,
|
| 203 |
+
id_calificacion=rating
|
| 204 |
+
))
|
| 205 |
+
|
| 206 |
+
datos_save = Dato.objects.bulk_create(datos_to_create)
|
| 207 |
+
save_data = Dato.objects.filter(id_palabra=word, id_calificacion__in=ratings)
|
| 208 |
+
|
| 209 |
+
for data_save in save_data:
|
| 210 |
+
values_to_create.append(ValorDecimal(
|
| 211 |
+
id_dato=data_save,
|
| 212 |
+
valor=product_values.get(data_save.id_calificacion.id_producto.codigoProducto)
|
| 213 |
+
))
|
| 214 |
+
|
| 215 |
+
ValorDecimal.objects.bulk_create(values_to_create)
|
| 216 |
+
|
| 217 |
+
return JsonResponse({"message": "Calificaciones guardadas con exito"})
|
| 218 |
+
except ValueError as e:
|
| 219 |
+
error_message = str(e)
|
| 220 |
+
print(f"Error de calificacion: {error_message}")
|
| 221 |
+
return JsonResponse({"error": error_message})
|
tecnicas/controllers/{views_controller/api_rating_controller.py → api_controller/rating_sacales_controller.py}
RENAMED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
-
from
|
| 2 |
from ...utils import controller_error
|
| 3 |
|
| 4 |
|
| 5 |
-
class
|
| 6 |
def __init__(self, rating_controller: CalificacionController, data_controller: DatoController):
|
| 7 |
self.rating_controller = rating_controller
|
| 8 |
self.data_controller = data_controller
|
|
|
|
| 1 |
+
from .. import CalificacionController, DatoController
|
| 2 |
from ...utils import controller_error
|
| 3 |
|
| 4 |
|
| 5 |
+
class RatingScalesController():
|
| 6 |
def __init__(self, rating_controller: CalificacionController, data_controller: DatoController):
|
| 7 |
self.rating_controller = rating_controller
|
| 8 |
self.data_controller = data_controller
|
tecnicas/controllers/api_controller/rating_sort_controller.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import JsonResponse, HttpRequest
|
| 2 |
+
from django.db import transaction
|
| 3 |
+
from tecnicas.models import Participacion, Palabra, GrupoProducto, Producto
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class RatingSortController():
|
| 7 |
+
def __init__(self):
|
| 8 |
+
pass
|
| 9 |
+
|
| 10 |
+
@staticmethod
|
| 11 |
+
def saveRating(request: HttpRequest, data: list[dict]):
|
| 12 |
+
try:
|
| 13 |
+
with transaction.atomic():
|
| 14 |
+
participation = Participacion.objects.get(
|
| 15 |
+
id=request.session["id_participation"])
|
| 16 |
+
|
| 17 |
+
technique = participation.tecnica
|
| 18 |
+
catador = participation.catador
|
| 19 |
+
|
| 20 |
+
# Obtener productos de la técnica
|
| 21 |
+
technique_products = Producto.objects.filter(
|
| 22 |
+
id_tecnica=technique)
|
| 23 |
+
technique_product_ids = set(p.id for p in technique_products)
|
| 24 |
+
|
| 25 |
+
# Recolectar IDs de productos enviados
|
| 26 |
+
sent_product_ids = set()
|
| 27 |
+
for group in data:
|
| 28 |
+
for product in group["products"]:
|
| 29 |
+
sent_product_ids.add(int(product["id"]))
|
| 30 |
+
|
| 31 |
+
# Validar que los productos enviados existan en la técnica
|
| 32 |
+
if not sent_product_ids.issubset(technique_product_ids):
|
| 33 |
+
return JsonResponse({"error": "Productos enviados no pertenecen a la técnica"})
|
| 34 |
+
|
| 35 |
+
# Validar que todos los productos de la técnica estén presentes
|
| 36 |
+
if sent_product_ids != technique_product_ids:
|
| 37 |
+
return JsonResponse({"error": "Faltan productos por clasificar"})
|
| 38 |
+
|
| 39 |
+
for group in data:
|
| 40 |
+
words_data = group["words"]
|
| 41 |
+
products_data = group["products"]
|
| 42 |
+
|
| 43 |
+
# Crear u obtener palabras
|
| 44 |
+
words_objs = []
|
| 45 |
+
for word_name in words_data:
|
| 46 |
+
word, created = Palabra.objects.get_or_create(nombre_palabra=word_name)
|
| 47 |
+
words_objs.append(word)
|
| 48 |
+
|
| 49 |
+
# Crear GrupoProducto
|
| 50 |
+
group_product = GrupoProducto.objects.create(
|
| 51 |
+
tecnica=technique,
|
| 52 |
+
catador=catador
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
# Asignar palabras
|
| 56 |
+
group_product.palabras.set(words_objs)
|
| 57 |
+
|
| 58 |
+
# Asignar productos
|
| 59 |
+
product_ids = [p["id"] for p in products_data]
|
| 60 |
+
group_product.productos.set(product_ids)
|
| 61 |
+
|
| 62 |
+
return JsonResponse({"message": "Valores guardados"})
|
| 63 |
+
except Participacion.DoesNotExist:
|
| 64 |
+
return JsonResponse({"error": "Participación no encontrada"})
|
| 65 |
+
except Exception as e:
|
| 66 |
+
print(f"Error de calificacion: {e}")
|
| 67 |
+
return JsonResponse({"error": "Error al guardar los datos"})
|
tecnicas/controllers/models_controller/calificacion_controller.py
CHANGED
|
@@ -21,7 +21,7 @@ class CalificacionController():
|
|
| 21 |
@staticmethod
|
| 22 |
def getRatingsByTechnique(technique: Tecnica):
|
| 23 |
repetition = technique.repeticion
|
| 24 |
-
ratings = list(Calificacion.objects.filter(id_tecnica=technique))
|
| 25 |
return ratings
|
| 26 |
|
| 27 |
@staticmethod
|
|
|
|
| 21 |
@staticmethod
|
| 22 |
def getRatingsByTechnique(technique: Tecnica):
|
| 23 |
repetition = technique.repeticion
|
| 24 |
+
ratings = list(Calificacion.objects.filter(id_tecnica=technique, num_repeticion=repetition))
|
| 25 |
return ratings
|
| 26 |
|
| 27 |
@staticmethod
|
tecnicas/controllers/models_controller/dato_controller.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
-
from
|
| 2 |
-
from
|
| 3 |
from django.core.exceptions import ValidationError
|
| 4 |
from django.db.models import F
|
| 5 |
|
|
@@ -12,11 +12,7 @@ class DatoController():
|
|
| 12 |
}
|
| 13 |
|
| 14 |
self.data = Dato(**atributes)
|
| 15 |
-
|
| 16 |
-
if isinstance(value_rating, bool):
|
| 17 |
-
self.value_data = ValorBooleano(valor=value_rating)
|
| 18 |
-
else:
|
| 19 |
-
self.value_data = ValorDecimal(valor=value_rating)
|
| 20 |
|
| 21 |
def setRating(self, new_rating: Calificacion):
|
| 22 |
try:
|
|
@@ -39,15 +35,23 @@ class DatoController():
|
|
| 39 |
except ValidationError as e:
|
| 40 |
return controller_error(e.message)
|
| 41 |
|
| 42 |
-
def setValue(self
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
self.value_data = ValorDecimal(valor=new_value)
|
| 48 |
else:
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
return self.value_data
|
| 52 |
|
| 53 |
def saveValue(self):
|
|
@@ -94,3 +98,21 @@ class DatoController():
|
|
| 94 |
)
|
| 95 |
|
| 96 |
return list(result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from tecnicas.models import Calificacion, Dato, Palabra, ValorDecimal, ValorBooleano, Tecnica, Catador
|
| 2 |
+
from tecnicas.utils import controller_error, getId
|
| 3 |
from django.core.exceptions import ValidationError
|
| 4 |
from django.db.models import F
|
| 5 |
|
|
|
|
| 12 |
}
|
| 13 |
|
| 14 |
self.data = Dato(**atributes)
|
| 15 |
+
self.value_rating = value_rating
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
def setRating(self, new_rating: Calificacion):
|
| 18 |
try:
|
|
|
|
| 35 |
except ValidationError as e:
|
| 36 |
return controller_error(e.message)
|
| 37 |
|
| 38 |
+
def setValue(self):
|
| 39 |
+
type_technique = self.data.id_calificacion.id_tecnica.tipo_tecnica
|
| 40 |
+
if type_technique == "cata":
|
| 41 |
+
self.value_data = ValorBooleano(valor=self.value_rating)
|
| 42 |
+
|
|
|
|
| 43 |
else:
|
| 44 |
+
type_scale = self.data.id_calificacion.id_tecnica.escala_tecnica.id_tipo_escala.nombre_escala
|
| 45 |
+
|
| 46 |
+
if type_scale == "continua":
|
| 47 |
+
decimal_value = self.value_rating/100
|
| 48 |
+
value_rounded = round(decimal_value)
|
| 49 |
+
self.value_data = ValorDecimal(valor=value_rounded)
|
| 50 |
|
| 51 |
+
else:
|
| 52 |
+
self.value_data = ValorDecimal(valor=self.value_rating)
|
| 53 |
+
|
| 54 |
+
self.value_data.id_dato = self.data
|
| 55 |
return self.value_data
|
| 56 |
|
| 57 |
def saveValue(self):
|
|
|
|
| 98 |
)
|
| 99 |
|
| 100 |
return list(result)
|
| 101 |
+
|
| 102 |
+
@staticmethod
|
| 103 |
+
def getWordValuesPF(technique: Tecnica, ratings: list[Calificacion], tester: Catador):
|
| 104 |
+
ids_ratings = [rat.id for rat in ratings]
|
| 105 |
+
|
| 106 |
+
result = (
|
| 107 |
+
ValorDecimal.objects
|
| 108 |
+
.filter(id_dato__id_calificacion_id__in=ids_ratings, id_dato__id_calificacion__id_catador=tester)
|
| 109 |
+
.values(
|
| 110 |
+
nombre_palabra=F("id_dato__id_palabra__nombre_palabra"),
|
| 111 |
+
repeticion=F("id_dato__id_calificacion__num_repeticion"),
|
| 112 |
+
producto_code=F(
|
| 113 |
+
"id_dato__id_calificacion__id_producto__codigoProducto"),
|
| 114 |
+
dato_valor=F("valor")
|
| 115 |
+
)
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
return list(result)
|
tecnicas/controllers/models_controller/escala_controller.py
CHANGED
|
@@ -7,19 +7,25 @@ class EscalaController():
|
|
| 7 |
scale: Escala
|
| 8 |
tags_relation: dict[str, EtiquetasEscala]
|
| 9 |
|
| 10 |
-
def __init__(self, data):
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
|
| 24 |
def saveScale(self):
|
| 25 |
try:
|
|
|
|
| 7 |
scale: Escala
|
| 8 |
tags_relation: dict[str, EtiquetasEscala]
|
| 9 |
|
| 10 |
+
def __init__(self, data, use_scale: Escala = None):
|
| 11 |
+
if use_scale:
|
| 12 |
+
self.scale = use_scale
|
| 13 |
+
else:
|
| 14 |
+
self.scale = Escala(
|
| 15 |
+
id_tipo_escala=TipoEscala.objects.get(id=data["id_scale"]),
|
| 16 |
+
longitud=data["size"],
|
| 17 |
+
tecnica=data["technique"]
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
def setScale(self, newData, use_scale: Escala):
|
| 21 |
+
if use_scale:
|
| 22 |
+
self.scale = use_scale
|
| 23 |
+
else:
|
| 24 |
+
self.scale = Escala(
|
| 25 |
+
id_tipo_escala=TipoEscala.objects.get(id=data["id_scale"]),
|
| 26 |
+
longitud=data["size"],
|
| 27 |
+
tecnica=data["technique"]
|
| 28 |
+
)
|
| 29 |
|
| 30 |
def saveScale(self):
|
| 31 |
try:
|
tecnicas/controllers/models_controller/particiapacion_controller.py
CHANGED
|
@@ -35,24 +35,14 @@ class ParticipacionController():
|
|
| 35 |
return controller_error("No se ha encontrado la participación")
|
| 36 |
|
| 37 |
@staticmethod
|
| 38 |
-
def outAllInSession(session: SesionSensorial
|
| 39 |
try:
|
| 40 |
-
if isinstance(session, str):
|
| 41 |
-
use_session = SesionSensorial.objects.get(
|
| 42 |
-
codigo_sesion=session)
|
| 43 |
-
else:
|
| 44 |
-
use_session = session
|
| 45 |
-
|
| 46 |
participations = Participacion.objects.filter(
|
| 47 |
-
tecnica=
|
| 48 |
-
|
| 49 |
-
if not participations.exists():
|
| 50 |
-
message = "No se encontraron participaciones en la sesión"
|
| 51 |
-
return (False, message)
|
| 52 |
|
| 53 |
participations.update(finalizado=False)
|
| 54 |
|
| 55 |
-
message = "Participaciones actualizadas a finalizadas"
|
| 56 |
return (True, message)
|
| 57 |
except Exception as e:
|
| 58 |
print(f"Error al actualizar las participaciones: {str(e)}")
|
|
|
|
| 35 |
return controller_error("No se ha encontrado la participación")
|
| 36 |
|
| 37 |
@staticmethod
|
| 38 |
+
def outAllInSession(session: SesionSensorial):
|
| 39 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
participations = Participacion.objects.filter(
|
| 41 |
+
tecnica=session.tecnica)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
participations.update(finalizado=False)
|
| 44 |
|
| 45 |
+
message = "Participaciones actualizadas a finalizadas como falso"
|
| 46 |
return (True, message)
|
| 47 |
except Exception as e:
|
| 48 |
print(f"Error al actualizar las participaciones: {str(e)}")
|
tecnicas/controllers/models_controller/sesion_controller.py
CHANGED
|
@@ -125,12 +125,7 @@ class SesionController():
|
|
| 125 |
return controller_error("Presentador invalido")
|
| 126 |
|
| 127 |
@staticmethod
|
| 128 |
-
def finishRepetion(session: SesionSensorial
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
else:
|
| 132 |
-
use_session = session
|
| 133 |
-
|
| 134 |
-
use_session.activo = False
|
| 135 |
-
use_session.save()
|
| 136 |
return session
|
|
|
|
| 125 |
return controller_error("Presentador invalido")
|
| 126 |
|
| 127 |
@staticmethod
|
| 128 |
+
def finishRepetion(session: SesionSensorial):
|
| 129 |
+
session.activo = False
|
| 130 |
+
session.save()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
return session
|
tecnicas/controllers/models_controller/tecnica_controller.py
CHANGED
|
@@ -16,7 +16,7 @@ class TecnicaController():
|
|
| 16 |
def setTechniqueFromBasicData(self, basic):
|
| 17 |
self.technique = Tecnica(
|
| 18 |
tipo_tecnica=TipoTecnica.objects.get(nombre_tecnica=basic["name_tecnica"]),
|
| 19 |
-
id_estilo=EstiloPalabra.objects.get(
|
| 20 |
repeticiones_max=basic["numero_repeticiones"] or 1,
|
| 21 |
limite_catadores=basic["numero_catadores"],
|
| 22 |
instrucciones=basic["instrucciones"] or "Espere instrucciones del Presentador",
|
|
|
|
| 16 |
def setTechniqueFromBasicData(self, basic):
|
| 17 |
self.technique = Tecnica(
|
| 18 |
tipo_tecnica=TipoTecnica.objects.get(nombre_tecnica=basic["name_tecnica"]),
|
| 19 |
+
id_estilo=EstiloPalabra.objects.get(nombre_estilo=basic["estilo_palabras"]),
|
| 20 |
repeticiones_max=basic["numero_repeticiones"] or 1,
|
| 21 |
limite_catadores=basic["numero_catadores"],
|
| 22 |
instrucciones=basic["instrucciones"] or "Espere instrucciones del Presentador",
|
tecnicas/controllers/views_controller/create_session/panel_basic_controller.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
from tecnicas.forms import SesionBasicForm, SesionBasicCATAForm
|
| 2 |
from django.http import HttpRequest
|
| 3 |
from django.shortcuts import redirect, render
|
| 4 |
from django.urls import reverse
|
|
@@ -10,11 +10,14 @@ class PanelBasicController():
|
|
| 10 |
"numero_repeticiones": 1
|
| 11 |
}
|
| 12 |
|
| 13 |
-
url_panel_basic = "tecnicas/create_sesion/
|
| 14 |
url_panel_basic_cata = "tecnicas/create_sesion/panel-basic-cata.html"
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
-
|
| 17 |
-
|
| 18 |
|
| 19 |
url_select_technique = "cata_system:seleccion_tecnica"
|
| 20 |
|
|
@@ -42,7 +45,7 @@ class PanelBasicController():
|
|
| 42 |
if form.is_valid():
|
| 43 |
values = {}
|
| 44 |
for name, value in form.cleaned_data.items():
|
| 45 |
-
if name == "
|
| 46 |
values[name] = value.id
|
| 47 |
else:
|
| 48 |
values[name] = value
|
|
@@ -50,7 +53,7 @@ class PanelBasicController():
|
|
| 50 |
values["name_tecnica"] = name_tecnica
|
| 51 |
request.session['form_basic'] = values
|
| 52 |
response = redirect(
|
| 53 |
-
reverse(
|
| 54 |
else:
|
| 55 |
response = render(request, PanelBasicController.url_panel_basic, {
|
| 56 |
"form_sesion": form, "error": "Información no valida"})
|
|
@@ -83,7 +86,7 @@ class PanelBasicController():
|
|
| 83 |
if form.is_valid():
|
| 84 |
values = {}
|
| 85 |
for name, value in form.cleaned_data.items():
|
| 86 |
-
if name == "
|
| 87 |
values[name] = value.id
|
| 88 |
else:
|
| 89 |
values[name] = value
|
|
@@ -102,7 +105,7 @@ class PanelBasicController():
|
|
| 102 |
values["name_tecnica"] = name_tecnica
|
| 103 |
request.session['form_basic'] = values
|
| 104 |
response = redirect(
|
| 105 |
-
reverse(
|
| 106 |
else:
|
| 107 |
response = render(request, PanelBasicController.url_panel_basic, {
|
| 108 |
"form_sesion": form, "error": "Información no valida"})
|
|
@@ -131,17 +134,107 @@ class PanelBasicController():
|
|
| 131 |
if form.is_valid():
|
| 132 |
values = {}
|
| 133 |
for name, value in form.cleaned_data.items():
|
| 134 |
-
|
| 135 |
-
values[name] = value.id
|
| 136 |
-
else:
|
| 137 |
-
values[name] = value
|
| 138 |
|
| 139 |
values["name_tecnica"] = name_tecnica
|
| 140 |
request.session['form_basic'] = values
|
| 141 |
response = redirect(
|
| 142 |
-
reverse(PanelBasicController.
|
| 143 |
else:
|
| 144 |
response = render(request, PanelBasicController.url_panel_basic, {
|
| 145 |
"form_sesion": form, "error": "Información no valida"})
|
| 146 |
|
| 147 |
return response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from tecnicas.forms import SesionBasicForm, SesionBasicCATAForm, SesionBasicPFForm, SesionBasicSortForm, SesionBasicNappingForm
|
| 2 |
from django.http import HttpRequest
|
| 3 |
from django.shortcuts import redirect, render
|
| 4 |
from django.urls import reverse
|
|
|
|
| 10 |
"numero_repeticiones": 1
|
| 11 |
}
|
| 12 |
|
| 13 |
+
url_panel_basic = "tecnicas/create_sesion/conf-panel-basic.html"
|
| 14 |
url_panel_basic_cata = "tecnicas/create_sesion/panel-basic-cata.html"
|
| 15 |
+
url_panel_basic_pf = "tecnicas/create_sesion/panel-basic-pf.html"
|
| 16 |
+
url_panel_basic_sort = "tecnicas/create_sesion/panel-basic-sort.html"
|
| 17 |
+
url_panel_basic_napping = "tecnicas/create_sesion/panel-basic-napping.html"
|
| 18 |
|
| 19 |
+
url_next_panel_tags = "cata_system:panel_configuracion_tags"
|
| 20 |
+
url_next_panel_codes = "cata_system:panel_configuracion_codes"
|
| 21 |
|
| 22 |
url_select_technique = "cata_system:seleccion_tecnica"
|
| 23 |
|
|
|
|
| 45 |
if form.is_valid():
|
| 46 |
values = {}
|
| 47 |
for name, value in form.cleaned_data.items():
|
| 48 |
+
if name == "tipo_escala":
|
| 49 |
values[name] = value.id
|
| 50 |
else:
|
| 51 |
values[name] = value
|
|
|
|
| 53 |
values["name_tecnica"] = name_tecnica
|
| 54 |
request.session['form_basic'] = values
|
| 55 |
response = redirect(
|
| 56 |
+
reverse(PanelBasicController.url_next_panel_tags))
|
| 57 |
else:
|
| 58 |
response = render(request, PanelBasicController.url_panel_basic, {
|
| 59 |
"form_sesion": form, "error": "Información no valida"})
|
|
|
|
| 86 |
if form.is_valid():
|
| 87 |
values = {}
|
| 88 |
for name, value in form.cleaned_data.items():
|
| 89 |
+
if name == "tipo_escala":
|
| 90 |
values[name] = value.id
|
| 91 |
else:
|
| 92 |
values[name] = value
|
|
|
|
| 105 |
values["name_tecnica"] = name_tecnica
|
| 106 |
request.session['form_basic'] = values
|
| 107 |
response = redirect(
|
| 108 |
+
reverse(PanelBasicController.url_next_panel_tags))
|
| 109 |
else:
|
| 110 |
response = render(request, PanelBasicController.url_panel_basic, {
|
| 111 |
"form_sesion": form, "error": "Información no valida"})
|
|
|
|
| 134 |
if form.is_valid():
|
| 135 |
values = {}
|
| 136 |
for name, value in form.cleaned_data.items():
|
| 137 |
+
values[name] = value
|
|
|
|
|
|
|
|
|
|
| 138 |
|
| 139 |
values["name_tecnica"] = name_tecnica
|
| 140 |
request.session['form_basic'] = values
|
| 141 |
response = redirect(
|
| 142 |
+
reverse(PanelBasicController.url_next_panel_codes))
|
| 143 |
else:
|
| 144 |
response = render(request, PanelBasicController.url_panel_basic, {
|
| 145 |
"form_sesion": form, "error": "Información no valida"})
|
| 146 |
|
| 147 |
return response
|
| 148 |
+
|
| 149 |
+
@staticmethod
|
| 150 |
+
def controllGetPF(request: HttpRequest):
|
| 151 |
+
form_sesion = SesionBasicPFForm()
|
| 152 |
+
|
| 153 |
+
view_context = {
|
| 154 |
+
"form_sesion": form_sesion,
|
| 155 |
+
"use_technique": "perfil flash"
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
return render(
|
| 159 |
+
request, PanelBasicController.url_panel_basic_pf, view_context)
|
| 160 |
+
|
| 161 |
+
@staticmethod
|
| 162 |
+
def controllPostPF(request: HttpRequest, name_tecnica: str):
|
| 163 |
+
form = SesionBasicPFForm(request.POST)
|
| 164 |
+
|
| 165 |
+
if form.is_valid():
|
| 166 |
+
values = {}
|
| 167 |
+
for name, value in form.cleaned_data.items():
|
| 168 |
+
values[name] = value
|
| 169 |
+
|
| 170 |
+
values["name_tecnica"] = name_tecnica
|
| 171 |
+
request.session['form_basic'] = values
|
| 172 |
+
response = redirect(
|
| 173 |
+
reverse(PanelBasicController.url_next_panel_codes))
|
| 174 |
+
else:
|
| 175 |
+
response = render(request, PanelBasicController.url_panel_basic_pf, {
|
| 176 |
+
"form_sesion": form, "error": "Información no valida"})
|
| 177 |
+
|
| 178 |
+
return response
|
| 179 |
+
|
| 180 |
+
@staticmethod
|
| 181 |
+
def controllGetSort(request: HttpRequest):
|
| 182 |
+
form_sesion = SesionBasicSortForm()
|
| 183 |
+
|
| 184 |
+
view_context = {
|
| 185 |
+
"form_sesion": form_sesion,
|
| 186 |
+
"use_technique": "sort"
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
return render(
|
| 190 |
+
request, PanelBasicController.url_panel_basic_sort, view_context)
|
| 191 |
+
|
| 192 |
+
@staticmethod
|
| 193 |
+
def controllPostSort(request: HttpRequest, name_tecnica: str):
|
| 194 |
+
form = SesionBasicSortForm(request.POST)
|
| 195 |
+
|
| 196 |
+
if form.is_valid():
|
| 197 |
+
values = {}
|
| 198 |
+
for name, value in form.cleaned_data.items():
|
| 199 |
+
values[name] = value
|
| 200 |
+
|
| 201 |
+
values["name_tecnica"] = name_tecnica
|
| 202 |
+
request.session['form_basic'] = values
|
| 203 |
+
response = redirect(
|
| 204 |
+
reverse(PanelBasicController.url_next_panel_codes))
|
| 205 |
+
else:
|
| 206 |
+
response = render(request, PanelBasicController.url_panel_basic_sort, {
|
| 207 |
+
"form_sesion": form, "error": "Información no valida"})
|
| 208 |
+
|
| 209 |
+
return response
|
| 210 |
+
|
| 211 |
+
@staticmethod
|
| 212 |
+
def controllGetNapping(request: HttpRequest):
|
| 213 |
+
form_sesion = SesionBasicNappingForm()
|
| 214 |
+
|
| 215 |
+
view_context = {
|
| 216 |
+
"form_sesion": form_sesion,
|
| 217 |
+
"use_technique": "napping"
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
return render(
|
| 221 |
+
request, PanelBasicController.url_panel_basic_napping, view_context)
|
| 222 |
+
|
| 223 |
+
@staticmethod
|
| 224 |
+
def controllPostNapping(request: HttpRequest, name_tecnica: str):
|
| 225 |
+
form = SesionBasicNappingForm(request.POST)
|
| 226 |
+
|
| 227 |
+
if form.is_valid():
|
| 228 |
+
values = {}
|
| 229 |
+
for name, value in form.cleaned_data.items():
|
| 230 |
+
values[name] = value
|
| 231 |
+
|
| 232 |
+
values["name_tecnica"] = name_tecnica
|
| 233 |
+
request.session['form_basic'] = values
|
| 234 |
+
response = redirect(
|
| 235 |
+
reverse(PanelBasicController.url_next_panel_codes))
|
| 236 |
+
else:
|
| 237 |
+
response = render(request, PanelBasicController.url_panel_basic_napping, {
|
| 238 |
+
"form_sesion": form, "error": "Información no valida"})
|
| 239 |
+
|
| 240 |
+
return response
|
tecnicas/controllers/views_controller/create_session/panel_codes_controller.py
CHANGED
|
@@ -7,8 +7,9 @@ import json
|
|
| 7 |
|
| 8 |
|
| 9 |
class PanelCodesController():
|
| 10 |
-
url_current_panel = "tecnicas/create_sesion/
|
| 11 |
-
|
|
|
|
| 12 |
|
| 13 |
def __init__(self):
|
| 14 |
pass
|
|
@@ -58,14 +59,14 @@ class PanelCodesController():
|
|
| 58 |
|
| 59 |
codes_sort["sort_codes"] = sorts_code
|
| 60 |
request.session["form_codes"] = codes_sort
|
| 61 |
-
return redirect(reverse(PanelCodesController.
|
| 62 |
else:
|
| 63 |
context_codes_form["error"] = "error en los datos recibidos"
|
| 64 |
|
| 65 |
return render(request, PanelCodesController.url_current_panel, context_codes_form)
|
| 66 |
|
| 67 |
@staticmethod
|
| 68 |
-
def
|
| 69 |
num_products = data["numero_productos"]
|
| 70 |
codes_products = generarCodigos(num_products)
|
| 71 |
form_codes = CodesForm(codes=codes_products)
|
|
@@ -73,13 +74,13 @@ class PanelCodesController():
|
|
| 73 |
context_codes_form = {
|
| 74 |
"form_codes": form_codes,
|
| 75 |
"num_tester": 0,
|
| 76 |
-
"use_technique":
|
| 77 |
}
|
| 78 |
|
| 79 |
return render(request, PanelCodesController.url_current_panel, context_codes_form)
|
| 80 |
|
| 81 |
@staticmethod
|
| 82 |
-
def
|
| 83 |
codes = []
|
| 84 |
context_codes_form = {}
|
| 85 |
|
|
@@ -91,12 +92,14 @@ class PanelCodesController():
|
|
| 91 |
|
| 92 |
context_codes_form = {
|
| 93 |
"form_codes": form_codes,
|
| 94 |
-
"use_technique":
|
| 95 |
}
|
| 96 |
|
| 97 |
if form_codes.is_valid():
|
| 98 |
-
|
| 99 |
-
|
|
|
|
|
|
|
| 100 |
else:
|
| 101 |
context_codes_form["error"] = "error en los datos recibidos"
|
| 102 |
|
|
@@ -114,3 +117,29 @@ class PanelCodesController():
|
|
| 114 |
}
|
| 115 |
|
| 116 |
return render(request, PanelCodesController.url_current_panel, context_codes_form)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
|
| 9 |
class PanelCodesController():
|
| 10 |
+
url_current_panel = "tecnicas/create_sesion/conf-panel-codes.html"
|
| 11 |
+
url_words = "cata_system:panel_configuracion_words"
|
| 12 |
+
url_create_session = "cata_system:creando_sesion"
|
| 13 |
|
| 14 |
def __init__(self):
|
| 15 |
pass
|
|
|
|
| 59 |
|
| 60 |
codes_sort["sort_codes"] = sorts_code
|
| 61 |
request.session["form_codes"] = codes_sort
|
| 62 |
+
return redirect(reverse(PanelCodesController.url_words))
|
| 63 |
else:
|
| 64 |
context_codes_form["error"] = "error en los datos recibidos"
|
| 65 |
|
| 66 |
return render(request, PanelCodesController.url_current_panel, context_codes_form)
|
| 67 |
|
| 68 |
@staticmethod
|
| 69 |
+
def controllGetWithoutOrders(request: HttpRequest, data, name_technique: str):
|
| 70 |
num_products = data["numero_productos"]
|
| 71 |
codes_products = generarCodigos(num_products)
|
| 72 |
form_codes = CodesForm(codes=codes_products)
|
|
|
|
| 74 |
context_codes_form = {
|
| 75 |
"form_codes": form_codes,
|
| 76 |
"num_tester": 0,
|
| 77 |
+
"use_technique": name_technique
|
| 78 |
}
|
| 79 |
|
| 80 |
return render(request, PanelCodesController.url_current_panel, context_codes_form)
|
| 81 |
|
| 82 |
@staticmethod
|
| 83 |
+
def controllPostWithWords(request: HttpRequest, name_technique: str):
|
| 84 |
codes = []
|
| 85 |
context_codes_form = {}
|
| 86 |
|
|
|
|
| 92 |
|
| 93 |
context_codes_form = {
|
| 94 |
"form_codes": form_codes,
|
| 95 |
+
"use_technique": name_technique
|
| 96 |
}
|
| 97 |
|
| 98 |
if form_codes.is_valid():
|
| 99 |
+
# Extract codes from cleaned_data to ensure uppercase conversion
|
| 100 |
+
cleaned_codes = [value for name, value in form_codes.cleaned_data.items() if name.startswith('producto_')]
|
| 101 |
+
request.session["form_codes"] = cleaned_codes
|
| 102 |
+
return redirect(reverse(PanelCodesController.url_words))
|
| 103 |
else:
|
| 104 |
context_codes_form["error"] = "error en los datos recibidos"
|
| 105 |
|
|
|
|
| 117 |
}
|
| 118 |
|
| 119 |
return render(request, PanelCodesController.url_current_panel, context_codes_form)
|
| 120 |
+
|
| 121 |
+
@staticmethod
|
| 122 |
+
def controllPostWithoutOrdersWords(request: HttpRequest, name_technique: str):
|
| 123 |
+
codes = []
|
| 124 |
+
context_codes_form = {}
|
| 125 |
+
|
| 126 |
+
for name, value in request.POST.items():
|
| 127 |
+
if name.__contains__("producto_"):
|
| 128 |
+
codes.append(value)
|
| 129 |
+
|
| 130 |
+
form_codes = CodesForm(request.POST, codes=codes)
|
| 131 |
+
|
| 132 |
+
context_codes_form = {
|
| 133 |
+
"form_codes": form_codes,
|
| 134 |
+
"use_technique": name_technique
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
if form_codes.is_valid():
|
| 138 |
+
# Extract codes from cleaned_data to ensure uppercase conversion
|
| 139 |
+
cleaned_codes = [value for name, value in form_codes.cleaned_data.items() if name.startswith('producto_')]
|
| 140 |
+
request.session["form_codes"] = cleaned_codes
|
| 141 |
+
return redirect(reverse(PanelCodesController.url_create_session))
|
| 142 |
+
else:
|
| 143 |
+
context_codes_form["error"] = "error en los datos recibidos"
|
| 144 |
+
|
| 145 |
+
return render(request, PanelCodesController.url_current_panel, context_codes_form)
|
tecnicas/controllers/views_controller/create_session/panel_tags_controller.py
CHANGED
|
@@ -25,7 +25,7 @@ class PanelTagsController():
|
|
| 25 |
"form_new_tag": form_new_etiqueta
|
| 26 |
}
|
| 27 |
|
| 28 |
-
return render(request, "tecnicas/create_sesion/
|
| 29 |
|
| 30 |
@staticmethod
|
| 31 |
def controllPostEscalas(request: HttpRequest, data):
|
|
@@ -54,7 +54,7 @@ class PanelTagsController():
|
|
| 54 |
else:
|
| 55 |
context_tags["error"] = "ha ocurrido un error"
|
| 56 |
response = render(
|
| 57 |
-
request, "tecnicas/create_sesion/
|
| 58 |
|
| 59 |
return response
|
| 60 |
|
|
|
|
| 25 |
"form_new_tag": form_new_etiqueta
|
| 26 |
}
|
| 27 |
|
| 28 |
+
return render(request, "tecnicas/create_sesion/conf-panel-tags.html", context_tags)
|
| 29 |
|
| 30 |
@staticmethod
|
| 31 |
def controllPostEscalas(request: HttpRequest, data):
|
|
|
|
| 54 |
else:
|
| 55 |
context_tags["error"] = "ha ocurrido un error"
|
| 56 |
response = render(
|
| 57 |
+
request, "tecnicas/create_sesion/conf-panel-tags.html", context_tags)
|
| 58 |
|
| 59 |
return response
|
| 60 |
|
tecnicas/controllers/views_controller/create_session/panel_words_controller.py
CHANGED
|
@@ -7,7 +7,7 @@ import json
|
|
| 7 |
|
| 8 |
|
| 9 |
class PanelWordsController():
|
| 10 |
-
current_url_escalas_atribute = "tecnicas/create_sesion/
|
| 11 |
current_url_escalas_vocabulary = "tecnicas/create_sesion/conf-panel-vocabulary.html"
|
| 12 |
|
| 13 |
def __init__(self):
|
|
|
|
| 7 |
|
| 8 |
|
| 9 |
class PanelWordsController():
|
| 10 |
+
current_url_escalas_atribute = "tecnicas/create_sesion/conf-panel-words.html"
|
| 11 |
current_url_escalas_vocabulary = "tecnicas/create_sesion/conf-panel-vocabulary.html"
|
| 12 |
|
| 13 |
def __init__(self):
|
tecnicas/controllers/views_controller/create_session/panels_create/panel_create_cata_controller.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .panel_create_controller import PanelCreateController
|
| 2 |
+
from django.http import HttpRequest, JsonResponse
|
| 3 |
+
from django.db import transaction
|
| 4 |
+
from tecnicas.models import EsVocabulario, Tecnica, TipoTecnica, EstiloPalabra, EsAtributo, Vocabulario, Palabra, SesionSensorial, Producto
|
| 5 |
+
from tecnicas.utils import deleteDataSession, general_error
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class PanelCreateCataController(PanelCreateController):
|
| 9 |
+
def __init__(self):
|
| 10 |
+
super().__init__()
|
| 11 |
+
|
| 12 |
+
@staticmethod
|
| 13 |
+
def controllPost(request: HttpRequest):
|
| 14 |
+
if request.POST.get('action') == 'create_session':
|
| 15 |
+
if not request.session.get("form_codes") or not request.session.get("form_words"):
|
| 16 |
+
deleteDataSession(request)
|
| 17 |
+
return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo")
|
| 18 |
+
try:
|
| 19 |
+
with transaction.atomic():
|
| 20 |
+
# //////////////////////////// #
|
| 21 |
+
#
|
| 22 |
+
# First step: Create technique #
|
| 23 |
+
#
|
| 24 |
+
# //////////////////////////// #
|
| 25 |
+
data_basic = request.session["form_basic"]
|
| 26 |
+
data_basic["numero_catadores"] = 0
|
| 27 |
+
data_basic["numero_repeticiones"] = 1
|
| 28 |
+
|
| 29 |
+
technique = Tecnica.objects.create(
|
| 30 |
+
tipo_tecnica=TipoTecnica.objects.get(
|
| 31 |
+
nombre_tecnica=data_basic["name_tecnica"]),
|
| 32 |
+
id_estilo=EstiloPalabra.objects.get(
|
| 33 |
+
nombre_estilo=data_basic["estilo_palabras"]),
|
| 34 |
+
repeticiones_max=data_basic["numero_repeticiones"] or 1,
|
| 35 |
+
limite_catadores=data_basic["numero_catadores"],
|
| 36 |
+
instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador",
|
| 37 |
+
)
|
| 38 |
+
|
| 39 |
+
if not technique:
|
| 40 |
+
raise ValueError("Error al guardar la técnica")
|
| 41 |
+
|
| 42 |
+
# ////////////////////////////////////////////// #
|
| 43 |
+
#
|
| 44 |
+
# Second step: Create productos with their codes #
|
| 45 |
+
#
|
| 46 |
+
# ////////////////////////////////////////////// #
|
| 47 |
+
codes = request.session["form_codes"]
|
| 48 |
+
|
| 49 |
+
if not codes:
|
| 50 |
+
raise ValueError("No hay códigos de productos")
|
| 51 |
+
|
| 52 |
+
products_without_save = []
|
| 53 |
+
for code in codes:
|
| 54 |
+
product = Producto(
|
| 55 |
+
codigoProducto=code,
|
| 56 |
+
id_tecnica=technique
|
| 57 |
+
)
|
| 58 |
+
products_without_save.append(product)
|
| 59 |
+
|
| 60 |
+
Producto.objects.bulk_create(products_without_save)
|
| 61 |
+
|
| 62 |
+
# /////////////////////////////////////////////////////// #
|
| 63 |
+
#
|
| 64 |
+
# Third step: Create relations technique with Words Style #
|
| 65 |
+
#
|
| 66 |
+
# /////////////////////////////////////////////////////// #
|
| 67 |
+
style_words = technique.id_estilo.nombre_estilo
|
| 68 |
+
|
| 69 |
+
if style_words == "atributos":
|
| 70 |
+
raw_ids_words = request.session["form_words"]
|
| 71 |
+
ids_words = [int(id_w) for id_w in raw_ids_words]
|
| 72 |
+
|
| 73 |
+
words = Palabra.objects.filter(id__in=ids_words)
|
| 74 |
+
|
| 75 |
+
style_atribute = EsAtributo.objects.create(
|
| 76 |
+
id_tecnica=technique
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
if not style_atribute:
|
| 80 |
+
raise ValueError(
|
| 81 |
+
"Error al intentar relacionar las palabras con la técnica")
|
| 82 |
+
|
| 83 |
+
style_atribute.palabras.set(words)
|
| 84 |
+
|
| 85 |
+
elif style_words == "vocabulario":
|
| 86 |
+
name_vocabulary = request.session["form_words"]
|
| 87 |
+
try:
|
| 88 |
+
vocabulary = Vocabulario.objects.get(
|
| 89 |
+
nombre_vocabulario=name_vocabulary)
|
| 90 |
+
except Vocabulario.DoesNotExist:
|
| 91 |
+
raise ValueError("Vocabulario no encontrado")
|
| 92 |
+
|
| 93 |
+
es_vocabulary = EsVocabulario.objects.create(
|
| 94 |
+
id_tecnica=technique,
|
| 95 |
+
id_vocabulario=vocabulary
|
| 96 |
+
)
|
| 97 |
+
if not es_vocabulary:
|
| 98 |
+
raise ValueError(
|
| 99 |
+
"Error al intentar relacionar el vocabulario con la técnica")
|
| 100 |
+
|
| 101 |
+
else:
|
| 102 |
+
raise ValueError("Estilo de palabas no permitido")
|
| 103 |
+
|
| 104 |
+
# //////////////////////////////////////////////////////// #
|
| 105 |
+
#
|
| 106 |
+
# Fourth step: Create session and relat with the technique #
|
| 107 |
+
#
|
| 108 |
+
# //////////////////////////////////////////////////////// #
|
| 109 |
+
session = SesionSensorial.objects.create(
|
| 110 |
+
nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None,
|
| 111 |
+
tecnica=technique,
|
| 112 |
+
creadoPor=request.user.user_presentador
|
| 113 |
+
)
|
| 114 |
+
|
| 115 |
+
if not session:
|
| 116 |
+
raise ValueError("Error al crear sesion sensorial")
|
| 117 |
+
|
| 118 |
+
context = {
|
| 119 |
+
"message": "sesión creada",
|
| 120 |
+
"data": {
|
| 121 |
+
"codigo_sesion": session.codigo_sesion,
|
| 122 |
+
"nombre_sesion": session.nombre_sesion
|
| 123 |
+
}
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
# ////////////////////////////////// #
|
| 127 |
+
#
|
| 128 |
+
# Final step: Delete date en session #
|
| 129 |
+
#
|
| 130 |
+
# ////////////////////////////////// #
|
| 131 |
+
deleteDataSession(request)
|
| 132 |
+
return JsonResponse(context)
|
| 133 |
+
|
| 134 |
+
except ValueError as e:
|
| 135 |
+
return general_error(f"Error: {e}")
|
| 136 |
+
else:
|
| 137 |
+
return general_error("No se ha establecido acción")
|
tecnicas/controllers/views_controller/create_session/panels_create/panel_create_controller.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import JsonResponse, HttpRequest
|
| 2 |
+
from django.shortcuts import render
|
| 3 |
+
|
| 4 |
+
class PanelCreateController():
|
| 5 |
+
url_template = 'tecnicas/create_sesion/creating_session.html'
|
| 6 |
+
|
| 7 |
+
def __init__(self):
|
| 8 |
+
pass
|
| 9 |
+
|
| 10 |
+
@staticmethod
|
| 11 |
+
def controllGet(request: HttpRequest):
|
| 12 |
+
return render(
|
| 13 |
+
request, PanelCreateController.url_template)
|
| 14 |
+
|
| 15 |
+
@staticmethod
|
| 16 |
+
def controllPost(request: HttpRequest):
|
| 17 |
+
return JsonResponse({"message": "Método no permitido"})
|
tecnicas/controllers/views_controller/create_session/{panel_create_controller.py → panels_create/panel_create_escalas_controller.py}
RENAMED
|
@@ -1,23 +1,17 @@
|
|
|
|
|
| 1 |
from django.http import HttpRequest, JsonResponse
|
| 2 |
from django.db import transaction
|
| 3 |
-
from
|
| 4 |
-
from tecnicas.
|
| 5 |
-
from tecnicas.
|
| 6 |
-
from tecnicas.controllers import TecnicaController, EscalaController, ProductosController, OrdenesController, EstiloPalabrasController, PalabrasController, SesionController
|
| 7 |
-
from tecnicas.utils import deleteDataSession
|
| 8 |
|
| 9 |
|
| 10 |
-
class PanelCreateController
|
| 11 |
def __init__(self):
|
| 12 |
-
|
| 13 |
|
| 14 |
@staticmethod
|
| 15 |
-
def
|
| 16 |
-
return render(
|
| 17 |
-
request, 'tecnicas/create_sesion/creando_sesion.html')
|
| 18 |
-
|
| 19 |
-
@staticmethod
|
| 20 |
-
def controllPostEscalas(request: HttpRequest):
|
| 21 |
if request.POST.get('action') == 'create_session':
|
| 22 |
if not request.session.get("form_tags") or not request.session.get("form_codes") or not request.session.get("form_words"):
|
| 23 |
deleteDataSession(request)
|
|
@@ -173,274 +167,3 @@ class PanelCreateController():
|
|
| 173 |
return general_error(f"Error: {e}")
|
| 174 |
else:
|
| 175 |
return general_error("No se ha establecido acción")
|
| 176 |
-
|
| 177 |
-
@staticmethod
|
| 178 |
-
def controllPostRATA(request: HttpRequest):
|
| 179 |
-
if request.POST.get('action') == 'create_session':
|
| 180 |
-
if not request.session.get("form_tags") or not request.session.get("form_codes") or not request.session.get("form_words"):
|
| 181 |
-
deleteDataSession(request)
|
| 182 |
-
return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo")
|
| 183 |
-
try:
|
| 184 |
-
with transaction.atomic():
|
| 185 |
-
# ////////////////////////////////////////////////////// #
|
| 186 |
-
#
|
| 187 |
-
# First step: Create technique and scale with their tags #
|
| 188 |
-
#
|
| 189 |
-
# ////////////////////////////////////////////////////// #
|
| 190 |
-
data_basic = request.session["form_basic"]
|
| 191 |
-
data_basic["numero_catadores"] = 0
|
| 192 |
-
data_basic["numero_repeticiones"] = 1
|
| 193 |
-
|
| 194 |
-
technique = Tecnica.objects.create(
|
| 195 |
-
tipo_tecnica=TipoTecnica.objects.get(
|
| 196 |
-
nombre_tecnica=data_basic["name_tecnica"]),
|
| 197 |
-
id_estilo=EstiloPalabra.objects.get(
|
| 198 |
-
id=data_basic["estilo_palabras"]),
|
| 199 |
-
repeticiones_max=data_basic["numero_repeticiones"] or 1,
|
| 200 |
-
limite_catadores=data_basic["numero_catadores"],
|
| 201 |
-
instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador",
|
| 202 |
-
)
|
| 203 |
-
|
| 204 |
-
if not technique:
|
| 205 |
-
raise ValueError("Error al guardar la técnica")
|
| 206 |
-
|
| 207 |
-
data_scale = {
|
| 208 |
-
"id_scale": data_basic["tipo_escala"],
|
| 209 |
-
"size": data_basic["tamano_escala"],
|
| 210 |
-
"technique": technique
|
| 211 |
-
}
|
| 212 |
-
|
| 213 |
-
controllerScale = EscalaController(data=data_scale)
|
| 214 |
-
|
| 215 |
-
scale = controllerScale.saveScale()
|
| 216 |
-
if isinstance(scale, dict):
|
| 217 |
-
raise ValueError(scale["error"])
|
| 218 |
-
|
| 219 |
-
dict_tags = request.session["form_tags"]
|
| 220 |
-
saved_related_tags = controllerScale.realteTags(dict_tags)
|
| 221 |
-
if "error" in saved_related_tags:
|
| 222 |
-
raise ValueError(saved_related_tags["error"])
|
| 223 |
-
|
| 224 |
-
# ////////////////////////////////////////////// #
|
| 225 |
-
#
|
| 226 |
-
# Second step: Create productos with their codes #
|
| 227 |
-
#
|
| 228 |
-
# ////////////////////////////////////////////// #
|
| 229 |
-
codes = request.session["form_codes"]
|
| 230 |
-
|
| 231 |
-
if not codes:
|
| 232 |
-
raise ValueError("No hay códigos de productos")
|
| 233 |
-
|
| 234 |
-
products_without_save = []
|
| 235 |
-
for code in codes:
|
| 236 |
-
product = Producto(
|
| 237 |
-
codigoProducto=code,
|
| 238 |
-
id_tecnica=technique
|
| 239 |
-
)
|
| 240 |
-
products_without_save.append(product)
|
| 241 |
-
|
| 242 |
-
Producto.objects.bulk_create(products_without_save)
|
| 243 |
-
|
| 244 |
-
# /////////////////////////////////////////////////////// #
|
| 245 |
-
#
|
| 246 |
-
# Third step: Create relations technique with Words Style #
|
| 247 |
-
#
|
| 248 |
-
# /////////////////////////////////////////////////////// #
|
| 249 |
-
style_words = technique.id_estilo.nombre_estilo
|
| 250 |
-
|
| 251 |
-
if style_words == "atributos":
|
| 252 |
-
raw_ids_words = request.session["form_words"]
|
| 253 |
-
ids_words = [int(id_w) for id_w in raw_ids_words]
|
| 254 |
-
|
| 255 |
-
words = Palabra.objects.filter(id__in=ids_words)
|
| 256 |
-
|
| 257 |
-
style_atribute = EsAtributo.objects.create(
|
| 258 |
-
id_tecnica=technique
|
| 259 |
-
)
|
| 260 |
-
|
| 261 |
-
if not style_atribute:
|
| 262 |
-
raise ValueError(
|
| 263 |
-
"Error al intentar relacionar las palabras con la técnica")
|
| 264 |
-
|
| 265 |
-
style_atribute.palabras.set(words)
|
| 266 |
-
|
| 267 |
-
elif style_words == "vocabulario":
|
| 268 |
-
name_vocabulary = request.session["form_words"]
|
| 269 |
-
try:
|
| 270 |
-
vocabulary = Vocabulario.objects.get(
|
| 271 |
-
nombre_vocabulario=name_vocabulary)
|
| 272 |
-
except Vocabulario.DoesNotExist:
|
| 273 |
-
raise ValueError("Vocabulario no encontrado")
|
| 274 |
-
|
| 275 |
-
es_vocabulary = EsVocabulario.objects.create(
|
| 276 |
-
id_tecnica=technique,
|
| 277 |
-
id_vocabulario=vocabulary
|
| 278 |
-
)
|
| 279 |
-
if not es_vocabulary:
|
| 280 |
-
raise ValueError(
|
| 281 |
-
"Error al intentar relacionar el vocabulario con la técnica")
|
| 282 |
-
|
| 283 |
-
else:
|
| 284 |
-
raise ValueError("Estilo de palabas no permitido")
|
| 285 |
-
|
| 286 |
-
# //////////////////////////////////////////////////////// #
|
| 287 |
-
#
|
| 288 |
-
# Fourth step: Create session and relat with the technique #
|
| 289 |
-
#
|
| 290 |
-
# //////////////////////////////////////////////////////// #
|
| 291 |
-
session = SesionSensorial.objects.create(
|
| 292 |
-
name_session=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None,
|
| 293 |
-
technique=technique,
|
| 294 |
-
creator=request.user.user_presentador
|
| 295 |
-
)
|
| 296 |
-
|
| 297 |
-
if not session:
|
| 298 |
-
raise ValueError("Error al crear sesion sensorial")
|
| 299 |
-
|
| 300 |
-
context = {
|
| 301 |
-
"message": "sesión creada",
|
| 302 |
-
"data": {
|
| 303 |
-
"codigo_sesion": session.codigo_sesion,
|
| 304 |
-
"nombre_sesion": session.nombre_sesion
|
| 305 |
-
}
|
| 306 |
-
}
|
| 307 |
-
|
| 308 |
-
# ////////////////////////////////// #
|
| 309 |
-
#
|
| 310 |
-
# Final step: Delete date en session #
|
| 311 |
-
#
|
| 312 |
-
# ////////////////////////////////// #
|
| 313 |
-
|
| 314 |
-
deleteDataSession(request)
|
| 315 |
-
return JsonResponse(context)
|
| 316 |
-
except ValueError as e:
|
| 317 |
-
return general_error(f"Error: {e}")
|
| 318 |
-
else:
|
| 319 |
-
return general_error("No se ha establecido acción")
|
| 320 |
-
|
| 321 |
-
@staticmethod
|
| 322 |
-
def controllPostCATA(request: HttpRequest):
|
| 323 |
-
if request.POST.get('action') == 'create_session':
|
| 324 |
-
if not request.session.get("form_codes") or not request.session.get("form_words"):
|
| 325 |
-
deleteDataSession(request)
|
| 326 |
-
return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo")
|
| 327 |
-
try:
|
| 328 |
-
with transaction.atomic():
|
| 329 |
-
# //////////////////////////// #
|
| 330 |
-
#
|
| 331 |
-
# First step: Create technique #
|
| 332 |
-
#
|
| 333 |
-
# //////////////////////////// #
|
| 334 |
-
data_basic = request.session["form_basic"]
|
| 335 |
-
data_basic["numero_catadores"] = 0
|
| 336 |
-
data_basic["numero_repeticiones"] = 1
|
| 337 |
-
|
| 338 |
-
technique = Tecnica.objects.create(
|
| 339 |
-
tipo_tecnica=TipoTecnica.objects.get(
|
| 340 |
-
nombre_tecnica=data_basic["name_tecnica"]),
|
| 341 |
-
id_estilo=EstiloPalabra.objects.get(
|
| 342 |
-
id=data_basic["estilo_palabras"]),
|
| 343 |
-
repeticiones_max=data_basic["numero_repeticiones"] or 1,
|
| 344 |
-
limite_catadores=data_basic["numero_catadores"],
|
| 345 |
-
instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador",
|
| 346 |
-
)
|
| 347 |
-
|
| 348 |
-
if not technique:
|
| 349 |
-
raise ValueError("Error al guardar la técnica")
|
| 350 |
-
|
| 351 |
-
# ////////////////////////////////////////////// #
|
| 352 |
-
#
|
| 353 |
-
# Second step: Create productos with their codes #
|
| 354 |
-
#
|
| 355 |
-
# ////////////////////////////////////////////// #
|
| 356 |
-
codes = request.session["form_codes"]
|
| 357 |
-
|
| 358 |
-
if not codes:
|
| 359 |
-
raise ValueError("No hay códigos de productos")
|
| 360 |
-
|
| 361 |
-
products_without_save = []
|
| 362 |
-
for code in codes:
|
| 363 |
-
product = Producto(
|
| 364 |
-
codigoProducto=code,
|
| 365 |
-
id_tecnica=technique
|
| 366 |
-
)
|
| 367 |
-
products_without_save.append(product)
|
| 368 |
-
|
| 369 |
-
Producto.objects.bulk_create(products_without_save)
|
| 370 |
-
|
| 371 |
-
# /////////////////////////////////////////////////////// #
|
| 372 |
-
#
|
| 373 |
-
# Third step: Create relations technique with Words Style #
|
| 374 |
-
#
|
| 375 |
-
# /////////////////////////////////////////////////////// #
|
| 376 |
-
style_words = technique.id_estilo.nombre_estilo
|
| 377 |
-
|
| 378 |
-
if style_words == "atributos":
|
| 379 |
-
raw_ids_words = request.session["form_words"]
|
| 380 |
-
ids_words = [int(id_w) for id_w in raw_ids_words]
|
| 381 |
-
|
| 382 |
-
words = Palabra.objects.filter(id__in=ids_words)
|
| 383 |
-
|
| 384 |
-
style_atribute = EsAtributo.objects.create(
|
| 385 |
-
id_tecnica=technique
|
| 386 |
-
)
|
| 387 |
-
|
| 388 |
-
if not style_atribute:
|
| 389 |
-
raise ValueError(
|
| 390 |
-
"Error al intentar relacionar las palabras con la técnica")
|
| 391 |
-
|
| 392 |
-
style_atribute.palabras.set(words)
|
| 393 |
-
|
| 394 |
-
elif style_words == "vocabulario":
|
| 395 |
-
name_vocabulary = request.session["form_words"]
|
| 396 |
-
try:
|
| 397 |
-
vocabulary = Vocabulario.objects.get(
|
| 398 |
-
nombre_vocabulario=name_vocabulary)
|
| 399 |
-
except Vocabulario.DoesNotExist:
|
| 400 |
-
raise ValueError("Vocabulario no encontrado")
|
| 401 |
-
|
| 402 |
-
es_vocabulary = EsVocabulario.objects.create(
|
| 403 |
-
id_tecnica=technique,
|
| 404 |
-
id_vocabulario=vocabulary
|
| 405 |
-
)
|
| 406 |
-
if not es_vocabulary:
|
| 407 |
-
raise ValueError(
|
| 408 |
-
"Error al intentar relacionar el vocabulario con la técnica")
|
| 409 |
-
|
| 410 |
-
else:
|
| 411 |
-
raise ValueError("Estilo de palabas no permitido")
|
| 412 |
-
|
| 413 |
-
# //////////////////////////////////////////////////////// #
|
| 414 |
-
#
|
| 415 |
-
# Fourth step: Create session and relat with the technique #
|
| 416 |
-
#
|
| 417 |
-
# //////////////////////////////////////////////////////// #
|
| 418 |
-
session = SesionSensorial.objects.create(
|
| 419 |
-
nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None,
|
| 420 |
-
tecnica=technique,
|
| 421 |
-
creadoPor=request.user.user_presentador
|
| 422 |
-
)
|
| 423 |
-
|
| 424 |
-
if not session:
|
| 425 |
-
raise ValueError("Error al crear sesion sensorial")
|
| 426 |
-
|
| 427 |
-
context = {
|
| 428 |
-
"message": "sesión creada",
|
| 429 |
-
"data": {
|
| 430 |
-
"codigo_sesion": session.codigo_sesion,
|
| 431 |
-
"nombre_sesion": session.nombre_sesion
|
| 432 |
-
}
|
| 433 |
-
}
|
| 434 |
-
|
| 435 |
-
# ////////////////////////////////// #
|
| 436 |
-
#
|
| 437 |
-
# Final step: Delete date en session #
|
| 438 |
-
#
|
| 439 |
-
# ////////////////////////////////// #
|
| 440 |
-
deleteDataSession(request)
|
| 441 |
-
return JsonResponse(context)
|
| 442 |
-
|
| 443 |
-
except ValueError as e:
|
| 444 |
-
return general_error(f"Error: {e}")
|
| 445 |
-
else:
|
| 446 |
-
return general_error("No se ha establecido acción")
|
|
|
|
| 1 |
+
from .panel_create_controller import PanelCreateController
|
| 2 |
from django.http import HttpRequest, JsonResponse
|
| 3 |
from django.db import transaction
|
| 4 |
+
from tecnicas.controllers import TecnicaController, EscalaController, ProductosController, OrdenesController, PalabrasController, EstiloPalabrasController, SesionController
|
| 5 |
+
from tecnicas.models import EsVocabulario, Vocabulario
|
| 6 |
+
from tecnicas.utils import deleteDataSession, general_error
|
|
|
|
|
|
|
| 7 |
|
| 8 |
|
| 9 |
+
class PanelCreateEscalasController(PanelCreateController):
|
| 10 |
def __init__(self):
|
| 11 |
+
super().__init__()
|
| 12 |
|
| 13 |
@staticmethod
|
| 14 |
+
def controllPost(request: HttpRequest):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
if request.POST.get('action') == 'create_session':
|
| 16 |
if not request.session.get("form_tags") or not request.session.get("form_codes") or not request.session.get("form_words"):
|
| 17 |
deleteDataSession(request)
|
|
|
|
| 167 |
return general_error(f"Error: {e}")
|
| 168 |
else:
|
| 169 |
return general_error("No se ha establecido acción")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tecnicas/controllers/views_controller/create_session/panels_create/panel_create_napping_controller.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .panel_create_controller import PanelCreateController
|
| 2 |
+
from django.http import HttpRequest, JsonResponse
|
| 3 |
+
from tecnicas.models import Tecnica, TipoTecnica, EstiloPalabra, Producto, SesionSensorial, Modalidad, TecnicaModalidad
|
| 4 |
+
from django.db import transaction
|
| 5 |
+
from tecnicas.utils import deleteDataSession
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class PanelCreateNappingController(PanelCreateController):
|
| 9 |
+
def __init__(self):
|
| 10 |
+
super().__init__()
|
| 11 |
+
|
| 12 |
+
@staticmethod
|
| 13 |
+
def controllPost(request: HttpRequest):
|
| 14 |
+
if request.POST.get('action') == 'create_session':
|
| 15 |
+
if not request.session.get("form_basic") or not request.session.get("form_codes"):
|
| 16 |
+
deleteDataSession(request)
|
| 17 |
+
return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo")
|
| 18 |
+
try:
|
| 19 |
+
with transaction.atomic():
|
| 20 |
+
# //////////////////////////// #
|
| 21 |
+
#
|
| 22 |
+
# First step: Create technique #
|
| 23 |
+
#
|
| 24 |
+
# //////////////////////////// #
|
| 25 |
+
data_basic = request.session["form_basic"]
|
| 26 |
+
data_basic["numero_catadores"] = data_basic["numero_catadores"] or 2
|
| 27 |
+
data_basic["numero_repeticiones"] = 0
|
| 28 |
+
|
| 29 |
+
technique = Tecnica.objects.create(
|
| 30 |
+
tipo_tecnica=TipoTecnica.objects.get(
|
| 31 |
+
nombre_tecnica=data_basic["name_tecnica"]),
|
| 32 |
+
id_estilo=EstiloPalabra.objects.get(
|
| 33 |
+
nombre_estilo="napping"),
|
| 34 |
+
repeticiones_max=data_basic["numero_repeticiones"],
|
| 35 |
+
limite_catadores=data_basic["numero_catadores"],
|
| 36 |
+
instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador",
|
| 37 |
+
)
|
| 38 |
+
|
| 39 |
+
if not technique:
|
| 40 |
+
raise ValueError("Error al guardar la técnica")
|
| 41 |
+
|
| 42 |
+
# ////////////////////////////////////////////// #
|
| 43 |
+
#
|
| 44 |
+
# Second step: Create productos with their codes #
|
| 45 |
+
#
|
| 46 |
+
# ////////////////////////////////////////////// #
|
| 47 |
+
codes = request.session["form_codes"]
|
| 48 |
+
|
| 49 |
+
if not codes:
|
| 50 |
+
raise ValueError("No hay códigos de productos")
|
| 51 |
+
|
| 52 |
+
products_without_save = []
|
| 53 |
+
for code in codes:
|
| 54 |
+
product = Producto(
|
| 55 |
+
codigoProducto=code,
|
| 56 |
+
id_tecnica=technique
|
| 57 |
+
)
|
| 58 |
+
products_without_save.append(product)
|
| 59 |
+
|
| 60 |
+
Producto.objects.bulk_create(products_without_save)
|
| 61 |
+
|
| 62 |
+
# /////////////////////////////////////////////////////// #
|
| 63 |
+
#
|
| 64 |
+
# Third step: Create session and relat with the technique #
|
| 65 |
+
#
|
| 66 |
+
# /////////////////////////////////////////////////////// #
|
| 67 |
+
mod = Modalidad.objects.get(
|
| 68 |
+
nombre=data_basic["modalidad"])
|
| 69 |
+
|
| 70 |
+
if not mod:
|
| 71 |
+
raise ValueError("Modalidad no encontrada")
|
| 72 |
+
|
| 73 |
+
technique_mod = TecnicaModalidad.objects.create(
|
| 74 |
+
tecnica=technique,
|
| 75 |
+
modalidad=mod
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
if not technique_mod:
|
| 79 |
+
raise ValueError("Error al guardar la técnica")
|
| 80 |
+
|
| 81 |
+
# /////////////////////////////////////////////////////// #
|
| 82 |
+
#
|
| 83 |
+
# Fourth step: Create session and relat with the technique #
|
| 84 |
+
#
|
| 85 |
+
# /////////////////////////////////////////////////////// #
|
| 86 |
+
session = SesionSensorial.objects.create(
|
| 87 |
+
nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None,
|
| 88 |
+
tecnica=technique,
|
| 89 |
+
creadoPor=request.user.user_presentador
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
if not session:
|
| 93 |
+
raise ValueError("Error al crear sesion sensorial")
|
| 94 |
+
|
| 95 |
+
context = {
|
| 96 |
+
"message": "sesión creada",
|
| 97 |
+
"data": {
|
| 98 |
+
"codigo_sesion": session.codigo_sesion,
|
| 99 |
+
"nombre_sesion": session.nombre_sesion
|
| 100 |
+
}
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
# ////////////////////////////////// #
|
| 104 |
+
#
|
| 105 |
+
# Final step: Delete date en session #
|
| 106 |
+
#
|
| 107 |
+
# ////////////////////////////////// #
|
| 108 |
+
deleteDataSession(request)
|
| 109 |
+
return JsonResponse(context)
|
| 110 |
+
|
| 111 |
+
except ValueError as e:
|
| 112 |
+
return general_error(f"Error: {e}")
|
| 113 |
+
else:
|
| 114 |
+
return general_error("No se ha establecido acción")
|
tecnicas/controllers/views_controller/create_session/panels_create/panel_create_pf_controller.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .panel_create_controller import PanelCreateController
|
| 2 |
+
from django.http import HttpRequest, JsonResponse
|
| 3 |
+
from django.db import transaction
|
| 4 |
+
from tecnicas.models import Tecnica, TipoTecnica, EstiloPalabra, SesionSensorial, Escala, TipoEscala, Producto
|
| 5 |
+
from tecnicas.utils import deleteDataSession, general_error
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class PanelCreatePFController(PanelCreateController):
|
| 9 |
+
def __init__(self):
|
| 10 |
+
super().__init__()
|
| 11 |
+
|
| 12 |
+
@staticmethod
|
| 13 |
+
def controllPost(request: HttpRequest):
|
| 14 |
+
if request.POST.get('action') == 'create_session':
|
| 15 |
+
if not request.session.get("form_codes"):
|
| 16 |
+
deleteDataSession(request)
|
| 17 |
+
return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo")
|
| 18 |
+
try:
|
| 19 |
+
with transaction.atomic():
|
| 20 |
+
# ////////////////////////////////////// #
|
| 21 |
+
#
|
| 22 |
+
# First step: Create technique and scale #
|
| 23 |
+
#
|
| 24 |
+
# ////////////////////////////////////// #
|
| 25 |
+
data_basic = request.session["form_basic"]
|
| 26 |
+
phases_before_reptition = 2
|
| 27 |
+
|
| 28 |
+
technique = Tecnica.objects.create(
|
| 29 |
+
tipo_tecnica=TipoTecnica.objects.get(
|
| 30 |
+
nombre_tecnica=data_basic["name_tecnica"]),
|
| 31 |
+
id_estilo=EstiloPalabra.objects.get(
|
| 32 |
+
nombre_estilo="perfil flash"),
|
| 33 |
+
repeticiones_max=data_basic["numero_repeticiones"] +
|
| 34 |
+
phases_before_reptition,
|
| 35 |
+
limite_catadores=data_basic["numero_catadores"],
|
| 36 |
+
instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Analista",
|
| 37 |
+
)
|
| 38 |
+
|
| 39 |
+
if not technique:
|
| 40 |
+
raise ValueError("Error al guardar la técnica")
|
| 41 |
+
|
| 42 |
+
created_scale = Escala.objects.create(
|
| 43 |
+
id_tipo_escala=TipoEscala.objects.get(
|
| 44 |
+
nombre_escala="estructurada"),
|
| 45 |
+
longitud=data_basic["numero_productos"],
|
| 46 |
+
tecnica=technique
|
| 47 |
+
)
|
| 48 |
+
|
| 49 |
+
if not created_scale:
|
| 50 |
+
raise ValueError("No se ha podido crear la escala")
|
| 51 |
+
|
| 52 |
+
# ////////////////////////////////////////////// #
|
| 53 |
+
#
|
| 54 |
+
# Second step: Create productos with their codes #
|
| 55 |
+
#
|
| 56 |
+
# ////////////////////////////////////////////// #
|
| 57 |
+
codes = request.session["form_codes"]
|
| 58 |
+
|
| 59 |
+
if not codes:
|
| 60 |
+
raise ValueError("No hay códigos de productos")
|
| 61 |
+
|
| 62 |
+
products_without_save = []
|
| 63 |
+
for code in codes:
|
| 64 |
+
product = Producto(
|
| 65 |
+
codigoProducto=code,
|
| 66 |
+
id_tecnica=technique
|
| 67 |
+
)
|
| 68 |
+
products_without_save.append(product)
|
| 69 |
+
|
| 70 |
+
Producto.objects.bulk_create(products_without_save)
|
| 71 |
+
|
| 72 |
+
# /////////////////////////////////////////////////////// #
|
| 73 |
+
#
|
| 74 |
+
# Third step: Create session and relat with the technique #
|
| 75 |
+
#
|
| 76 |
+
# /////////////////////////////////////////////////////// #
|
| 77 |
+
session = SesionSensorial.objects.create(
|
| 78 |
+
nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None,
|
| 79 |
+
tecnica=technique,
|
| 80 |
+
creadoPor=request.user.user_presentador
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
if not session:
|
| 84 |
+
raise ValueError("Error al crear sesion sensorial")
|
| 85 |
+
|
| 86 |
+
context = {
|
| 87 |
+
"message": "sesión creada",
|
| 88 |
+
"data": {
|
| 89 |
+
"codigo_sesion": session.codigo_sesion,
|
| 90 |
+
"nombre_sesion": session.nombre_sesion
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
# ////////////////////////////////// #
|
| 95 |
+
#
|
| 96 |
+
# Final step: Delete date en session #
|
| 97 |
+
#
|
| 98 |
+
# ////////////////////////////////// #
|
| 99 |
+
deleteDataSession(request)
|
| 100 |
+
return JsonResponse(context)
|
| 101 |
+
|
| 102 |
+
except ValueError as e:
|
| 103 |
+
return general_error(f"Error: {e}")
|
| 104 |
+
else:
|
| 105 |
+
return general_error("No se ha establecido acción")
|
tecnicas/controllers/views_controller/create_session/panels_create/panel_create_rata_controller.py
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .panel_create_controller import PanelCreateController
|
| 2 |
+
from django.http import HttpRequest, JsonResponse
|
| 3 |
+
from django.db import transaction
|
| 4 |
+
from tecnicas.controllers import EscalaController
|
| 5 |
+
from tecnicas.models import EsVocabulario, Tecnica, TipoTecnica, EstiloPalabra, EsAtributo, Vocabulario, Palabra, SesionSensorial, Producto
|
| 6 |
+
from tecnicas.utils import deleteDataSession, general_error
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class PanelCreateRataController(PanelCreateController):
|
| 10 |
+
def __init__(self):
|
| 11 |
+
super().__init__()
|
| 12 |
+
|
| 13 |
+
@staticmethod
|
| 14 |
+
def controllPost(request: HttpRequest):
|
| 15 |
+
if request.POST.get('action') == 'create_session':
|
| 16 |
+
if not request.session.get("form_tags") or not request.session.get("form_codes") or not request.session.get("form_words"):
|
| 17 |
+
deleteDataSession(request)
|
| 18 |
+
return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo")
|
| 19 |
+
try:
|
| 20 |
+
with transaction.atomic():
|
| 21 |
+
# ////////////////////////////////////////////////////// #
|
| 22 |
+
#
|
| 23 |
+
# First step: Create technique and scale with their tags #
|
| 24 |
+
#
|
| 25 |
+
# ////////////////////////////////////////////////////// #
|
| 26 |
+
data_basic = request.session["form_basic"]
|
| 27 |
+
data_basic["numero_catadores"] = 0
|
| 28 |
+
data_basic["numero_repeticiones"] = 1
|
| 29 |
+
|
| 30 |
+
technique = Tecnica.objects.create(
|
| 31 |
+
tipo_tecnica=TipoTecnica.objects.get(
|
| 32 |
+
nombre_tecnica=data_basic["name_tecnica"]),
|
| 33 |
+
id_estilo=EstiloPalabra.objects.get(
|
| 34 |
+
nombre_estilo=data_basic["estilo_palabras"]),
|
| 35 |
+
repeticiones_max=data_basic["numero_repeticiones"] or 1,
|
| 36 |
+
limite_catadores=data_basic["numero_catadores"],
|
| 37 |
+
instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador",
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
+
if not technique:
|
| 41 |
+
raise ValueError("Error al guardar la técnica")
|
| 42 |
+
|
| 43 |
+
data_scale = {
|
| 44 |
+
"id_scale": data_basic["tipo_escala"],
|
| 45 |
+
"size": data_basic["tamano_escala"],
|
| 46 |
+
"technique": technique
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
controllerScale = EscalaController(data=data_scale)
|
| 50 |
+
|
| 51 |
+
scale = controllerScale.saveScale()
|
| 52 |
+
if isinstance(scale, dict):
|
| 53 |
+
raise ValueError(scale["error"])
|
| 54 |
+
|
| 55 |
+
dict_tags = request.session["form_tags"]
|
| 56 |
+
saved_related_tags = controllerScale.realteTags(dict_tags)
|
| 57 |
+
if "error" in saved_related_tags:
|
| 58 |
+
raise ValueError(saved_related_tags["error"])
|
| 59 |
+
|
| 60 |
+
# ////////////////////////////////////////////// #
|
| 61 |
+
#
|
| 62 |
+
# Second step: Create productos with their codes #
|
| 63 |
+
#
|
| 64 |
+
# ////////////////////////////////////////////// #
|
| 65 |
+
codes = request.session["form_codes"]
|
| 66 |
+
|
| 67 |
+
if not codes:
|
| 68 |
+
raise ValueError("No hay códigos de productos")
|
| 69 |
+
|
| 70 |
+
products_without_save = []
|
| 71 |
+
for code in codes:
|
| 72 |
+
product = Producto(
|
| 73 |
+
codigoProducto=code,
|
| 74 |
+
id_tecnica=technique
|
| 75 |
+
)
|
| 76 |
+
products_without_save.append(product)
|
| 77 |
+
|
| 78 |
+
Producto.objects.bulk_create(products_without_save)
|
| 79 |
+
|
| 80 |
+
# /////////////////////////////////////////////////////// #
|
| 81 |
+
#
|
| 82 |
+
# Third step: Create relations technique with Words Style #
|
| 83 |
+
#
|
| 84 |
+
# /////////////////////////////////////////////////////// #
|
| 85 |
+
style_words = technique.id_estilo.nombre_estilo
|
| 86 |
+
|
| 87 |
+
if style_words == "atributos":
|
| 88 |
+
raw_ids_words = request.session["form_words"]
|
| 89 |
+
ids_words = [int(id_w) for id_w in raw_ids_words]
|
| 90 |
+
|
| 91 |
+
words = Palabra.objects.filter(id__in=ids_words)
|
| 92 |
+
|
| 93 |
+
style_atribute = EsAtributo.objects.create(
|
| 94 |
+
id_tecnica=technique
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
if not style_atribute:
|
| 98 |
+
raise ValueError(
|
| 99 |
+
"Error al intentar relacionar las palabras con la técnica")
|
| 100 |
+
|
| 101 |
+
style_atribute.palabras.set(words)
|
| 102 |
+
|
| 103 |
+
elif style_words == "vocabulario":
|
| 104 |
+
name_vocabulary = request.session["form_words"]
|
| 105 |
+
try:
|
| 106 |
+
vocabulary = Vocabulario.objects.get(
|
| 107 |
+
nombre_vocabulario=name_vocabulary)
|
| 108 |
+
except Vocabulario.DoesNotExist:
|
| 109 |
+
raise ValueError("Vocabulario no encontrado")
|
| 110 |
+
|
| 111 |
+
es_vocabulary = EsVocabulario.objects.create(
|
| 112 |
+
id_tecnica=technique,
|
| 113 |
+
id_vocabulario=vocabulary
|
| 114 |
+
)
|
| 115 |
+
if not es_vocabulary:
|
| 116 |
+
raise ValueError(
|
| 117 |
+
"Error al intentar relacionar el vocabulario con la técnica")
|
| 118 |
+
|
| 119 |
+
else:
|
| 120 |
+
raise ValueError("Estilo de palabas no permitido")
|
| 121 |
+
|
| 122 |
+
# //////////////////////////////////////////////////////// #
|
| 123 |
+
#
|
| 124 |
+
# Fourth step: Create session and relat with the technique #
|
| 125 |
+
#
|
| 126 |
+
# //////////////////////////////////////////////////////// #
|
| 127 |
+
session = SesionSensorial.objects.create(
|
| 128 |
+
nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else "",
|
| 129 |
+
tecnica=technique,
|
| 130 |
+
creadoPor=request.user.user_presentador
|
| 131 |
+
)
|
| 132 |
+
|
| 133 |
+
if not session:
|
| 134 |
+
raise ValueError("Error al crear sesion sensorial")
|
| 135 |
+
|
| 136 |
+
context = {
|
| 137 |
+
"message": "sesión creada",
|
| 138 |
+
"data": {
|
| 139 |
+
"codigo_sesion": session.codigo_sesion,
|
| 140 |
+
"nombre_sesion": session.nombre_sesion
|
| 141 |
+
}
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
# ////////////////////////////////// #
|
| 145 |
+
#
|
| 146 |
+
# Final step: Delete date en session #
|
| 147 |
+
#
|
| 148 |
+
# ////////////////////////////////// #
|
| 149 |
+
|
| 150 |
+
deleteDataSession(request)
|
| 151 |
+
return JsonResponse(context)
|
| 152 |
+
except ValueError as e:
|
| 153 |
+
return general_error(f"Error: {e}")
|
| 154 |
+
else:
|
| 155 |
+
return general_error("No se ha establecido acción")
|
tecnicas/controllers/views_controller/create_session/panels_create/panel_create_sort_controller.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .panel_create_controller import PanelCreateController
|
| 2 |
+
from django.http import HttpRequest, JsonResponse
|
| 3 |
+
from django.db import transaction
|
| 4 |
+
from tecnicas.models import Tecnica, TipoTecnica, EstiloPalabra, SesionSensorial, Producto
|
| 5 |
+
from tecnicas.utils import deleteDataSession, general_error
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class PanelCreateSortController(PanelCreateController):
|
| 9 |
+
def __init__(self):
|
| 10 |
+
super().__init__()
|
| 11 |
+
|
| 12 |
+
@staticmethod
|
| 13 |
+
def controllPost(request: HttpRequest):
|
| 14 |
+
if request.POST.get('action') == 'create_session':
|
| 15 |
+
if not request.session.get("form_basic") or not request.session.get("form_codes"):
|
| 16 |
+
deleteDataSession(request)
|
| 17 |
+
return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo")
|
| 18 |
+
try:
|
| 19 |
+
with transaction.atomic():
|
| 20 |
+
# //////////////////////////// #
|
| 21 |
+
#
|
| 22 |
+
# First step: Create technique #
|
| 23 |
+
#
|
| 24 |
+
# //////////////////////////// #
|
| 25 |
+
data_basic = request.session["form_basic"]
|
| 26 |
+
data_basic["numero_catadores"] = data_basic["numero_catadores"] or 1
|
| 27 |
+
data_basic["numero_repeticiones"] = 1
|
| 28 |
+
|
| 29 |
+
technique = Tecnica.objects.create(
|
| 30 |
+
tipo_tecnica=TipoTecnica.objects.get(
|
| 31 |
+
nombre_tecnica=data_basic["name_tecnica"]),
|
| 32 |
+
id_estilo=EstiloPalabra.objects.get(
|
| 33 |
+
nombre_estilo="sort"),
|
| 34 |
+
repeticiones_max=data_basic["numero_repeticiones"],
|
| 35 |
+
limite_catadores=data_basic["numero_catadores"],
|
| 36 |
+
instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador",
|
| 37 |
+
)
|
| 38 |
+
|
| 39 |
+
if not technique:
|
| 40 |
+
raise ValueError("Error al guardar la técnica")
|
| 41 |
+
|
| 42 |
+
# ////////////////////////////////////////////// #
|
| 43 |
+
#
|
| 44 |
+
# Second step: Create productos with their codes #
|
| 45 |
+
#
|
| 46 |
+
# ////////////////////////////////////////////// #
|
| 47 |
+
codes = request.session["form_codes"]
|
| 48 |
+
|
| 49 |
+
if not codes:
|
| 50 |
+
raise ValueError("No hay códigos de productos")
|
| 51 |
+
|
| 52 |
+
products_without_save = []
|
| 53 |
+
for code in codes:
|
| 54 |
+
product = Producto(
|
| 55 |
+
codigoProducto=code,
|
| 56 |
+
id_tecnica=technique
|
| 57 |
+
)
|
| 58 |
+
products_without_save.append(product)
|
| 59 |
+
|
| 60 |
+
Producto.objects.bulk_create(products_without_save)
|
| 61 |
+
|
| 62 |
+
# /////////////////////////////////////////////////////// #
|
| 63 |
+
#
|
| 64 |
+
# Third step: Create session and relat with the technique #
|
| 65 |
+
#
|
| 66 |
+
# /////////////////////////////////////////////////////// #
|
| 67 |
+
session = SesionSensorial.objects.create(
|
| 68 |
+
nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None,
|
| 69 |
+
tecnica=technique,
|
| 70 |
+
creadoPor=request.user.user_presentador
|
| 71 |
+
)
|
| 72 |
+
|
| 73 |
+
if not session:
|
| 74 |
+
raise ValueError("Error al crear sesion sensorial")
|
| 75 |
+
|
| 76 |
+
context = {
|
| 77 |
+
"message": "sesión creada",
|
| 78 |
+
"data": {
|
| 79 |
+
"codigo_sesion": session.codigo_sesion,
|
| 80 |
+
"nombre_sesion": session.nombre_sesion
|
| 81 |
+
}
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
# ////////////////////////////////// #
|
| 85 |
+
#
|
| 86 |
+
# Final step: Delete date en session #
|
| 87 |
+
#
|
| 88 |
+
# ////////////////////////////////// #
|
| 89 |
+
deleteDataSession(request)
|
| 90 |
+
return JsonResponse(context)
|
| 91 |
+
|
| 92 |
+
except ValueError as e:
|
| 93 |
+
return general_error(f"Error: {e}")
|
| 94 |
+
else:
|
| 95 |
+
return general_error("No se ha establecido acción")
|
tecnicas/controllers/views_controller/session_management/{details_rata_controller.py → details/details_cata_controller.py}
RENAMED
|
@@ -1,48 +1,60 @@
|
|
| 1 |
-
from django.
|
| 2 |
-
from
|
| 3 |
-
from tecnicas.
|
| 4 |
-
from tecnicas.controllers import PalabrasController, DatoController, CalificacionController
|
| 5 |
from tecnicas.utils import defaultdict_to_dict
|
| 6 |
from .details_controller import DetallesController
|
| 7 |
from collections import defaultdict
|
| 8 |
|
| 9 |
|
| 10 |
-
class
|
| 11 |
def __init__(self, session: SesionSensorial):
|
| 12 |
super().__init__(session)
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
context = self.getContext()
|
| 16 |
-
if error != "" or error:
|
| 17 |
-
context["error"] = error
|
| 18 |
-
return render(
|
| 19 |
-
request, self.url_template, context)
|
| 20 |
|
| 21 |
def getContext(self):
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
self.words = PalabrasController.getWordsInTechnique(
|
| 25 |
self.session.tecnica)
|
| 26 |
self.context["palabras"] = [word.nombre_palabra for word in self.words]
|
| 27 |
|
|
|
|
| 28 |
ratings_for_repetition = []
|
| 29 |
|
| 30 |
-
ratings =
|
| 31 |
-
technique
|
| 32 |
|
| 33 |
-
if
|
| 34 |
self.context["calificaciones"] = ratings_for_repetition
|
| 35 |
self.context["existen_calificaciones"] = False
|
| 36 |
return self.context
|
| 37 |
|
| 38 |
-
data =
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
ratings_for_repetition = defaultdict(
|
| 42 |
lambda: defaultdict(lambda: defaultdict(list)))
|
| 43 |
|
| 44 |
for item in data:
|
| 45 |
-
user = item["
|
| 46 |
rep = item["repeticion"]
|
| 47 |
prod = item["producto_code"]
|
| 48 |
|
|
@@ -54,3 +66,7 @@ class DetallesRATAController(DetallesController):
|
|
| 54 |
self.context["calificaciones"] = defaultdict_to_dict(
|
| 55 |
ratings_for_repetition)
|
| 56 |
self.context["existen_calificaciones"] = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.db.models import F
|
| 2 |
+
from tecnicas.models import SesionSensorial, Calificacion, ValorBooleano
|
| 3 |
+
from tecnicas.controllers import PalabrasController
|
|
|
|
| 4 |
from tecnicas.utils import defaultdict_to_dict
|
| 5 |
from .details_controller import DetallesController
|
| 6 |
from collections import defaultdict
|
| 7 |
|
| 8 |
|
| 9 |
+
class DetallesCATAController(DetallesController):
|
| 10 |
def __init__(self, session: SesionSensorial):
|
| 11 |
super().__init__(session)
|
| 12 |
+
self.url_template = "tecnicas/manage_sesions/details-session-cata.html"
|
| 13 |
+
self.url_next = "cata_system:monitor_sesion"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
def getContext(self):
|
| 16 |
+
technique = self.session.tecnica
|
| 17 |
+
|
| 18 |
+
self.context = {
|
| 19 |
+
"sesion": self.session,
|
| 20 |
+
"use_technique": technique
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
# Recuperar palabras
|
| 24 |
self.words = PalabrasController.getWordsInTechnique(
|
| 25 |
self.session.tecnica)
|
| 26 |
self.context["palabras"] = [word.nombre_palabra for word in self.words]
|
| 27 |
|
| 28 |
+
# Intentar recuperar las calificaciones
|
| 29 |
ratings_for_repetition = []
|
| 30 |
|
| 31 |
+
ratings = list(Calificacion.objects.filter(
|
| 32 |
+
id_tecnica=technique))
|
| 33 |
|
| 34 |
+
if not ratings:
|
| 35 |
self.context["calificaciones"] = ratings_for_repetition
|
| 36 |
self.context["existen_calificaciones"] = False
|
| 37 |
return self.context
|
| 38 |
|
| 39 |
+
data = (
|
| 40 |
+
ValorBooleano.objects
|
| 41 |
+
.filter(id_dato__id_calificacion__in=ratings)
|
| 42 |
+
.values(
|
| 43 |
+
nombre_palabra=F("id_dato__id_palabra__nombre_palabra"),
|
| 44 |
+
repeticion=F("id_dato__id_calificacion__num_repeticion"),
|
| 45 |
+
producto_code=F(
|
| 46 |
+
"id_dato__id_calificacion__id_producto__codigoProducto"),
|
| 47 |
+
usuario_catador=F(
|
| 48 |
+
"id_dato__id_calificacion__id_catador__user__username"),
|
| 49 |
+
dato_valor=F("valor")
|
| 50 |
+
)
|
| 51 |
+
)
|
| 52 |
|
| 53 |
ratings_for_repetition = defaultdict(
|
| 54 |
lambda: defaultdict(lambda: defaultdict(list)))
|
| 55 |
|
| 56 |
for item in data:
|
| 57 |
+
user = item["usuario_catador"]
|
| 58 |
rep = item["repeticion"]
|
| 59 |
prod = item["producto_code"]
|
| 60 |
|
|
|
|
| 66 |
self.context["calificaciones"] = defaultdict_to_dict(
|
| 67 |
ratings_for_repetition)
|
| 68 |
self.context["existen_calificaciones"] = True
|
| 69 |
+
|
| 70 |
+
# Se comprueba que ya no se pueda iniciar la repeticion
|
| 71 |
+
self.context["fin_repeticiones"] = technique.repeticion >= technique.repeticiones_max
|
| 72 |
+
return self.context
|
tecnicas/controllers/views_controller/session_management/details/details_controller.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import render, redirect
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import SesionSensorial, Presentador, Tecnica, Participacion
|
| 5 |
+
from tecnicas.controllers import ParticipacionController
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class DetallesController():
|
| 9 |
+
url_template: str
|
| 10 |
+
url_next = "cata_system:monitor_sesion"
|
| 11 |
+
|
| 12 |
+
def __init__(self, session: SesionSensorial):
|
| 13 |
+
self.session = session
|
| 14 |
+
|
| 15 |
+
def controllGetResponse(self, request: HttpRequest, error: str = "", message: str = ""):
|
| 16 |
+
context = self.getContext()
|
| 17 |
+
|
| 18 |
+
if error != "" or error:
|
| 19 |
+
context["error"] = error
|
| 20 |
+
if message != "" or message:
|
| 21 |
+
context["message"] = message
|
| 22 |
+
|
| 23 |
+
return render(
|
| 24 |
+
request, self.url_template, context)
|
| 25 |
+
|
| 26 |
+
def getContext(self):
|
| 27 |
+
return {}
|
| 28 |
+
|
| 29 |
+
def deleteSesorialSession(self):
|
| 30 |
+
technique = Tecnica.objects.get(id=self.session.tecnica.id)
|
| 31 |
+
technique.delete()
|
| 32 |
+
|
| 33 |
+
def startRepetition(self, presenter: Presentador, request: HttpRequest):
|
| 34 |
+
creator = presenter
|
| 35 |
+
technique = self.session.tecnica
|
| 36 |
+
|
| 37 |
+
if creator.user.username != self.session.creadoPor.user.username:
|
| 38 |
+
return self.controllGetResponse(error="Solo el presentador que crea la sesión puede iniciar la repetición", request=request)
|
| 39 |
+
elif self.session.activo:
|
| 40 |
+
return self.controllGetResponse(error="La sesión ya está activada", request=request)
|
| 41 |
+
elif technique.repeticion >= technique.repeticiones_max:
|
| 42 |
+
return self.controllGetResponse(error="Se ha alcanzado el número de repeticiones máxima", request=request)
|
| 43 |
+
|
| 44 |
+
is_update_participations = self.setParticipationsToNoFinished()
|
| 45 |
+
if not is_update_participations:
|
| 46 |
+
return self.controllGetResponse(error="Error al actualizar las participaciones", request=request)
|
| 47 |
+
|
| 48 |
+
self.session.activo = True
|
| 49 |
+
technique.repeticion = technique.repeticion + 1
|
| 50 |
+
|
| 51 |
+
technique.save()
|
| 52 |
+
self.session.save()
|
| 53 |
+
|
| 54 |
+
parameters = {
|
| 55 |
+
"session_code": self.session.codigo_sesion
|
| 56 |
+
}
|
| 57 |
+
return redirect(
|
| 58 |
+
reverse(self.url_next, kwargs=parameters))
|
| 59 |
+
|
| 60 |
+
def setParticipationsToNoFinished(self):
|
| 61 |
+
there_participacions = Participacion.objects.filter(
|
| 62 |
+
tecnica=self.session.tecnica).exists()
|
| 63 |
+
|
| 64 |
+
if there_participacions:
|
| 65 |
+
(is_update_participations,
|
| 66 |
+
message) = ParticipacionController.outAllInSession(self.session)
|
| 67 |
+
|
| 68 |
+
return is_update_participations
|
| 69 |
+
|
| 70 |
+
return True
|
tecnicas/controllers/views_controller/session_management/{details_escala_controller.py → details/details_escala_controller.py}
RENAMED
|
@@ -11,40 +11,26 @@ Encabezados de como deben de aparecer los datos juntos
|
|
| 11 |
| Repeticion | Codigo Producto | Catador | P1 | P2 | P3 | Pn |
|
| 12 |
|
| 13 |
'''
|
| 14 |
-
from
|
| 15 |
-
from
|
| 16 |
-
from django.urls import reverse
|
| 17 |
-
from tecnicas.models import SesionSensorial, Presentador, Participacion, Calificacion, Escala
|
| 18 |
-
from tecnicas.controllers import DatoController, PalabrasController, ParticipacionController
|
| 19 |
from .details_controller import DetallesController
|
| 20 |
-
from tecnicas.utils import defaultdict_to_dict
|
| 21 |
from collections import defaultdict
|
| 22 |
|
| 23 |
|
| 24 |
class DetallesEscalasController(DetallesController):
|
| 25 |
-
url_template = "tecnicas/manage_sesions/detalles-sesion.html"
|
| 26 |
-
|
| 27 |
def __init__(self, session: SesionSensorial):
|
| 28 |
super().__init__(session)
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
context = self.getContext()
|
| 32 |
-
|
| 33 |
-
if error != "" or error:
|
| 34 |
-
context["error"] = error
|
| 35 |
-
if message != "" or message:
|
| 36 |
-
context["message"] = message
|
| 37 |
-
|
| 38 |
-
return render(
|
| 39 |
-
request, self.url_template, context)
|
| 40 |
|
| 41 |
def getContext(self):
|
|
|
|
|
|
|
| 42 |
self.context = {
|
| 43 |
-
"
|
|
|
|
| 44 |
}
|
| 45 |
-
self.context["sesion"] = self.session
|
| 46 |
-
|
| 47 |
-
technique = self.session.tecnica
|
| 48 |
|
| 49 |
# Datos de la escala usada
|
| 50 |
scale: Escala = technique.escala_tecnica
|
|
@@ -94,35 +80,3 @@ class DetallesEscalasController(DetallesController):
|
|
| 94 |
self.context["fin_repeticiones"] = technique.repeticion >= technique.repeticiones_max
|
| 95 |
|
| 96 |
return self.context
|
| 97 |
-
|
| 98 |
-
def startRepetition(self, presenter: Presentador, request: HttpRequest):
|
| 99 |
-
creator = presenter
|
| 100 |
-
technique = self.session.tecnica
|
| 101 |
-
|
| 102 |
-
if creator.user.username != self.session.creadoPor.user.username:
|
| 103 |
-
return self.getResponse(error="Solo el presentador que crea la sesión puede iniciar la repetición", request=request)
|
| 104 |
-
elif self.session.activo:
|
| 105 |
-
return self.getResponse(error="La sesión ya está activada", request=request)
|
| 106 |
-
elif technique.repeticion >= technique.repeticiones_max:
|
| 107 |
-
return self.getResponse(error="Se ha alcanzado el número de repeticiones máxima", request=request)
|
| 108 |
-
|
| 109 |
-
there_participacions = Participacion.objects.filter(
|
| 110 |
-
tecnica=technique).exists()
|
| 111 |
-
|
| 112 |
-
if there_participacions:
|
| 113 |
-
(is_update_participations,
|
| 114 |
-
message) = ParticipacionController.outAllInSession(self.session)
|
| 115 |
-
if not is_update_participations:
|
| 116 |
-
return self.getResponse(error=message, request=request)
|
| 117 |
-
|
| 118 |
-
self.session.activo = True
|
| 119 |
-
technique.repeticion = technique.repeticion + 1
|
| 120 |
-
|
| 121 |
-
technique.save()
|
| 122 |
-
self.session.save()
|
| 123 |
-
|
| 124 |
-
parameters = {
|
| 125 |
-
"session_code": self.session.codigo_sesion
|
| 126 |
-
}
|
| 127 |
-
return redirect(
|
| 128 |
-
reverse("cata_system:monitor_sesion", kwargs=parameters))
|
|
|
|
| 11 |
| Repeticion | Codigo Producto | Catador | P1 | P2 | P3 | Pn |
|
| 12 |
|
| 13 |
'''
|
| 14 |
+
from tecnicas.models import SesionSensorial, Calificacion, Escala
|
| 15 |
+
from tecnicas.controllers import DatoController, PalabrasController
|
|
|
|
|
|
|
|
|
|
| 16 |
from .details_controller import DetallesController
|
| 17 |
+
from tecnicas.utils import defaultdict_to_dict
|
| 18 |
from collections import defaultdict
|
| 19 |
|
| 20 |
|
| 21 |
class DetallesEscalasController(DetallesController):
|
|
|
|
|
|
|
| 22 |
def __init__(self, session: SesionSensorial):
|
| 23 |
super().__init__(session)
|
| 24 |
+
self.url_template = "tecnicas/manage_sesions/details-session.html"
|
| 25 |
+
self.url_next = "cata_system:monitor_sesion"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
def getContext(self):
|
| 28 |
+
technique = self.session.tecnica
|
| 29 |
+
|
| 30 |
self.context = {
|
| 31 |
+
"sesion": self.session,
|
| 32 |
+
"use_technique": technique.tipo_tecnica.nombre_tecnica
|
| 33 |
}
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
# Datos de la escala usada
|
| 36 |
scale: Escala = technique.escala_tecnica
|
|
|
|
| 80 |
self.context["fin_repeticiones"] = technique.repeticion >= technique.repeticiones_max
|
| 81 |
|
| 82 |
return self.context
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tecnicas/controllers/views_controller/session_management/details/details_napping_controller.py
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import redirect
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from django.db.models import F
|
| 5 |
+
from .details_controller import DetallesController
|
| 6 |
+
from tecnicas.models import (
|
| 7 |
+
SesionSensorial, Presentador, Modalidad, TecnicaModalidad, Catador,
|
| 8 |
+
Participacion, DatoPunto, Calificacion, GrupoProducto, ValorBooleano,
|
| 9 |
+
ValorDecimal, Producto, Escala, EsVocabulario, Vocabulario
|
| 10 |
+
)
|
| 11 |
+
from tecnicas.utils import defaultdict_to_dict
|
| 12 |
+
from collections import defaultdict
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class DetallesNappingController(DetallesController):
|
| 16 |
+
def __init__(self, session: SesionSensorial):
|
| 17 |
+
super().__init__(session)
|
| 18 |
+
self.url_template = "tecnicas/manage_sesions/details-session-napping.html"
|
| 19 |
+
self.url_next = "cata_system:monitor_sesion"
|
| 20 |
+
self.context = {}
|
| 21 |
+
|
| 22 |
+
def getContext(self):
|
| 23 |
+
self.context["session"] = self.session
|
| 24 |
+
|
| 25 |
+
self.defineStatus()
|
| 26 |
+
self.setIsEndSession()
|
| 27 |
+
self.setDataTable()
|
| 28 |
+
|
| 29 |
+
return self.context
|
| 30 |
+
|
| 31 |
+
def defineStatus(self):
|
| 32 |
+
repetition = self.session.tecnica.repeticion
|
| 33 |
+
mod = TecnicaModalidad.objects.get(
|
| 34 |
+
tecnica=self.session.tecnica)
|
| 35 |
+
|
| 36 |
+
self.context["mod_tech"] = mod.modalidad.nombre
|
| 37 |
+
self.context["mode"] = mod.modalidad.nombre
|
| 38 |
+
if mod.modalidad.nombre == "sin modalidad":
|
| 39 |
+
self.context["mod_tech"] = "No se usa modalidad"
|
| 40 |
+
|
| 41 |
+
if not self.session.activo:
|
| 42 |
+
self.context["status"] = "Listo para iniciar la sesión con Napping"
|
| 43 |
+
elif self.session.activo:
|
| 44 |
+
self.context["status"] = "Sesión con en curso"
|
| 45 |
+
|
| 46 |
+
def controllPostResponse(self, request: HttpRequest, action: str):
|
| 47 |
+
if action == "start_sin_modalidad":
|
| 48 |
+
response = self.startNapping(request=request)
|
| 49 |
+
|
| 50 |
+
elif action == "start_perfil_ultra_flash":
|
| 51 |
+
response = self.startNapping(request=request)
|
| 52 |
+
|
| 53 |
+
elif action == "start_sorting":
|
| 54 |
+
response = self.startNapping(request=request)
|
| 55 |
+
|
| 56 |
+
elif action == "combine_sessions":
|
| 57 |
+
response = self.combineSessions(request=request)
|
| 58 |
+
|
| 59 |
+
elif action == "delete_session":
|
| 60 |
+
self.deleteSesorialSession()
|
| 61 |
+
response = redirect(
|
| 62 |
+
reverse("cata_system:panel_sesiones", kwargs={"page": 1}))
|
| 63 |
+
|
| 64 |
+
else:
|
| 65 |
+
response = self.controllGetResponse(
|
| 66 |
+
error="Modalidad sin implantar", request=request)
|
| 67 |
+
|
| 68 |
+
return response
|
| 69 |
+
|
| 70 |
+
def startNapping(self, request: HttpRequest):
|
| 71 |
+
if request.user.user_presentador.user.username != self.session.creadoPor.user.username:
|
| 72 |
+
return self.controllGetResponse(error="Solo el presentador que crea la sesión puede iniciar la repetición", request=request)
|
| 73 |
+
elif self.session.activo:
|
| 74 |
+
return self.controllGetResponse(error="La sesión ya está activada", request=request)
|
| 75 |
+
|
| 76 |
+
is_update_participations = self.setParticipationsToNoFinished()
|
| 77 |
+
if not is_update_participations:
|
| 78 |
+
return self.controllGetResponse(error="Error al actualizar las participaciones", request=request)
|
| 79 |
+
|
| 80 |
+
self.session.activo = True
|
| 81 |
+
self.session.save()
|
| 82 |
+
|
| 83 |
+
parameters = {
|
| 84 |
+
"session_code": self.session.codigo_sesion
|
| 85 |
+
}
|
| 86 |
+
return redirect(
|
| 87 |
+
reverse(self.url_next, kwargs=parameters))
|
| 88 |
+
|
| 89 |
+
def setDataTable(self):
|
| 90 |
+
participations = Participacion.objects.filter(
|
| 91 |
+
tecnica=self.session.tecnica).select_related("catador")
|
| 92 |
+
testers = [participation.catador for participation in participations]
|
| 93 |
+
self.context["testers"] = testers
|
| 94 |
+
|
| 95 |
+
ratings = Calificacion.objects.filter(id_tecnica=self.session.tecnica)
|
| 96 |
+
|
| 97 |
+
coordinates = (
|
| 98 |
+
DatoPunto.objects.filter(calificacion__in=ratings)
|
| 99 |
+
.values(
|
| 100 |
+
producto=F("calificacion__id_producto__codigoProducto"),
|
| 101 |
+
catador=F("calificacion__id_catador__user__username"),
|
| 102 |
+
px=F("x"),
|
| 103 |
+
py=F("y"),
|
| 104 |
+
))
|
| 105 |
+
|
| 106 |
+
if not coordinates.exists():
|
| 107 |
+
self.context["there_data"] = False
|
| 108 |
+
return []
|
| 109 |
+
|
| 110 |
+
coordinates_by_product = defaultdict(dict)
|
| 111 |
+
|
| 112 |
+
for coordinate in coordinates:
|
| 113 |
+
coordinates_by_product[coordinate["producto"]][coordinate["catador"]] = {
|
| 114 |
+
"px": coordinate["px"],
|
| 115 |
+
"py": coordinate["py"],
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
self.context["coordinates_no_mode"] = defaultdict_to_dict(
|
| 119 |
+
coordinates_by_product)
|
| 120 |
+
|
| 121 |
+
# Add word frequency data for perfil ultra flash mode
|
| 122 |
+
mod = TecnicaModalidad.objects.get(tecnica=self.session.tecnica)
|
| 123 |
+
if mod.modalidad.nombre == "perfil ultra flash":
|
| 124 |
+
self.setWordFrequencies(ratings)
|
| 125 |
+
elif mod.modalidad.nombre == "sorting":
|
| 126 |
+
self.setSortingData()
|
| 127 |
+
|
| 128 |
+
self.context["there_data"] = True
|
| 129 |
+
|
| 130 |
+
def setWordFrequencies(self, ratings):
|
| 131 |
+
from collections import Counter
|
| 132 |
+
|
| 133 |
+
# Prefetch palabras to optimize queries
|
| 134 |
+
ratings_with_words = ratings.prefetch_related(
|
| 135 |
+
'palabras').select_related('id_producto')
|
| 136 |
+
|
| 137 |
+
# Dictionary to store word frequencies by product
|
| 138 |
+
word_frequencies_by_product = defaultdict(Counter)
|
| 139 |
+
all_words_set = set()
|
| 140 |
+
|
| 141 |
+
for rating in ratings_with_words:
|
| 142 |
+
producto_code = rating.id_producto.codigoProducto
|
| 143 |
+
words = rating.palabras.all()
|
| 144 |
+
|
| 145 |
+
for word in words:
|
| 146 |
+
word_name = word.nombre_palabra
|
| 147 |
+
word_frequencies_by_product[producto_code][word_name] += 1
|
| 148 |
+
all_words_set.add(word_name)
|
| 149 |
+
|
| 150 |
+
# Convert Counter objects to regular dicts and sort words alphabetically
|
| 151 |
+
word_frequencies_dict = {
|
| 152 |
+
product: dict(frequencies)
|
| 153 |
+
for product, frequencies in word_frequencies_by_product.items()
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
# Sort all words alphabetically for consistent column ordering
|
| 157 |
+
all_words_sorted = sorted(all_words_set)
|
| 158 |
+
|
| 159 |
+
self.context["word_frequencies"] = word_frequencies_dict
|
| 160 |
+
self.context["all_words"] = all_words_sorted
|
| 161 |
+
|
| 162 |
+
def setSortingData(self):
|
| 163 |
+
# Get all ratings for this technique to access DatoPunto
|
| 164 |
+
ratings = Calificacion.objects.filter(id_tecnica=self.session.tecnica)
|
| 165 |
+
|
| 166 |
+
# Get coordinates for all products
|
| 167 |
+
coordinates = (
|
| 168 |
+
DatoPunto.objects.filter(calificacion__in=ratings)
|
| 169 |
+
.values(
|
| 170 |
+
producto=F("calificacion__id_producto__codigoProducto"),
|
| 171 |
+
producto_id=F("calificacion__id_producto__id"),
|
| 172 |
+
catador=F("calificacion__id_catador__user__username"),
|
| 173 |
+
catador_id=F("calificacion__id_catador__id"),
|
| 174 |
+
px=F("x"),
|
| 175 |
+
py=F("y"),
|
| 176 |
+
))
|
| 177 |
+
|
| 178 |
+
# Create a mapping of (catador_id, producto_id) -> coordinates
|
| 179 |
+
coord_map = {}
|
| 180 |
+
for coord in coordinates:
|
| 181 |
+
key = (coord["catador_id"], coord["producto_id"])
|
| 182 |
+
coord_map[key] = {
|
| 183 |
+
"px": coord["px"],
|
| 184 |
+
"py": coord["py"],
|
| 185 |
+
"producto": coord["producto"],
|
| 186 |
+
"catador": coord["catador"]
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
# Get all groups with their products and words
|
| 190 |
+
grupos = (
|
| 191 |
+
GrupoProducto.objects.filter(tecnica=self.session.tecnica)
|
| 192 |
+
.prefetch_related("productos", "palabras")
|
| 193 |
+
.select_related("catador__user")
|
| 194 |
+
)
|
| 195 |
+
|
| 196 |
+
# Create a mapping of (catador_id, producto_id) -> words
|
| 197 |
+
words_map = defaultdict(list)
|
| 198 |
+
for grupo in grupos:
|
| 199 |
+
catador_id = grupo.catador.id
|
| 200 |
+
words = [palabra.nombre_palabra for palabra in grupo.palabras.all()]
|
| 201 |
+
words_str = ";".join(words) if words else ""
|
| 202 |
+
|
| 203 |
+
for producto in grupo.productos.all():
|
| 204 |
+
key = (catador_id, producto.id)
|
| 205 |
+
words_map[key] = words_str
|
| 206 |
+
|
| 207 |
+
# Structure final data: product -> catador -> {px, py, words}
|
| 208 |
+
sorting_data = defaultdict(dict)
|
| 209 |
+
|
| 210 |
+
for key, coord_data in coord_map.items():
|
| 211 |
+
catador_id, producto_id = key
|
| 212 |
+
producto_code = coord_data["producto"]
|
| 213 |
+
catador_username = coord_data["catador"]
|
| 214 |
+
|
| 215 |
+
sorting_data[producto_code][catador_username] = {
|
| 216 |
+
"px": coord_data["px"],
|
| 217 |
+
"py": coord_data["py"],
|
| 218 |
+
"words": words_map.get(key, "")
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
self.context["sorting_data"] = defaultdict_to_dict(sorting_data)
|
| 222 |
+
|
| 223 |
+
def setIsEndSession(self):
|
| 224 |
+
if not self.session.activo and self.session.tecnica.repeticion < 1:
|
| 225 |
+
self.context["finished"] = False
|
| 226 |
+
return
|
| 227 |
+
elif self.session.activo:
|
| 228 |
+
self.context["finished"] = False
|
| 229 |
+
return
|
| 230 |
+
elif not self.session.activo and self.session.tecnica.repeticion >= 1:
|
| 231 |
+
self.context["finished"] = True
|
| 232 |
+
return
|
| 233 |
+
|
| 234 |
+
# ==================== SESSION COMBINATION METHODS ====================
|
| 235 |
+
|
| 236 |
+
def combineSessions(self, request: HttpRequest):
|
| 237 |
+
"""Handle session combination request"""
|
| 238 |
+
session_b_code = request.POST.get("session_b_code", "").strip()
|
| 239 |
+
|
| 240 |
+
if not session_b_code:
|
| 241 |
+
return self.controllGetResponse(
|
| 242 |
+
error="Debe proporcionar un código de sesión", request=request)
|
| 243 |
+
|
| 244 |
+
# Validate and get session B
|
| 245 |
+
validation_result = self.validateSessionCombination(session_b_code)
|
| 246 |
+
|
| 247 |
+
if validation_result.get("error"):
|
| 248 |
+
return self.controllGetResponse(
|
| 249 |
+
error=validation_result["error"], request=request)
|
| 250 |
+
|
| 251 |
+
session_b = validation_result["session_b"]
|
| 252 |
+
technique_type = validation_result["technique_type"]
|
| 253 |
+
|
| 254 |
+
# Get combined data based on technique type
|
| 255 |
+
if technique_type == "cata":
|
| 256 |
+
combined_data = self.getCombinedDataForCATA(session_b)
|
| 257 |
+
elif technique_type == "rata":
|
| 258 |
+
combined_data = self.getCombinedDataForRATA(session_b)
|
| 259 |
+
elif technique_type == "escalas":
|
| 260 |
+
combined_data = self.getCombinedDataForEscalas(session_b)
|
| 261 |
+
else:
|
| 262 |
+
return self.controllGetResponse(
|
| 263 |
+
error="Tipo de técnica no soportado para combinación", request=request)
|
| 264 |
+
|
| 265 |
+
# Add combined data to context
|
| 266 |
+
self.context["combined_data"] = combined_data
|
| 267 |
+
self.context["session_b"] = session_b
|
| 268 |
+
self.context["session_b_technique_type"] = technique_type
|
| 269 |
+
|
| 270 |
+
return self.controllGetResponse(request=request)
|
| 271 |
+
|
| 272 |
+
def validateSessionCombination(self, session_b_code: str):
|
| 273 |
+
"""Validate that Session B can be combined with Session A (Napping)"""
|
| 274 |
+
result = {"error": None, "session_b": None, "technique_type": None}
|
| 275 |
+
|
| 276 |
+
# Check if Session B exists
|
| 277 |
+
try:
|
| 278 |
+
session_b = SesionSensorial.objects.select_related(
|
| 279 |
+
"tecnica__tipo_tecnica").get(codigo_sesion=session_b_code)
|
| 280 |
+
except SesionSensorial.DoesNotExist:
|
| 281 |
+
result["error"] = f"No existe una sesión con el código: {session_b_code}"
|
| 282 |
+
return result
|
| 283 |
+
|
| 284 |
+
# Check if Session B technique is CATA, RATA, or Escalas
|
| 285 |
+
technique_type = session_b.tecnica.tipo_tecnica.nombre_tecnica
|
| 286 |
+
valid_techniques = ["cata", "rata", "escalas"]
|
| 287 |
+
|
| 288 |
+
if technique_type not in valid_techniques:
|
| 289 |
+
result[
|
| 290 |
+
"error"] = f"La sesión B debe usar CATA, RATA o Escalas. Técnica actual: {technique_type}"
|
| 291 |
+
return result
|
| 292 |
+
|
| 293 |
+
# Check if Session B is finished
|
| 294 |
+
if session_b.activo:
|
| 295 |
+
result["error"] = "La sesión B debe estar finalizada (no activa)"
|
| 296 |
+
return result
|
| 297 |
+
|
| 298 |
+
if session_b.tecnica.repeticion < 1:
|
| 299 |
+
result["error"] = "La sesión B debe haber completado al menos una repetición"
|
| 300 |
+
return result
|
| 301 |
+
|
| 302 |
+
# Get products from both sessions
|
| 303 |
+
products_a = set(
|
| 304 |
+
Producto.objects.filter(
|
| 305 |
+
calificacion_producto__id_tecnica=self.session.tecnica
|
| 306 |
+
).values_list("codigoProducto", flat=True).distinct()
|
| 307 |
+
)
|
| 308 |
+
|
| 309 |
+
products_b = set(
|
| 310 |
+
Producto.objects.filter(
|
| 311 |
+
calificacion_producto__id_tecnica=session_b.tecnica
|
| 312 |
+
).values_list("codigoProducto", flat=True).distinct()
|
| 313 |
+
)
|
| 314 |
+
|
| 315 |
+
# Check if products match
|
| 316 |
+
if products_a != products_b:
|
| 317 |
+
result["error"] = f"Los productos no coinciden. Sesión A: {len(products_a)} productos, Sesión B: {len(products_b)} productos"
|
| 318 |
+
return result
|
| 319 |
+
|
| 320 |
+
# Get tasters from both sessions
|
| 321 |
+
tasters_a = set(
|
| 322 |
+
Participacion.objects.filter(
|
| 323 |
+
tecnica=self.session.tecnica
|
| 324 |
+
).values_list("catador__user__username", flat=True)
|
| 325 |
+
)
|
| 326 |
+
|
| 327 |
+
tasters_b = set(
|
| 328 |
+
Participacion.objects.filter(
|
| 329 |
+
tecnica=session_b.tecnica
|
| 330 |
+
).values_list("catador__user__username", flat=True)
|
| 331 |
+
)
|
| 332 |
+
|
| 333 |
+
# Check if tasters match
|
| 334 |
+
if tasters_a != tasters_b:
|
| 335 |
+
result["error"] = f"Los catadores no coinciden. Sesión A: {len(tasters_a)} catadores, Sesión B: {len(tasters_b)} catadores"
|
| 336 |
+
return result
|
| 337 |
+
|
| 338 |
+
result["session_b"] = session_b
|
| 339 |
+
result["technique_type"] = technique_type
|
| 340 |
+
return result
|
| 341 |
+
|
| 342 |
+
def getCombinedDataForCATA(self, session_b: SesionSensorial):
|
| 343 |
+
"""Get combined data for CATA technique (word frequencies)"""
|
| 344 |
+
from collections import Counter
|
| 345 |
+
|
| 346 |
+
# Get all ratings for session B
|
| 347 |
+
ratings_b = Calificacion.objects.filter(id_tecnica=session_b.tecnica)
|
| 348 |
+
|
| 349 |
+
# Get boolean values (CATA uses boolean)
|
| 350 |
+
data = (
|
| 351 |
+
ValorBooleano.objects
|
| 352 |
+
.filter(id_dato__id_calificacion__in=ratings_b, valor=True)
|
| 353 |
+
.values(
|
| 354 |
+
palabra=F("id_dato__id_palabra__nombre_palabra"),
|
| 355 |
+
producto=F(
|
| 356 |
+
"id_dato__id_calificacion__id_producto__codigoProducto"),
|
| 357 |
+
)
|
| 358 |
+
)
|
| 359 |
+
|
| 360 |
+
# Count word frequencies per product
|
| 361 |
+
word_frequencies = defaultdict(Counter)
|
| 362 |
+
all_words_set = set()
|
| 363 |
+
|
| 364 |
+
for item in data:
|
| 365 |
+
palabra = item["palabra"]
|
| 366 |
+
producto = item["producto"]
|
| 367 |
+
word_frequencies[producto][palabra] += 1
|
| 368 |
+
all_words_set.add(palabra)
|
| 369 |
+
|
| 370 |
+
# Get vocabulary info if exists
|
| 371 |
+
vocabulary_info = self.getVocabularyInfo(session_b.tecnica)
|
| 372 |
+
|
| 373 |
+
return {
|
| 374 |
+
"word_frequencies": defaultdict_to_dict(word_frequencies),
|
| 375 |
+
"all_words": sorted(all_words_set),
|
| 376 |
+
"vocabulary_info": vocabulary_info,
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
def getCombinedDataForRATA(self, session_b: SesionSensorial):
|
| 380 |
+
"""Get combined data for RATA technique (word averages)"""
|
| 381 |
+
|
| 382 |
+
# Get all ratings for session B
|
| 383 |
+
ratings_b = Calificacion.objects.filter(id_tecnica=session_b.tecnica)
|
| 384 |
+
|
| 385 |
+
# Get decimal values (RATA uses decimal)
|
| 386 |
+
data = (
|
| 387 |
+
ValorDecimal.objects
|
| 388 |
+
.filter(id_dato__id_calificacion__in=ratings_b)
|
| 389 |
+
.values(
|
| 390 |
+
palabra=F("id_dato__id_palabra__nombre_palabra"),
|
| 391 |
+
producto=F(
|
| 392 |
+
"id_dato__id_calificacion__id_producto__codigoProducto"),
|
| 393 |
+
valor_decimal=F("valor"),
|
| 394 |
+
)
|
| 395 |
+
)
|
| 396 |
+
|
| 397 |
+
# Calculate averages per product per word
|
| 398 |
+
word_sums = defaultdict(lambda: defaultdict(list))
|
| 399 |
+
all_words_set = set()
|
| 400 |
+
|
| 401 |
+
for item in data:
|
| 402 |
+
palabra = item["palabra"]
|
| 403 |
+
producto = item["producto"]
|
| 404 |
+
valor = item["valor_decimal"]
|
| 405 |
+
word_sums[producto][palabra].append(valor)
|
| 406 |
+
all_words_set.add(palabra)
|
| 407 |
+
|
| 408 |
+
# Calculate averages
|
| 409 |
+
word_averages = {}
|
| 410 |
+
for producto, palabras in word_sums.items():
|
| 411 |
+
word_averages[producto] = {}
|
| 412 |
+
for palabra, valores in palabras.items():
|
| 413 |
+
word_averages[producto][palabra] = sum(valores) / len(valores)
|
| 414 |
+
|
| 415 |
+
# Get vocabulary info if exists
|
| 416 |
+
vocabulary_info = self.getVocabularyInfo(session_b.tecnica)
|
| 417 |
+
|
| 418 |
+
return {
|
| 419 |
+
"word_averages": word_averages,
|
| 420 |
+
"all_words": sorted(all_words_set),
|
| 421 |
+
"vocabulary_info": vocabulary_info,
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
def getCombinedDataForEscalas(self, session_b: SesionSensorial):
|
| 425 |
+
"""Get combined data for Escalas technique (averages across repetitions)"""
|
| 426 |
+
|
| 427 |
+
# Get all ratings for session B
|
| 428 |
+
ratings_b = Calificacion.objects.filter(id_tecnica=session_b.tecnica)
|
| 429 |
+
|
| 430 |
+
# Get decimal values grouped by repetition
|
| 431 |
+
data = (
|
| 432 |
+
ValorDecimal.objects
|
| 433 |
+
.filter(id_dato__id_calificacion__in=ratings_b)
|
| 434 |
+
.values(
|
| 435 |
+
palabra=F("id_dato__id_palabra__nombre_palabra"),
|
| 436 |
+
producto=F(
|
| 437 |
+
"id_dato__id_calificacion__id_producto__codigoProducto"),
|
| 438 |
+
repeticion=F("id_dato__id_calificacion__num_repeticion"),
|
| 439 |
+
valor_decimal=F("valor"),
|
| 440 |
+
)
|
| 441 |
+
)
|
| 442 |
+
|
| 443 |
+
# Calculate averages per repetition (like RATA), then average across repetitions
|
| 444 |
+
# Structure: {producto: {repeticion: {palabra: [valores]}}}
|
| 445 |
+
repetition_values = defaultdict(
|
| 446 |
+
lambda: defaultdict(lambda: defaultdict(list)))
|
| 447 |
+
all_words_set = set()
|
| 448 |
+
|
| 449 |
+
for item in data:
|
| 450 |
+
palabra = item["palabra"]
|
| 451 |
+
producto = item["producto"]
|
| 452 |
+
repeticion = item["repeticion"]
|
| 453 |
+
valor = item["valor_decimal"]
|
| 454 |
+
# Collect all values for averaging
|
| 455 |
+
repetition_values[producto][repeticion][palabra].append(valor)
|
| 456 |
+
all_words_set.add(palabra)
|
| 457 |
+
|
| 458 |
+
# Calculate average per repetition, then average across repetitions
|
| 459 |
+
word_averages = {}
|
| 460 |
+
for producto, repeticiones in repetition_values.items():
|
| 461 |
+
word_averages[producto] = {}
|
| 462 |
+
# Get all words for this product across all repetitions
|
| 463 |
+
all_product_words = set()
|
| 464 |
+
for rep_words in repeticiones.values():
|
| 465 |
+
all_product_words.update(rep_words.keys())
|
| 466 |
+
|
| 467 |
+
# Calculate average for each word
|
| 468 |
+
for palabra in all_product_words:
|
| 469 |
+
# Get average for each repetition
|
| 470 |
+
rep_averages = []
|
| 471 |
+
for rep in repeticiones.keys():
|
| 472 |
+
if palabra in repeticiones[rep]:
|
| 473 |
+
valores = repeticiones[rep][palabra]
|
| 474 |
+
rep_averages.append(sum(valores) / len(valores))
|
| 475 |
+
|
| 476 |
+
# Average the repetition averages
|
| 477 |
+
if rep_averages:
|
| 478 |
+
word_averages[producto][palabra] = sum(
|
| 479 |
+
rep_averages) / len(rep_averages)
|
| 480 |
+
|
| 481 |
+
# Get scale and vocabulary info
|
| 482 |
+
scale = Escala.objects.get(tecnica=session_b.tecnica)
|
| 483 |
+
scale_info = None
|
| 484 |
+
if scale:
|
| 485 |
+
scale_info = {
|
| 486 |
+
"type": scale.id_tipo_escala.nombre_escala,
|
| 487 |
+
"size": scale.longitud
|
| 488 |
+
}
|
| 489 |
+
|
| 490 |
+
vocabulary_info = self.getVocabularyInfo(session_b.tecnica)
|
| 491 |
+
|
| 492 |
+
return {
|
| 493 |
+
"word_averages": word_averages,
|
| 494 |
+
"all_words": sorted(all_words_set),
|
| 495 |
+
"scale_info": scale_info,
|
| 496 |
+
"vocabulary_info": vocabulary_info,
|
| 497 |
+
"num_repetitions": session_b.tecnica.repeticion,
|
| 498 |
+
}
|
| 499 |
+
|
| 500 |
+
def getVocabularyInfo(self, tecnica):
|
| 501 |
+
es_vocabulario = EsVocabulario.objects.filter(
|
| 502 |
+
id_tecnica=tecnica).first()
|
| 503 |
+
if es_vocabulario:
|
| 504 |
+
vocabulario = es_vocabulario.id_vocabulario
|
| 505 |
+
return {
|
| 506 |
+
"nombre": vocabulario.nombre_vocabulario,
|
| 507 |
+
}
|
| 508 |
+
return None
|
tecnicas/controllers/views_controller/session_management/details/details_pf_controller.py
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from tecnicas.models import SesionSensorial, ListaPalabras, Calificacion, Catador
|
| 2 |
+
from tecnicas.controllers import DatoController
|
| 3 |
+
from tecnicas.utils import defaultdict_to_dict
|
| 4 |
+
from .details_controller import DetallesController
|
| 5 |
+
from collections import defaultdict
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class DetallesPFController(DetallesController):
|
| 9 |
+
skip_repetition = 2
|
| 10 |
+
|
| 11 |
+
def __init__(self, session: SesionSensorial):
|
| 12 |
+
super().__init__(session)
|
| 13 |
+
self.url_template = "tecnicas/manage_sesions/details-session-pf.html"
|
| 14 |
+
self.url_next = "cata_system:monitor_sesion"
|
| 15 |
+
|
| 16 |
+
def getContext(self):
|
| 17 |
+
technique = self.session.tecnica
|
| 18 |
+
|
| 19 |
+
self.context = {
|
| 20 |
+
"sesion": self.session,
|
| 21 |
+
"use_technique": technique,
|
| 22 |
+
"tipo_escala": technique.escala_tecnica.id_tipo_escala.nombre_escala,
|
| 23 |
+
"repeticiones_max": technique.repeticiones_max - self.skip_repetition
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
# Definir el estado de la sesion
|
| 27 |
+
rep = technique.repeticion
|
| 28 |
+
activate = self.session.activo
|
| 29 |
+
self.context["estado"] = self.getStatus(rep, activate)
|
| 30 |
+
|
| 31 |
+
self.getDataPhases()
|
| 32 |
+
|
| 33 |
+
self.isEndSession()
|
| 34 |
+
|
| 35 |
+
return self.context
|
| 36 |
+
|
| 37 |
+
def isEndSession(self):
|
| 38 |
+
current_rep = self.session.tecnica.repeticion - self.skip_repetition
|
| 39 |
+
max_rep = self.session.tecnica.repeticiones_max - self.skip_repetition
|
| 40 |
+
self.context["finished"] = current_rep >= max_rep
|
| 41 |
+
|
| 42 |
+
def getDataPhases(self):
|
| 43 |
+
curren_repetition = self.session.tecnica.repeticion
|
| 44 |
+
|
| 45 |
+
if curren_repetition == 1:
|
| 46 |
+
self.context["fisrt_phase"] = self.getDataFirstPhase()
|
| 47 |
+
self.context["repeticion"] = 0
|
| 48 |
+
|
| 49 |
+
elif curren_repetition == 2:
|
| 50 |
+
self.context["fisrt_phase"] = self.getDataFirstPhase()
|
| 51 |
+
self.context["second_phase"] = self.getDataSecondPhase()
|
| 52 |
+
self.context["repeticion"] = 0
|
| 53 |
+
|
| 54 |
+
elif curren_repetition >= 3:
|
| 55 |
+
self.context["fisrt_phase"] = self.getDataFirstPhase()
|
| 56 |
+
self.context["second_phase"] = self.getDataSecondPhase()
|
| 57 |
+
self.context["data_ratings"] = self.getDataRatings()
|
| 58 |
+
self.context["repeticion"] = self.session.tecnica.repeticion - self.skip_repetition
|
| 59 |
+
|
| 60 |
+
return self.context
|
| 61 |
+
|
| 62 |
+
def getDataFirstPhase(self):
|
| 63 |
+
lists_testers = ListaPalabras.objects.filter(
|
| 64 |
+
tecnica=self.session.tecnica,
|
| 65 |
+
es_final=False
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
result = []
|
| 69 |
+
for list in lists_testers:
|
| 70 |
+
try:
|
| 71 |
+
username = list.catador.user.username
|
| 72 |
+
except Exception:
|
| 73 |
+
username = None
|
| 74 |
+
|
| 75 |
+
words_qs = list.palabras.all()
|
| 76 |
+
words = []
|
| 77 |
+
for p in words_qs:
|
| 78 |
+
nombre = getattr(p, 'nombre_palabra', None)
|
| 79 |
+
words.append({
|
| 80 |
+
'id': getattr(p, 'id', None),
|
| 81 |
+
'nombre_palabra': nombre
|
| 82 |
+
})
|
| 83 |
+
|
| 84 |
+
result.append({
|
| 85 |
+
'username': username,
|
| 86 |
+
'words': words
|
| 87 |
+
})
|
| 88 |
+
|
| 89 |
+
return result
|
| 90 |
+
|
| 91 |
+
def getDataSecondPhase(self):
|
| 92 |
+
lists_testers = ListaPalabras.objects.filter(
|
| 93 |
+
tecnica=self.session.tecnica,
|
| 94 |
+
es_final=True
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
result = []
|
| 98 |
+
for list in lists_testers:
|
| 99 |
+
try:
|
| 100 |
+
username = list.catador.user.username
|
| 101 |
+
except Exception:
|
| 102 |
+
username = None
|
| 103 |
+
|
| 104 |
+
words_qs = list.palabras.all()
|
| 105 |
+
words = []
|
| 106 |
+
for p in words_qs:
|
| 107 |
+
nombre = getattr(p, 'nombre_palabra', None)
|
| 108 |
+
words.append({
|
| 109 |
+
'id': getattr(p, 'id', None),
|
| 110 |
+
'nombre_palabra': nombre
|
| 111 |
+
})
|
| 112 |
+
|
| 113 |
+
result.append({
|
| 114 |
+
'username': username,
|
| 115 |
+
'words': words
|
| 116 |
+
})
|
| 117 |
+
|
| 118 |
+
return result
|
| 119 |
+
|
| 120 |
+
def getDataRatings(self):
|
| 121 |
+
technique = self.session.tecnica
|
| 122 |
+
|
| 123 |
+
if technique.repeticion > 3:
|
| 124 |
+
return self.getDataRatingsFinal()
|
| 125 |
+
|
| 126 |
+
elif technique.repeticion == 3:
|
| 127 |
+
return self.getDataRatingsInitial()
|
| 128 |
+
|
| 129 |
+
def getStatus(self, rep: int, activate: bool):
|
| 130 |
+
status = ""
|
| 131 |
+
|
| 132 |
+
if rep == 0 and not activate:
|
| 133 |
+
status = "Listo para crear listas iniciales"
|
| 134 |
+
|
| 135 |
+
elif rep == 1 and activate:
|
| 136 |
+
status = "En primera fase, creación de listas iniciales"
|
| 137 |
+
elif rep == 1 and not activate:
|
| 138 |
+
status = "Listo para crear listas finales"
|
| 139 |
+
|
| 140 |
+
elif rep == 2 and activate:
|
| 141 |
+
status = "En segunda fase, creación de listas finales"
|
| 142 |
+
elif rep == 2 and not activate:
|
| 143 |
+
status = "Listo para calificaciones"
|
| 144 |
+
|
| 145 |
+
elif rep > 2 and not activate:
|
| 146 |
+
status = "Listo para calificaciones"
|
| 147 |
+
elif rep > 2 and activate:
|
| 148 |
+
status = "Catadores calificando"
|
| 149 |
+
|
| 150 |
+
return status
|
| 151 |
+
|
| 152 |
+
def getDataRatingsInitial(self):
|
| 153 |
+
ratings = list(Calificacion.objects.filter(id_tecnica=self.session.tecnica, num_repeticion=3))
|
| 154 |
+
|
| 155 |
+
if ratings:
|
| 156 |
+
raw_data = DatoController.getWordValuesForConvecional(
|
| 157 |
+
technique=self.session.tecnica,
|
| 158 |
+
ratings=ratings
|
| 159 |
+
)
|
| 160 |
+
|
| 161 |
+
structured_data = defaultdict(lambda: defaultdict(list))
|
| 162 |
+
|
| 163 |
+
for item in raw_data:
|
| 164 |
+
prod_code = item["producto_code"]
|
| 165 |
+
username = item["usuario_catador"]
|
| 166 |
+
|
| 167 |
+
structured_data[prod_code][username].append({
|
| 168 |
+
"palabra": item["nombre_palabra"],
|
| 169 |
+
"valor": item["dato_valor"]
|
| 170 |
+
})
|
| 171 |
+
|
| 172 |
+
return defaultdict_to_dict(structured_data)
|
| 173 |
+
|
| 174 |
+
def getDataRatingsFinal(self):
|
| 175 |
+
lists_words_testers = self.context["second_phase"]
|
| 176 |
+
technique = self.session.tecnica
|
| 177 |
+
|
| 178 |
+
ratings_for_tester = []
|
| 179 |
+
|
| 180 |
+
for list_tester in lists_words_testers:
|
| 181 |
+
tester_username = list_tester["username"]
|
| 182 |
+
# Se recuperan las calificaciones
|
| 183 |
+
ratings_for_repetition = []
|
| 184 |
+
|
| 185 |
+
ratings = list(Calificacion.objects.filter(
|
| 186 |
+
id_tecnica=technique, id_catador__user__username=tester_username))
|
| 187 |
+
|
| 188 |
+
if not ratings:
|
| 189 |
+
continue
|
| 190 |
+
|
| 191 |
+
data = DatoController.getWordValuesPF(
|
| 192 |
+
ratings=ratings, technique=technique, tester=Catador.objects.get(user__username=tester_username))
|
| 193 |
+
|
| 194 |
+
ratings_for_repetition = defaultdict(lambda: defaultdict(list))
|
| 195 |
+
|
| 196 |
+
# Estructurar los datos
|
| 197 |
+
for item in data:
|
| 198 |
+
rep = item["repeticion"]
|
| 199 |
+
prod = item["producto_code"]
|
| 200 |
+
|
| 201 |
+
ratings_for_repetition[rep-2][prod].append({
|
| 202 |
+
"nombre_palabra": item["nombre_palabra"],
|
| 203 |
+
"dato_valor": item["dato_valor"]
|
| 204 |
+
})
|
| 205 |
+
|
| 206 |
+
ratings_for_tester.append(
|
| 207 |
+
{
|
| 208 |
+
"tester": tester_username,
|
| 209 |
+
"ratings": defaultdict_to_dict(
|
| 210 |
+
ratings_for_repetition),
|
| 211 |
+
"words": list_tester["words"]
|
| 212 |
+
}
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
return ratings_for_tester
|
tecnicas/controllers/views_controller/session_management/details/details_rata_controller.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from tecnicas.models import SesionSensorial
|
| 2 |
+
from .details_controller import DetallesController
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class DetallesRATAController(DetallesController):
|
| 6 |
+
def __init__(self, session: SesionSensorial):
|
| 7 |
+
super().__init__(session)
|
tecnicas/controllers/views_controller/session_management/details/details_sort_controller.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .details_controller import DetallesController
|
| 2 |
+
from tecnicas.models import SesionSensorial, GrupoProducto, Producto, Participacion
|
| 3 |
+
from collections import defaultdict
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class DetallesSortController(DetallesController):
|
| 7 |
+
def __init__(self, session: SesionSensorial):
|
| 8 |
+
super().__init__(session)
|
| 9 |
+
self.url_template = "tecnicas/manage_sesions/details-session-sort.html"
|
| 10 |
+
self.url_next = "cata_system:monitor_sesion"
|
| 11 |
+
|
| 12 |
+
def getContext(self):
|
| 13 |
+
technique = self.session.tecnica
|
| 14 |
+
|
| 15 |
+
finished = False
|
| 16 |
+
status = ""
|
| 17 |
+
|
| 18 |
+
if technique.repeticion < technique.repeticiones_max and not self.session.activo:
|
| 19 |
+
status = "En espera para iniciar la sesión"
|
| 20 |
+
elif technique.repeticion >= technique.repeticiones_max and not self.session.activo:
|
| 21 |
+
status = "Esta sesión ha sido finalizada"
|
| 22 |
+
finished = True
|
| 23 |
+
else:
|
| 24 |
+
status = "La sesión está en progreso"
|
| 25 |
+
|
| 26 |
+
self.context = {
|
| 27 |
+
"sesion": self.session,
|
| 28 |
+
"technique": technique,
|
| 29 |
+
"status": status,
|
| 30 |
+
"finished": finished
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
self.context["data_groups"] = {
|
| 34 |
+
"data": self.setDataSort(),
|
| 35 |
+
"testers": self.setHeaders()
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
return self.context
|
| 39 |
+
|
| 40 |
+
def setDataSort(self):
|
| 41 |
+
data = []
|
| 42 |
+
technique = self.session.tecnica
|
| 43 |
+
|
| 44 |
+
products = Producto.objects.filter(id_tecnica=technique)
|
| 45 |
+
|
| 46 |
+
groups = GrupoProducto.objects.select_related("catador").filter(
|
| 47 |
+
tecnica=technique
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
if len(groups):
|
| 51 |
+
self.context["there_data"] = True
|
| 52 |
+
else:
|
| 53 |
+
self.context["there_data"] = False
|
| 54 |
+
return []
|
| 55 |
+
|
| 56 |
+
for product in products:
|
| 57 |
+
product_data = {
|
| 58 |
+
"codigo_producto": product.codigoProducto,
|
| 59 |
+
"palabras": {}
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
related_groups = groups.filter(productos=product).select_related(
|
| 63 |
+
"catador__user"
|
| 64 |
+
).prefetch_related("palabras")
|
| 65 |
+
|
| 66 |
+
data_words = defaultdict(set)
|
| 67 |
+
|
| 68 |
+
for group in related_groups:
|
| 69 |
+
catador_username = group.catador.user.username
|
| 70 |
+
|
| 71 |
+
for word in group.palabras.all():
|
| 72 |
+
data_words[catador_username].add(word.nombre_palabra)
|
| 73 |
+
|
| 74 |
+
product_data["palabras"] = {
|
| 75 |
+
username: list(words)
|
| 76 |
+
for username, words in data_words.items()
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
data.append(product_data)
|
| 80 |
+
|
| 81 |
+
return data
|
| 82 |
+
|
| 83 |
+
def setHeaders(self):
|
| 84 |
+
participacions = list(Participacion.objects.filter(
|
| 85 |
+
tecnica=self.session.tecnica
|
| 86 |
+
).only("catador").select_related("catador__user"))
|
| 87 |
+
|
| 88 |
+
testers = [
|
| 89 |
+
participacion.catador.user.username for participacion in participacions]
|
| 90 |
+
|
| 91 |
+
return testers
|
tecnicas/controllers/views_controller/session_management/details_controller.py
DELETED
|
@@ -1,13 +0,0 @@
|
|
| 1 |
-
from tecnicas.models import SesionSensorial, Presentador, Tecnica
|
| 2 |
-
from tecnicas.utils import controller_error
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
class DetallesController():
|
| 6 |
-
url_template = "tecnicas/manage_sesions/detalles-sesion.html"
|
| 7 |
-
|
| 8 |
-
def __init__(self, session: SesionSensorial):
|
| 9 |
-
self.session = session
|
| 10 |
-
|
| 11 |
-
def deleteSesorialSession(self):
|
| 12 |
-
technique = Tecnica.objects.get(id=self.session.tecnica.id)
|
| 13 |
-
technique.delete()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tecnicas/controllers/views_controller/session_management/{monitor_controller.py → monitor/monitor_controller.py}
RENAMED
|
@@ -1,8 +1,7 @@
|
|
| 1 |
from django.http import HttpRequest
|
| 2 |
-
from django.shortcuts import render
|
| 3 |
-
from
|
| 4 |
-
from tecnicas.
|
| 5 |
-
from tecnicas.utils import controller_error
|
| 6 |
|
| 7 |
|
| 8 |
class MonitorController():
|
|
@@ -12,9 +11,21 @@ class MonitorController():
|
|
| 12 |
def __init__(self, session: SesionSensorial):
|
| 13 |
self.sensorial_session = session
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
def setContext(self):
|
| 16 |
-
self.participations =
|
| 17 |
-
self.sensorial_session.tecnica)
|
| 18 |
|
| 19 |
self.context = {
|
| 20 |
"code_session": self.sensorial_session.codigo_sesion,
|
|
@@ -26,7 +37,7 @@ class MonitorController():
|
|
| 26 |
"use_technique": self.sensorial_session.tecnica.tipo_tecnica.nombre_tecnica
|
| 27 |
}
|
| 28 |
|
| 29 |
-
def
|
| 30 |
self.setContext()
|
| 31 |
|
| 32 |
if error != "" or error:
|
|
@@ -36,7 +47,7 @@ class MonitorController():
|
|
| 36 |
|
| 37 |
return render(request, self.url_view, self.context)
|
| 38 |
|
| 39 |
-
def
|
| 40 |
num_products = Producto.objects.filter(
|
| 41 |
id_tecnica=self.sensorial_session.tecnica).count()
|
| 42 |
style_words = self.sensorial_session.tecnica.id_estilo
|
|
@@ -52,8 +63,6 @@ class MonitorController():
|
|
| 52 |
return num_products * num_words
|
| 53 |
|
| 54 |
def finishSession(self):
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
return controller_error(response["error"])
|
| 58 |
-
self.sensorial_session.refresh_from_db()
|
| 59 |
return self.sensorial_session
|
|
|
|
| 1 |
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import render, redirect
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import SesionSensorial, Producto, EsAtributo, EsVocabulario, Participacion
|
|
|
|
| 5 |
|
| 6 |
|
| 7 |
class MonitorController():
|
|
|
|
| 11 |
def __init__(self, session: SesionSensorial):
|
| 12 |
self.sensorial_session = session
|
| 13 |
|
| 14 |
+
def controllPostFinishSession(self, request: HttpRequest):
|
| 15 |
+
(is_all_end, message) = self.checkAllFinish()
|
| 16 |
+
if not is_all_end:
|
| 17 |
+
self.setContext()
|
| 18 |
+
self.context["error"] = message
|
| 19 |
+
return render(request, self.url_view, self.context)
|
| 20 |
+
self.finishSession()
|
| 21 |
+
return redirect(reverse(self.previus_view, kwargs={"session_code": self.sensorial_session.codigo_sesion}))
|
| 22 |
+
|
| 23 |
+
def checkAllFinish(self) -> (bool, str):
|
| 24 |
+
return (False, "Función sin implementar")
|
| 25 |
+
|
| 26 |
def setContext(self):
|
| 27 |
+
self.participations = Participacion.objects.filter(
|
| 28 |
+
tecnica=self.sensorial_session.tecnica)
|
| 29 |
|
| 30 |
self.context = {
|
| 31 |
"code_session": self.sensorial_session.codigo_sesion,
|
|
|
|
| 37 |
"use_technique": self.sensorial_session.tecnica.tipo_tecnica.nombre_tecnica
|
| 38 |
}
|
| 39 |
|
| 40 |
+
def controllGetResponse(self, request: HttpRequest, error: str = "", message: str = ""):
|
| 41 |
self.setContext()
|
| 42 |
|
| 43 |
if error != "" or error:
|
|
|
|
| 47 |
|
| 48 |
return render(request, self.url_view, self.context)
|
| 49 |
|
| 50 |
+
def getExpectedRatings(self):
|
| 51 |
num_products = Producto.objects.filter(
|
| 52 |
id_tecnica=self.sensorial_session.tecnica).count()
|
| 53 |
style_words = self.sensorial_session.tecnica.id_estilo
|
|
|
|
| 63 |
return num_products * num_words
|
| 64 |
|
| 65 |
def finishSession(self):
|
| 66 |
+
self.sensorial_session.activo = False
|
| 67 |
+
self.sensorial_session.save()
|
|
|
|
|
|
|
| 68 |
return self.sensorial_session
|
tecnicas/controllers/views_controller/session_management/{monitor_escalas_controller.py → monitor/monitor_escalas_controller.py}
RENAMED
|
@@ -1,6 +1,3 @@
|
|
| 1 |
-
from django.http import HttpRequest
|
| 2 |
-
from django.shortcuts import render, redirect
|
| 3 |
-
from django.urls import reverse
|
| 4 |
from tecnicas.models import Dato, Participacion
|
| 5 |
from tecnicas.controllers import SesionController
|
| 6 |
from .monitor_controller import MonitorController
|
|
@@ -12,23 +9,10 @@ class MonitorEscalasController(MonitorController):
|
|
| 12 |
self.url_view = "tecnicas/manage_sesions/monitor-sesion.html"
|
| 13 |
self.previus_view = "cata_system:detalles_sesion"
|
| 14 |
|
| 15 |
-
def controllPostFinishSession(self, request: HttpRequest):
|
| 16 |
-
self.setContext()
|
| 17 |
-
(is_all_end, message) = self.checkAllFinish()
|
| 18 |
-
if not is_all_end:
|
| 19 |
-
self.context["error"] = message
|
| 20 |
-
return render(request, self.url_view, self.context)
|
| 21 |
-
response = self.finishSession()
|
| 22 |
-
if isinstance(response, dict):
|
| 23 |
-
self.context["error"] = response["error"]
|
| 24 |
-
return render(request, self.url_view, self.context)
|
| 25 |
-
self.context["message"] = message
|
| 26 |
-
return redirect(reverse(self.previus_view, kwargs={"session_code": self.sensorial_session.codigo_sesion}))
|
| 27 |
-
|
| 28 |
def checkAllFinish(self):
|
| 29 |
technique = self.sensorial_session.tecnica
|
| 30 |
|
| 31 |
-
expected_ratings_repetition = self.
|
| 32 |
|
| 33 |
all_participations = list(
|
| 34 |
Participacion.objects.filter(tecnica=technique))
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from tecnicas.models import Dato, Participacion
|
| 2 |
from tecnicas.controllers import SesionController
|
| 3 |
from .monitor_controller import MonitorController
|
|
|
|
| 9 |
self.url_view = "tecnicas/manage_sesions/monitor-sesion.html"
|
| 10 |
self.previus_view = "cata_system:detalles_sesion"
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
def checkAllFinish(self):
|
| 13 |
technique = self.sensorial_session.tecnica
|
| 14 |
|
| 15 |
+
expected_ratings_repetition = self.getExpectedRatings()
|
| 16 |
|
| 17 |
all_participations = list(
|
| 18 |
Participacion.objects.filter(tecnica=technique))
|
tecnicas/controllers/views_controller/session_management/monitor/monitor_napping_controller.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from tecnicas.models import SesionSensorial
|
| 2 |
+
from tecnicas.models import Participacion, TecnicaModalidad
|
| 3 |
+
from .monitor_controller import MonitorController
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class MonitorNappingController(MonitorController):
|
| 7 |
+
def __init__(self, session: SesionSensorial):
|
| 8 |
+
super().__init__(session)
|
| 9 |
+
self.url_view = "tecnicas/manage_sesions/monitor-session-sort.html"
|
| 10 |
+
self.previus_view = "cata_system:detalles_sesion"
|
| 11 |
+
|
| 12 |
+
def checkAllFinish(self) -> (bool, str):
|
| 13 |
+
technique = self.sensorial_session.tecnica
|
| 14 |
+
|
| 15 |
+
num_participations = Participacion.objects.filter(
|
| 16 |
+
tecnica=technique).count()
|
| 17 |
+
|
| 18 |
+
if num_participations < technique.limite_catadores:
|
| 19 |
+
return (False, "No se ha alcanzado el número máximo de catadores")
|
| 20 |
+
|
| 21 |
+
unfinished_participations = Participacion.objects.filter(
|
| 22 |
+
tecnica=technique, finalizado=False).count()
|
| 23 |
+
|
| 24 |
+
if unfinished_participations > 0:
|
| 25 |
+
return (False, "No todos los catadores han finalizado su evaluación")
|
| 26 |
+
|
| 27 |
+
return (True, "Puedes finalizar la sesión")
|
| 28 |
+
|
| 29 |
+
def finishSession(self):
|
| 30 |
+
technique = self.sensorial_session.tecnica
|
| 31 |
+
technique.repeticion = 1
|
| 32 |
+
technique.save()
|
| 33 |
+
self.sensorial_session.activo = False
|
| 34 |
+
self.sensorial_session.save()
|
| 35 |
+
return self.sensorial_session
|
tecnicas/controllers/views_controller/session_management/monitor/monitor_pf_controller.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from tecnicas.models import Dato, Participacion, Catador, ListaPalabras, Producto
|
| 2 |
+
from tecnicas.controllers import SesionController
|
| 3 |
+
from .monitor_controller import MonitorController
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class MonitorPFController(MonitorController):
|
| 7 |
+
def __init__(self, session: SesionController):
|
| 8 |
+
super().__init__(session)
|
| 9 |
+
self.url_view = "tecnicas/manage_sesions/monitor-session-pf.html"
|
| 10 |
+
self.previus_view = "cata_system:detalles_sesion"
|
| 11 |
+
|
| 12 |
+
def checkAllFinish(self):
|
| 13 |
+
rep = self.sensorial_session.tecnica.repeticion
|
| 14 |
+
|
| 15 |
+
finish_data = ()
|
| 16 |
+
|
| 17 |
+
if rep == 1 or rep == 2:
|
| 18 |
+
finish_data = self.checkFinishFirstPhase()
|
| 19 |
+
elif rep >= 3:
|
| 20 |
+
finish_data = self.checkFinishRepetition()
|
| 21 |
+
|
| 22 |
+
return finish_data
|
| 23 |
+
|
| 24 |
+
def checkFinishFirstPhase(self):
|
| 25 |
+
num_paricipations = Participacion.objects.filter(
|
| 26 |
+
tecnica=self.sensorial_session.tecnica).count()
|
| 27 |
+
if num_paricipations < self.sensorial_session.tecnica.limite_catadores:
|
| 28 |
+
return (False, "No se ha alcanzado el número máximo de catadores")
|
| 29 |
+
|
| 30 |
+
unfinished_participations = Participacion.objects.filter(
|
| 31 |
+
tecnica=self.sensorial_session.tecnica, finalizado=False).count()
|
| 32 |
+
if unfinished_participations:
|
| 33 |
+
return (False, "No todos los catadores han finalizado su evaluación")
|
| 34 |
+
|
| 35 |
+
return (True, "Puedes finalizar la sesión")
|
| 36 |
+
|
| 37 |
+
def checkFinishRepetition(self) -> tuple[bool, str]:
|
| 38 |
+
technique = self.sensorial_session.tecnica
|
| 39 |
+
|
| 40 |
+
# Revisar numero de catadores sea alcanzado
|
| 41 |
+
all_participations = list(
|
| 42 |
+
Participacion.objects.filter(tecnica=technique))
|
| 43 |
+
if len(all_participations) < technique.limite_catadores:
|
| 44 |
+
return (False, "No se ha alcanzado el número máximo de Catadores")
|
| 45 |
+
|
| 46 |
+
# Revisar que cada catador haya terminado de calificar sus palabras
|
| 47 |
+
for particiapation in all_participations:
|
| 48 |
+
expected_ratings_repetition = self.getExpectedRatings(
|
| 49 |
+
tester=particiapation.catador)
|
| 50 |
+
|
| 51 |
+
num_ratings_now = Dato.objects.filter(
|
| 52 |
+
id_calificacion__num_repeticion=technique.repeticion,
|
| 53 |
+
id_calificacion__id_catador=particiapation.catador,
|
| 54 |
+
id_calificacion__id_tecnica=technique
|
| 55 |
+
).count()
|
| 56 |
+
|
| 57 |
+
if num_ratings_now < expected_ratings_repetition:
|
| 58 |
+
return (False, "No todos los catadores han finalizado su evaluación")
|
| 59 |
+
|
| 60 |
+
return (True, "Puedes finalizar la sesión")
|
| 61 |
+
|
| 62 |
+
def getExpectedRatings(self, tester: Catador):
|
| 63 |
+
num_words = ListaPalabras.objects.get(
|
| 64 |
+
tecnica=self.sensorial_session.tecnica,
|
| 65 |
+
catador=tester,
|
| 66 |
+
es_final=True
|
| 67 |
+
).palabras.all().count()
|
| 68 |
+
|
| 69 |
+
num_products = Producto.objects.filter(
|
| 70 |
+
id_tecnica=self.sensorial_session.tecnica).count()
|
| 71 |
+
|
| 72 |
+
return num_products * num_words
|
tecnicas/controllers/views_controller/session_management/{monitor_rata_controller.py → monitor/monitor_rata_controller.py}
RENAMED
|
@@ -1,6 +1,3 @@
|
|
| 1 |
-
from django.http import HttpRequest
|
| 2 |
-
from django.shortcuts import render, redirect
|
| 3 |
-
from django.urls import reverse
|
| 4 |
from tecnicas.models import Dato, Participacion
|
| 5 |
from tecnicas.controllers import SesionController
|
| 6 |
from .monitor_controller import MonitorController
|
|
@@ -12,23 +9,10 @@ class MonitorRATAController(MonitorController):
|
|
| 12 |
self.url_view = "tecnicas/manage_sesions/monitor-sesion.html"
|
| 13 |
self.previus_view = "cata_system:detalles_sesion"
|
| 14 |
|
| 15 |
-
def controllPostFinishSession(self, request: HttpRequest):
|
| 16 |
-
self.setContext()
|
| 17 |
-
(is_all_end, message) = self.checkAllFinish()
|
| 18 |
-
if not is_all_end:
|
| 19 |
-
self.context["error"] = message
|
| 20 |
-
return render(request, self.url_view, self.context)
|
| 21 |
-
response = self.finishSession()
|
| 22 |
-
if isinstance(response, dict):
|
| 23 |
-
self.context["error"] = response["error"]
|
| 24 |
-
return render(request, self.url_view, self.context)
|
| 25 |
-
self.context["message"] = message
|
| 26 |
-
return redirect(reverse(self.previus_view, kwargs={"session_code": self.sensorial_session.codigo_sesion}))
|
| 27 |
-
|
| 28 |
def checkAllFinish(self):
|
| 29 |
technique = self.sensorial_session.tecnica
|
| 30 |
|
| 31 |
-
expected_ratings_repetition = self.
|
| 32 |
|
| 33 |
all_participations = list(
|
| 34 |
Participacion.objects.filter(tecnica=technique))
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from tecnicas.models import Dato, Participacion
|
| 2 |
from tecnicas.controllers import SesionController
|
| 3 |
from .monitor_controller import MonitorController
|
|
|
|
| 9 |
self.url_view = "tecnicas/manage_sesions/monitor-sesion.html"
|
| 10 |
self.previus_view = "cata_system:detalles_sesion"
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
def checkAllFinish(self):
|
| 13 |
technique = self.sensorial_session.tecnica
|
| 14 |
|
| 15 |
+
expected_ratings_repetition = self.getExpectedRatings()
|
| 16 |
|
| 17 |
all_participations = list(
|
| 18 |
Participacion.objects.filter(tecnica=technique))
|
tecnicas/controllers/views_controller/session_management/monitor/monitor_sort_controller.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from tecnicas.models import SesionSensorial
|
| 2 |
+
from tecnicas.models import Participacion
|
| 3 |
+
from .monitor_controller import MonitorController
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class MonitorSortController(MonitorController):
|
| 7 |
+
def __init__(self, session: SesionSensorial):
|
| 8 |
+
super().__init__(session)
|
| 9 |
+
self.url_view = "tecnicas/manage_sesions/monitor-session-sort.html"
|
| 10 |
+
self.previus_view = "cata_system:detalles_sesion"
|
| 11 |
+
|
| 12 |
+
def checkAllFinish(self):
|
| 13 |
+
technique = self.sensorial_session.tecnica
|
| 14 |
+
|
| 15 |
+
num_participations = Participacion.objects.filter(
|
| 16 |
+
tecnica=technique).count()
|
| 17 |
+
|
| 18 |
+
if num_participations < technique.limite_catadores:
|
| 19 |
+
return (False, "No se ha alcanzado el número máximo de catadores")
|
| 20 |
+
|
| 21 |
+
unfinished_participations = Participacion.objects.filter(
|
| 22 |
+
tecnica=technique, finalizado=False).count()
|
| 23 |
+
|
| 24 |
+
if unfinished_participations > 0:
|
| 25 |
+
return (False, "No todos los catadores han finalizado su evaluación")
|
| 26 |
+
|
| 27 |
+
return (True, "Puedes finalizar la sesión")
|
tecnicas/controllers/views_controller/sessions_tester/{init_session_tester_controller.py → init_session/init_session_controller.py}
RENAMED
|
@@ -1,96 +1,23 @@
|
|
| 1 |
-
from django.db import transaction
|
| 2 |
from django.http import HttpRequest
|
| 3 |
from django.shortcuts import render, redirect
|
| 4 |
from django.urls import reverse
|
| 5 |
-
from
|
| 6 |
-
from tecnicas.
|
| 7 |
from tecnicas.utils import controller_error, shuffleArray
|
| 8 |
|
| 9 |
|
| 10 |
-
class
|
| 11 |
tester: Catador
|
| 12 |
session: SesionSensorial
|
| 13 |
order: Orden | dict
|
| 14 |
-
current_direction
|
|
|
|
| 15 |
escalas_direction = "cata_system:session_convencional"
|
| 16 |
|
| 17 |
def __init__(self, sensorial_session: SesionSensorial, user_tester: Catador):
|
| 18 |
self.tester = user_tester
|
| 19 |
self.session = sensorial_session
|
| 20 |
|
| 21 |
-
def controllGetEscalas(self, request: HttpRequest):
|
| 22 |
-
context = {
|
| 23 |
-
"session": self.session,
|
| 24 |
-
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 25 |
-
}
|
| 26 |
-
|
| 27 |
-
order = self.checkAndAssignOrder()
|
| 28 |
-
if isinstance(order, dict):
|
| 29 |
-
context["error"] = order["error"]
|
| 30 |
-
return render(request, self.current_direction, context)
|
| 31 |
-
|
| 32 |
-
is_end = self.isEndedSessionEscalas()
|
| 33 |
-
|
| 34 |
-
request.session["id_order"] = order.id
|
| 35 |
-
context["has_ended"] = is_end
|
| 36 |
-
|
| 37 |
-
if is_end:
|
| 38 |
-
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 39 |
-
|
| 40 |
-
if "error" in request.GET:
|
| 41 |
-
context["error"] = request.GET["error"]
|
| 42 |
-
|
| 43 |
-
return render(request, self.current_direction, context)
|
| 44 |
-
|
| 45 |
-
def controllPostEscalas(self, request: HttpRequest):
|
| 46 |
-
context = {
|
| 47 |
-
"session": self.session,
|
| 48 |
-
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 49 |
-
}
|
| 50 |
-
|
| 51 |
-
if request.POST["action"] == "start_posting":
|
| 52 |
-
parameters = {
|
| 53 |
-
"code_sesion": self.session.codigo_sesion
|
| 54 |
-
}
|
| 55 |
-
|
| 56 |
-
is_end = self.isEndedSessionEscalas()
|
| 57 |
-
if is_end:
|
| 58 |
-
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 59 |
-
return render(request, self.current_direction, context)
|
| 60 |
-
|
| 61 |
-
update_participation = ParticipacionController.enterSession(
|
| 62 |
-
tester=request.user.user_catador, session=self.session)
|
| 63 |
-
if isinstance(update_participation, dict):
|
| 64 |
-
context["error"] = update_participation["error"]
|
| 65 |
-
return render(request, self.current_direction, context)
|
| 66 |
-
|
| 67 |
-
request.session["id_participation"] = update_participation.id
|
| 68 |
-
return redirect(reverse(self.escalas_direction, kwargs=parameters))
|
| 69 |
-
elif request.POST["action"] == "exit_session":
|
| 70 |
-
response = ParticipacionController.outSession(
|
| 71 |
-
tester=request.user.user_catador, session=self.session)
|
| 72 |
-
if isinstance(response, dict):
|
| 73 |
-
context["error"] = response["error"]
|
| 74 |
-
return render(request, self.current_direction, context)
|
| 75 |
-
else:
|
| 76 |
-
context["error"] = "Acción sin especificar"
|
| 77 |
-
return render(request, self.current_direction, context)
|
| 78 |
-
|
| 79 |
-
def controllGetRATA(self, request: HttpRequest):
|
| 80 |
-
context = {
|
| 81 |
-
"session": self.session,
|
| 82 |
-
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 83 |
-
}
|
| 84 |
-
|
| 85 |
-
is_end = self.isEndedSessionEscalas()
|
| 86 |
-
|
| 87 |
-
context["has_ended"] = is_end
|
| 88 |
-
|
| 89 |
-
if is_end:
|
| 90 |
-
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 91 |
-
|
| 92 |
-
return render(request, self.current_direction, context)
|
| 93 |
-
|
| 94 |
def assignOrder(self):
|
| 95 |
with transaction.atomic():
|
| 96 |
orders_without_tester = list(Orden.objects.select_for_update().filter(
|
|
@@ -117,7 +44,7 @@ class InitSessionTesterController():
|
|
| 117 |
return create
|
| 118 |
return self.order_to_assign
|
| 119 |
|
| 120 |
-
def
|
| 121 |
try:
|
| 122 |
participation = Participacion.objects.get(
|
| 123 |
catador=self.tester, tecnica=self.session.tecnica)
|
|
|
|
|
|
|
| 1 |
from django.http import HttpRequest
|
| 2 |
from django.shortcuts import render, redirect
|
| 3 |
from django.urls import reverse
|
| 4 |
+
from django.db import transaction
|
| 5 |
+
from tecnicas.models import Catador, SesionSensorial, Orden, Participacion, Producto, EsAtributo, EsVocabulario, Dato, ListaPalabras
|
| 6 |
from tecnicas.utils import controller_error, shuffleArray
|
| 7 |
|
| 8 |
|
| 9 |
+
class InitSessionController():
|
| 10 |
tester: Catador
|
| 11 |
session: SesionSensorial
|
| 12 |
order: Orden | dict
|
| 13 |
+
current_direction: str
|
| 14 |
+
current_direction = "tecnicas/forms_tester/init_scales_test.html"
|
| 15 |
escalas_direction = "cata_system:session_convencional"
|
| 16 |
|
| 17 |
def __init__(self, sensorial_session: SesionSensorial, user_tester: Catador):
|
| 18 |
self.tester = user_tester
|
| 19 |
self.session = sensorial_session
|
| 20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
def assignOrder(self):
|
| 22 |
with transaction.atomic():
|
| 23 |
orders_without_tester = list(Orden.objects.select_for_update().filter(
|
|
|
|
| 44 |
return create
|
| 45 |
return self.order_to_assign
|
| 46 |
|
| 47 |
+
def isEndedSession(self):
|
| 48 |
try:
|
| 49 |
participation = Participacion.objects.get(
|
| 50 |
catador=self.tester, tecnica=self.session.tecnica)
|
tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_escalas_controller.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import render, redirect
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import Catador, SesionSensorial, Orden
|
| 5 |
+
from tecnicas.controllers import ParticipacionController
|
| 6 |
+
from .init_session_controller import InitSessionController
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class InitSessionEscalasController(InitSessionController):
|
| 10 |
+
tester: Catador
|
| 11 |
+
session: SesionSensorial
|
| 12 |
+
order: Orden | dict
|
| 13 |
+
|
| 14 |
+
def __init__(self, sensorial_session, user_tester):
|
| 15 |
+
super().__init__(sensorial_session, user_tester)
|
| 16 |
+
self.current_direction = "tecnicas/forms_tester/init_scales_test.html"
|
| 17 |
+
self.escalas_direction = "cata_system:session_convencional"
|
| 18 |
+
self.cata_direction = "cata_system:session_cata"
|
| 19 |
+
|
| 20 |
+
def controllGet(self, request: HttpRequest):
|
| 21 |
+
context = {
|
| 22 |
+
"session": self.session,
|
| 23 |
+
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
order = self.checkAndAssignOrder()
|
| 27 |
+
if isinstance(order, dict):
|
| 28 |
+
context["error"] = order["error"]
|
| 29 |
+
return render(request, self.current_direction, context)
|
| 30 |
+
|
| 31 |
+
is_end = self.isEndedSession()
|
| 32 |
+
|
| 33 |
+
request.session["id_order"] = order.id
|
| 34 |
+
context["has_ended"] = is_end
|
| 35 |
+
|
| 36 |
+
if is_end:
|
| 37 |
+
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 38 |
+
|
| 39 |
+
if "error" in request.GET:
|
| 40 |
+
context["error"] = request.GET["error"]
|
| 41 |
+
|
| 42 |
+
return render(request, self.current_direction, context)
|
| 43 |
+
|
| 44 |
+
def controllPost(self, request: HttpRequest):
|
| 45 |
+
context = {
|
| 46 |
+
"session": self.session,
|
| 47 |
+
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
if request.POST["action"] == "start_posting":
|
| 51 |
+
parameters = {
|
| 52 |
+
"code_sesion": self.session.codigo_sesion
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
is_end = self.isEndedSession()
|
| 56 |
+
if is_end:
|
| 57 |
+
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 58 |
+
return render(request, self.current_direction, context)
|
| 59 |
+
|
| 60 |
+
update_participation = ParticipacionController.enterSession(
|
| 61 |
+
tester=request.user.user_catador, session=self.session)
|
| 62 |
+
if isinstance(update_participation, dict):
|
| 63 |
+
context["error"] = update_participation["error"]
|
| 64 |
+
return render(request, self.current_direction, context)
|
| 65 |
+
|
| 66 |
+
request.session["id_participation"] = update_participation.id
|
| 67 |
+
|
| 68 |
+
if self.session.tecnica.tipo_tecnica.nombre_tecnica == "cata":
|
| 69 |
+
return redirect(reverse(self.cata_direction, kwargs=parameters))
|
| 70 |
+
|
| 71 |
+
return redirect(reverse(self.escalas_direction, kwargs=parameters))
|
| 72 |
+
|
| 73 |
+
elif request.POST["action"] == "exit_session":
|
| 74 |
+
response = ParticipacionController.outSession(
|
| 75 |
+
tester=request.user.user_catador, session=self.session)
|
| 76 |
+
if isinstance(response, dict):
|
| 77 |
+
context["error"] = response["error"]
|
| 78 |
+
return render(request, self.current_direction, context)
|
| 79 |
+
|
| 80 |
+
else:
|
| 81 |
+
context["error"] = "Acción sin especificar"
|
| 82 |
+
return render(request, self.current_direction, context)
|
tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_napping_controller.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import render, redirect
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import Participacion, TecnicaModalidad
|
| 5 |
+
from tecnicas.controllers import ParticipacionController
|
| 6 |
+
from .init_session_controller import InitSessionController
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class InitSessionNappingController(InitSessionController):
|
| 10 |
+
def __init__(self, sensorial_session, user_tester):
|
| 11 |
+
super().__init__(sensorial_session, user_tester)
|
| 12 |
+
self.current_direction = "tecnicas/forms_tester/init_test_napping.html"
|
| 13 |
+
self.napping_direction = "cata_system:session_napping"
|
| 14 |
+
|
| 15 |
+
def controllGet(self, request: HttpRequest):
|
| 16 |
+
self.context = {
|
| 17 |
+
"session": self.session,
|
| 18 |
+
"type_technique": "napping",
|
| 19 |
+
"has_ended": self.isEndedSession()
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
self.setStatusSession()
|
| 23 |
+
|
| 24 |
+
if "error" in request.GET:
|
| 25 |
+
self.context["error"] = request.GET["error"]
|
| 26 |
+
|
| 27 |
+
return render(request, self.current_direction, self.context)
|
| 28 |
+
|
| 29 |
+
def isEndedSession(self):
|
| 30 |
+
return Participacion.objects.get(
|
| 31 |
+
tecnica=self.session.tecnica, catador=self.tester).finalizado
|
| 32 |
+
|
| 33 |
+
def controllPost(self, request: HttpRequest):
|
| 34 |
+
context = {
|
| 35 |
+
"session": self.session,
|
| 36 |
+
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
use_action = request.POST["action"]
|
| 40 |
+
|
| 41 |
+
if use_action == "start_posting":
|
| 42 |
+
parameters = {
|
| 43 |
+
"code_sesion": self.session.codigo_sesion
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
is_end = self.isEndedSession()
|
| 47 |
+
if is_end:
|
| 48 |
+
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 49 |
+
return render(request, self.current_direction, context)
|
| 50 |
+
|
| 51 |
+
update_participation = ParticipacionController.enterSession(
|
| 52 |
+
tester=request.user.user_catador, session=self.session)
|
| 53 |
+
|
| 54 |
+
if isinstance(update_participation, dict):
|
| 55 |
+
context["error"] = update_participation["error"]
|
| 56 |
+
return render(request, self.current_direction, context)
|
| 57 |
+
|
| 58 |
+
request.session["id_participation"] = update_participation.id
|
| 59 |
+
|
| 60 |
+
return redirect(reverse(self.napping_direction, kwargs=parameters))
|
| 61 |
+
|
| 62 |
+
elif use_action == "exit_session":
|
| 63 |
+
response = ParticipacionController.outSession(
|
| 64 |
+
tester=request.user.user_catador, session=self.session)
|
| 65 |
+
if isinstance(response, dict):
|
| 66 |
+
context["error"] = response["error"]
|
| 67 |
+
return render(request, self.current_direction, context)
|
| 68 |
+
|
| 69 |
+
else:
|
| 70 |
+
context["error"] = "Acción sin especificar"
|
| 71 |
+
return render(request, self.current_direction, context)
|
| 72 |
+
|
| 73 |
+
def setStatusSession(self):
|
| 74 |
+
technique_mode = TecnicaModalidad.objects.get(
|
| 75 |
+
tecnica=self.session.tecnica).modalidad.nombre
|
| 76 |
+
|
| 77 |
+
if technique_mode == "sin modalidad":
|
| 78 |
+
self.context["status"] = "La sesión usa Napping"
|
| 79 |
+
else:
|
| 80 |
+
self.context["status"] = f"La sesión usa Napping con modalidad {technique_mode}"
|
tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_pf_controller.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import render, redirect
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import Participacion, Producto, Dato, ListaPalabras
|
| 5 |
+
from tecnicas.controllers import ParticipacionController
|
| 6 |
+
from .init_session_controller import InitSessionController
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class InitSessionPFController(InitSessionController):
|
| 10 |
+
def __init__(self, sensorial_session, user_tester):
|
| 11 |
+
super().__init__(sensorial_session, user_tester)
|
| 12 |
+
self.current_direction = "tecnicas/forms_tester/init_pf_test.html"
|
| 13 |
+
self.pf_direction = "cata_system:session_pf"
|
| 14 |
+
|
| 15 |
+
def controllGet(self, request: HttpRequest):
|
| 16 |
+
context = {
|
| 17 |
+
"session": self.session,
|
| 18 |
+
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
(is_end, message, rep_show) = self.isEndedSession()
|
| 22 |
+
|
| 23 |
+
context["has_ended"] = is_end
|
| 24 |
+
context["activity"] = message
|
| 25 |
+
context["repetition"] = rep_show
|
| 26 |
+
|
| 27 |
+
if "error" in request.GET:
|
| 28 |
+
context["error"] = request.GET["error"]
|
| 29 |
+
|
| 30 |
+
return render(request, self.current_direction, context)
|
| 31 |
+
|
| 32 |
+
def controllPost(self, request: HttpRequest):
|
| 33 |
+
context = {
|
| 34 |
+
"session": self.session,
|
| 35 |
+
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
action = request.POST["action"]
|
| 39 |
+
|
| 40 |
+
if action == "start_posting":
|
| 41 |
+
parameters = {
|
| 42 |
+
"code_sesion": self.session.codigo_sesion
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
(is_end, message, rep_show) = self.isEndedSession()
|
| 46 |
+
if is_end:
|
| 47 |
+
return self.controllGet(request)
|
| 48 |
+
|
| 49 |
+
update_participation = ParticipacionController.enterSession(
|
| 50 |
+
tester=request.user.user_catador, session=self.session)
|
| 51 |
+
if isinstance(update_participation, dict):
|
| 52 |
+
context["error"] = update_participation["error"]
|
| 53 |
+
return render(request, self.current_direction, context)
|
| 54 |
+
|
| 55 |
+
request.session["id_participation"] = update_participation.id
|
| 56 |
+
|
| 57 |
+
return redirect(reverse(self.pf_direction, kwargs=parameters))
|
| 58 |
+
|
| 59 |
+
elif action == "exit_session":
|
| 60 |
+
response = ParticipacionController.outSession(
|
| 61 |
+
tester=request.user.user_catador, session=self.session)
|
| 62 |
+
if isinstance(response, dict):
|
| 63 |
+
context["error"] = response["error"]
|
| 64 |
+
return self.controllGet(request)
|
| 65 |
+
|
| 66 |
+
else:
|
| 67 |
+
context["error"] = "Acción sin especificar"
|
| 68 |
+
return render(request, self.current_direction, context)
|
| 69 |
+
|
| 70 |
+
def isEndedSession(self) -> tuple[bool, str, int]:
|
| 71 |
+
rep = self.session.tecnica.repeticion
|
| 72 |
+
|
| 73 |
+
is_end = False
|
| 74 |
+
message = ""
|
| 75 |
+
repetitiom_show = 0
|
| 76 |
+
|
| 77 |
+
if rep == 1:
|
| 78 |
+
is_end = self.endedSessionMakeList()
|
| 79 |
+
message = "Ya has creado la Lista de palabras inicial" if is_end else "Debes crear tu lista de palabras inicial"
|
| 80 |
+
repetitiom_show = 0
|
| 81 |
+
elif rep == 2:
|
| 82 |
+
is_end = self.endedSessionMakeList()
|
| 83 |
+
message = "Ya has creado la Lista de palabras final" if is_end else "Debes crear tu lista de palabras final"
|
| 84 |
+
repetitiom_show = 0
|
| 85 |
+
elif rep >= 3:
|
| 86 |
+
is_end = self.endedSessionRepetition()
|
| 87 |
+
message = "Has finalizado con el proceso de calificación" if is_end else "Debe hacer tu proceso de calificación"
|
| 88 |
+
repetitiom_show = rep - 2
|
| 89 |
+
else:
|
| 90 |
+
message = "Parece que la repetición es cero, no es posible hacer algo ahora mismo"
|
| 91 |
+
|
| 92 |
+
return (is_end, message, repetitiom_show)
|
| 93 |
+
|
| 94 |
+
def endedSessionMakeList(self):
|
| 95 |
+
try:
|
| 96 |
+
return Participacion.objects.get(
|
| 97 |
+
catador=self.tester, tecnica=self.session.tecnica).finalizado
|
| 98 |
+
except Participacion.DoesNotExist:
|
| 99 |
+
print("No se ha encontrado la participación")
|
| 100 |
+
return False
|
| 101 |
+
|
| 102 |
+
def endedSessionRepetition(self):
|
| 103 |
+
try:
|
| 104 |
+
participation = Participacion.objects.get(
|
| 105 |
+
catador=self.tester, tecnica=self.session.tecnica)
|
| 106 |
+
self.session.refresh_from_db()
|
| 107 |
+
|
| 108 |
+
# ////////////////////////////////////////////////////////////// #
|
| 109 |
+
#
|
| 110 |
+
# numero_datos_esperadas = num_productos * num_palabras
|
| 111 |
+
# Si numero_datos_esperadas es igual a numero_datos_actuales en la repetcion R
|
| 112 |
+
# Ha terminado la repeticion
|
| 113 |
+
#
|
| 114 |
+
# ////////////////////////////////////////////////////////////// #
|
| 115 |
+
|
| 116 |
+
if participation.finalizado:
|
| 117 |
+
num_products = Producto.objects.filter(
|
| 118 |
+
id_tecnica=self.session.tecnica).count()
|
| 119 |
+
|
| 120 |
+
num_words = ListaPalabras.objects.get(
|
| 121 |
+
tecnica=self.session.tecnica,
|
| 122 |
+
catador=self.tester,
|
| 123 |
+
es_final=True
|
| 124 |
+
).palabras.all().count()
|
| 125 |
+
|
| 126 |
+
expected_ratings_repetition = num_products * num_words
|
| 127 |
+
|
| 128 |
+
technique = self.session.tecnica
|
| 129 |
+
num_ratings_now = Dato.objects.filter(
|
| 130 |
+
id_calificacion__id_catador=self.tester,
|
| 131 |
+
id_calificacion__id_tecnica=technique,
|
| 132 |
+
id_calificacion__num_repeticion=technique.repeticion
|
| 133 |
+
).count()
|
| 134 |
+
|
| 135 |
+
is_end = num_ratings_now >= expected_ratings_repetition
|
| 136 |
+
|
| 137 |
+
return is_end
|
| 138 |
+
|
| 139 |
+
else:
|
| 140 |
+
return participation.finalizado
|
| 141 |
+
|
| 142 |
+
except Participacion.DoesNotExist:
|
| 143 |
+
print("No se ha encontrado la participación")
|
| 144 |
+
return False
|
tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_rata_controller.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import render
|
| 3 |
+
from .init_session_controller import InitSessionController
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class InitSessionRATAController(InitSessionController):
|
| 7 |
+
def __init__(self, sensorial_session, user_tester):
|
| 8 |
+
super().__init__(sensorial_session, user_tester)
|
| 9 |
+
self.current_direction = "tecnicas/forms_tester/init_scales_test.html"
|
| 10 |
+
|
| 11 |
+
def controllGet(self, request: HttpRequest):
|
| 12 |
+
context = {
|
| 13 |
+
"session": self.session,
|
| 14 |
+
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
is_end = self.isEndedSession()
|
| 18 |
+
|
| 19 |
+
context["has_ended"] = is_end
|
| 20 |
+
|
| 21 |
+
if is_end:
|
| 22 |
+
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 23 |
+
|
| 24 |
+
return render(request, self.current_direction, context)
|
tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_sort_controller.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import render, redirect
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import Participacion
|
| 5 |
+
from tecnicas.controllers import ParticipacionController
|
| 6 |
+
from .init_session_controller import InitSessionController
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class InitSessionSortController(InitSessionController):
|
| 10 |
+
def __init__(self, sensorial_session, user_tester):
|
| 11 |
+
super().__init__(sensorial_session, user_tester)
|
| 12 |
+
self.current_direction = "tecnicas/forms_tester/init_test_sort.html"
|
| 13 |
+
self.sort_direction = "cata_system:session_sort"
|
| 14 |
+
|
| 15 |
+
def controllGet(self, request: HttpRequest, error=""):
|
| 16 |
+
context = {
|
| 17 |
+
"session": self.session,
|
| 18 |
+
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
is_end = self.isEndedSession()
|
| 22 |
+
|
| 23 |
+
context["has_ended"] = is_end
|
| 24 |
+
|
| 25 |
+
if is_end:
|
| 26 |
+
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 27 |
+
|
| 28 |
+
if "error" in request.GET:
|
| 29 |
+
context["error"] = request.GET["error"]
|
| 30 |
+
|
| 31 |
+
return render(request, self.current_direction, context)
|
| 32 |
+
|
| 33 |
+
def isEndedSession(self):
|
| 34 |
+
participation = Participacion.objects.get(
|
| 35 |
+
catador=self.tester, tecnica=self.session.tecnica)
|
| 36 |
+
|
| 37 |
+
return participation.finalizado
|
| 38 |
+
|
| 39 |
+
def controllPost(self, request: HttpRequest):
|
| 40 |
+
context = {
|
| 41 |
+
"session": self.session,
|
| 42 |
+
"type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
use_action = request.POST["action"]
|
| 46 |
+
|
| 47 |
+
if use_action == "start_posting":
|
| 48 |
+
parameters = {
|
| 49 |
+
"code_sesion": self.session.codigo_sesion
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
is_end = self.isEndedSession()
|
| 53 |
+
if is_end:
|
| 54 |
+
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 55 |
+
return render(request, self.current_direction, context)
|
| 56 |
+
|
| 57 |
+
update_participation = ParticipacionController.enterSession(
|
| 58 |
+
tester=request.user.user_catador, session=self.session)
|
| 59 |
+
|
| 60 |
+
if isinstance(update_participation, dict):
|
| 61 |
+
context["error"] = update_participation["error"]
|
| 62 |
+
return render(request, self.current_direction, context)
|
| 63 |
+
|
| 64 |
+
request.session["id_participation"] = update_participation.id
|
| 65 |
+
|
| 66 |
+
return redirect(reverse(self.sort_direction, kwargs=parameters))
|
| 67 |
+
|
| 68 |
+
elif use_action == "exit_session":
|
| 69 |
+
response = ParticipacionController.outSession(
|
| 70 |
+
tester=request.user.user_catador, session=self.session)
|
| 71 |
+
if isinstance(response, dict):
|
| 72 |
+
context["error"] = response["error"]
|
| 73 |
+
return render(request, self.current_direction, context)
|
| 74 |
+
|
| 75 |
+
else:
|
| 76 |
+
context["error"] = "Acción sin especificar"
|
| 77 |
+
return render(request, self.current_direction, context)
|
tecnicas/controllers/views_controller/sessions_tester/login_session_tester_controller.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
from django.http import HttpRequest
|
| 2 |
from django.shortcuts import render, redirect
|
| 3 |
from django.urls import reverse
|
| 4 |
from django.db import transaction
|
|
@@ -12,6 +12,7 @@ class LoginSessionTesterController():
|
|
| 12 |
taster_participation: Participacion
|
| 13 |
current_direcction = "tecnicas/forms_tester/login_session.html"
|
| 14 |
destinity_direcction = "cata_system:catador_init_session"
|
|
|
|
| 15 |
|
| 16 |
def __init__(self):
|
| 17 |
self.tester = Catador()
|
|
@@ -28,17 +29,18 @@ class LoginSessionTesterController():
|
|
| 28 |
return controller_error("Credenciales inválidas")
|
| 29 |
|
| 30 |
def validateEntryEscalas(self, request=HttpRequest):
|
| 31 |
-
context = {}
|
| 32 |
if not self.session.activo:
|
| 33 |
-
context["error"] = "La sesión no está activa actualmente"
|
| 34 |
-
return render(request, self.current_direcction, context)
|
| 35 |
|
| 36 |
if self.session.tecnica.repeticion == 1:
|
| 37 |
try:
|
| 38 |
self.taster_participation = Participacion.objects.get(
|
| 39 |
tecnica=self.session.tecnica, catador=self.tester)
|
| 40 |
-
context["error"] = "Usted ya esta dentro de la sesión"
|
| 41 |
-
return render(request, self.current_direcction, context)
|
|
|
|
| 42 |
except Participacion.DoesNotExist:
|
| 43 |
with transaction.atomic():
|
| 44 |
code_session = self.session.codigo_sesion
|
|
@@ -50,8 +52,8 @@ class LoginSessionTesterController():
|
|
| 50 |
tecnica=self.session.tecnica).count()
|
| 51 |
|
| 52 |
if current_num_testers >= max_testers:
|
| 53 |
-
context["error"] = "La sesión ha alcanzado el número máximo de catadores"
|
| 54 |
-
return render(request, self.current_direcction, context)
|
| 55 |
|
| 56 |
self.taster_participation = Participacion.objects.create(
|
| 57 |
tecnica=self.session.tecnica,
|
|
@@ -63,21 +65,21 @@ class LoginSessionTesterController():
|
|
| 63 |
}
|
| 64 |
return redirect(reverse(self.destinity_direcction, kwargs=params))
|
| 65 |
else:
|
| 66 |
-
context["error"] = "Ya no es posible ingresar a la sesión"
|
| 67 |
-
return render(request, self.current_direcction, context)
|
| 68 |
|
| 69 |
-
def
|
| 70 |
-
context = {}
|
| 71 |
if not self.session.activo:
|
| 72 |
-
context["error"] = "La sesión no está activa actualmente"
|
| 73 |
-
return render(request, self.current_direcction, context)
|
| 74 |
|
| 75 |
if self.session.tecnica.repeticion <= 1:
|
| 76 |
try:
|
| 77 |
self.taster_participation = Participacion.objects.get(
|
| 78 |
tecnica=self.session.tecnica, catador=self.tester)
|
| 79 |
-
context["error"] = "Usted ya esta dentro de la sesión"
|
| 80 |
-
return render(request, self.current_direcction, context)
|
| 81 |
except Participacion.DoesNotExist:
|
| 82 |
with transaction.atomic():
|
| 83 |
code_session = self.session.codigo_sesion
|
|
@@ -95,5 +97,67 @@ class LoginSessionTesterController():
|
|
| 95 |
}
|
| 96 |
return redirect(reverse(self.destinity_direcction, kwargs=params))
|
| 97 |
else:
|
| 98 |
-
context["error"] = "Imposible acceder a esta sesión"
|
| 99 |
-
return render(request, self.current_direcction, context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
from django.shortcuts import render, redirect
|
| 3 |
from django.urls import reverse
|
| 4 |
from django.db import transaction
|
|
|
|
| 12 |
taster_participation: Participacion
|
| 13 |
current_direcction = "tecnicas/forms_tester/login_session.html"
|
| 14 |
destinity_direcction = "cata_system:catador_init_session"
|
| 15 |
+
context = {}
|
| 16 |
|
| 17 |
def __init__(self):
|
| 18 |
self.tester = Catador()
|
|
|
|
| 29 |
return controller_error("Credenciales inválidas")
|
| 30 |
|
| 31 |
def validateEntryEscalas(self, request=HttpRequest):
|
| 32 |
+
self.context = {}
|
| 33 |
if not self.session.activo:
|
| 34 |
+
self.context["error"] = "La sesión no está activa actualmente"
|
| 35 |
+
return render(request, self.current_direcction, self.context)
|
| 36 |
|
| 37 |
if self.session.tecnica.repeticion == 1:
|
| 38 |
try:
|
| 39 |
self.taster_participation = Participacion.objects.get(
|
| 40 |
tecnica=self.session.tecnica, catador=self.tester)
|
| 41 |
+
self.context["error"] = "Usted ya esta dentro de la sesión"
|
| 42 |
+
return render(request, self.current_direcction, self.context)
|
| 43 |
+
|
| 44 |
except Participacion.DoesNotExist:
|
| 45 |
with transaction.atomic():
|
| 46 |
code_session = self.session.codigo_sesion
|
|
|
|
| 52 |
tecnica=self.session.tecnica).count()
|
| 53 |
|
| 54 |
if current_num_testers >= max_testers:
|
| 55 |
+
self.context["error"] = "La sesión ha alcanzado el número máximo de catadores"
|
| 56 |
+
return render(request, self.current_direcction, self.context)
|
| 57 |
|
| 58 |
self.taster_participation = Participacion.objects.create(
|
| 59 |
tecnica=self.session.tecnica,
|
|
|
|
| 65 |
}
|
| 66 |
return redirect(reverse(self.destinity_direcction, kwargs=params))
|
| 67 |
else:
|
| 68 |
+
self.context["error"] = "Ya no es posible ingresar a la sesión"
|
| 69 |
+
return render(request, self.current_direcction, self.context)
|
| 70 |
|
| 71 |
+
def validateEntryRataCata(self, request: HttpRequest):
|
| 72 |
+
self.context = {}
|
| 73 |
if not self.session.activo:
|
| 74 |
+
self.context["error"] = "La sesión no está activa actualmente"
|
| 75 |
+
return render(request, self.current_direcction, self.context)
|
| 76 |
|
| 77 |
if self.session.tecnica.repeticion <= 1:
|
| 78 |
try:
|
| 79 |
self.taster_participation = Participacion.objects.get(
|
| 80 |
tecnica=self.session.tecnica, catador=self.tester)
|
| 81 |
+
self.context["error"] = "Usted ya esta dentro de la sesión"
|
| 82 |
+
return render(request, self.current_direcction, self.context)
|
| 83 |
except Participacion.DoesNotExist:
|
| 84 |
with transaction.atomic():
|
| 85 |
code_session = self.session.codigo_sesion
|
|
|
|
| 97 |
}
|
| 98 |
return redirect(reverse(self.destinity_direcction, kwargs=params))
|
| 99 |
else:
|
| 100 |
+
self.context["error"] = "Imposible acceder a esta sesión"
|
| 101 |
+
return render(request, self.current_direcction, self.context)
|
| 102 |
+
|
| 103 |
+
def validateEntryLimitTesters(self, request: HttpRequest):
|
| 104 |
+
self.context = {}
|
| 105 |
+
if not self.session.activo:
|
| 106 |
+
self.context["error"] = "La sesión no está activa actualmente"
|
| 107 |
+
return render(request, self.current_direcction, self.context)
|
| 108 |
+
|
| 109 |
+
if self.session.tecnica.repeticion == 1:
|
| 110 |
+
return self.entrySessionLimitTesters(request)
|
| 111 |
+
|
| 112 |
+
else:
|
| 113 |
+
self.context["error"] = "Ya no es posible ingresar a la sesión"
|
| 114 |
+
return render(request, self.current_direcction, self.context)
|
| 115 |
+
|
| 116 |
+
def validateEntryNapping(self, request: HttpRequest):
|
| 117 |
+
self.context = {}
|
| 118 |
+
if not self.session.activo:
|
| 119 |
+
self.context["error"] = "La sesión no está activa actualmente"
|
| 120 |
+
return render(request, self.current_direcction, self.context)
|
| 121 |
+
|
| 122 |
+
if self.session.tecnica.repeticion == 0:
|
| 123 |
+
return self.entrySessionLimitTesters(request)
|
| 124 |
+
|
| 125 |
+
else:
|
| 126 |
+
self.context["error"] = "Ya no es posible ingresar a la sesión"
|
| 127 |
+
return render(request, self.current_direcction, self.context)
|
| 128 |
+
|
| 129 |
+
def entrySessionLimitTesters(self, request: HttpRequest):
|
| 130 |
+
try:
|
| 131 |
+
self.taster_participation = Participacion.objects.get(
|
| 132 |
+
tecnica=self.session.tecnica, catador=self.tester)
|
| 133 |
+
self.context["error"] = "Usted ya esta dentro de la sesión"
|
| 134 |
+
return render(request, self.current_direcction, self.context)
|
| 135 |
+
|
| 136 |
+
except Participacion.DoesNotExist:
|
| 137 |
+
try:
|
| 138 |
+
with transaction.atomic():
|
| 139 |
+
code_session = self.session.codigo_sesion
|
| 140 |
+
self.session = SesionSensorial.objects.select_for_update().get(
|
| 141 |
+
codigo_sesion=code_session)
|
| 142 |
+
|
| 143 |
+
max_testers = self.session.tecnica.limite_catadores
|
| 144 |
+
current_num_testers = Participacion.objects.filter(
|
| 145 |
+
tecnica=self.session.tecnica).count()
|
| 146 |
+
|
| 147 |
+
if current_num_testers >= max_testers:
|
| 148 |
+
raise ValueError(
|
| 149 |
+
"La sesión ha alcanzado el número máximo de catadores")
|
| 150 |
+
|
| 151 |
+
self.taster_participation = Participacion.objects.create(
|
| 152 |
+
tecnica=self.session.tecnica,
|
| 153 |
+
catador=self.tester,
|
| 154 |
+
finalizado=False
|
| 155 |
+
)
|
| 156 |
+
params = {
|
| 157 |
+
"code_sesion": self.session.codigo_sesion
|
| 158 |
+
}
|
| 159 |
+
return redirect(reverse(self.destinity_direcction, kwargs=params))
|
| 160 |
+
|
| 161 |
+
except ValueError as e:
|
| 162 |
+
self.context["error"] = str(e)
|
| 163 |
+
return render(request, self.current_direcction, self.context)
|
tecnicas/controllers/views_controller/sessions_tester/tests_forms/general_test_controller.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import redirect, render
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import SesionSensorial, Catador, Participacion
|
| 5 |
+
from tecnicas.controllers import ParticipacionController
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class GenetalTestController():
|
| 9 |
+
previus_directory = "cata_system:catador_init_session"
|
| 10 |
+
context = {}
|
| 11 |
+
current_directory: str
|
| 12 |
+
|
| 13 |
+
def __init__(self, sensorial_session: SesionSensorial, user_tester: Catador):
|
| 14 |
+
self.tester = user_tester
|
| 15 |
+
self.session = sensorial_session
|
| 16 |
+
|
| 17 |
+
def controllPost(self, request: HttpRequest):
|
| 18 |
+
action = request.POST["action"]
|
| 19 |
+
|
| 20 |
+
if action == "finish_session":
|
| 21 |
+
self.participation = Participacion.objects.get(
|
| 22 |
+
tecnica=self.session.tecnica, catador=request.user.user_catador)
|
| 23 |
+
ParticipacionController.finishSession(self.participation)
|
| 24 |
+
params = {"code_sesion": self.session.codigo_sesion}
|
| 25 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 26 |
+
|
| 27 |
+
else:
|
| 28 |
+
return self.controllGet(request, error="Acción no permitida")
|
tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_cata_controller.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import redirect, render
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import Producto, Participacion, Palabra, Calificacion
|
| 5 |
+
from tecnicas.controllers import PalabrasController, ParticipacionController
|
| 6 |
+
from .general_test_controller import GenetalTestController
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class TestCataController(GenetalTestController):
|
| 10 |
+
def __init__(self, sensorial_session, user_tester):
|
| 11 |
+
super().__init__(sensorial_session, user_tester)
|
| 12 |
+
self.current_directory = "tecnicas/forms_tester/test_cata.html"
|
| 13 |
+
|
| 14 |
+
def controllGet(self, request: HttpRequest):
|
| 15 |
+
technique = self.session.tecnica
|
| 16 |
+
self.participation = Participacion.objects.get(
|
| 17 |
+
tecnica=technique, catador=request.user.user_catador)
|
| 18 |
+
|
| 19 |
+
self.context["session"] = self.session
|
| 20 |
+
|
| 21 |
+
products_in_technique = Producto.objects.filter(id_tecnica=technique)
|
| 22 |
+
|
| 23 |
+
words = PalabrasController.getWordsInTechnique(technique=technique)
|
| 24 |
+
|
| 25 |
+
use_product: Producto = None
|
| 26 |
+
use_words: list[Palabra] = None
|
| 27 |
+
|
| 28 |
+
# Revisamos el producto que le falten calificaciones
|
| 29 |
+
for current_product in products_in_technique:
|
| 30 |
+
try:
|
| 31 |
+
rating = Calificacion.objects.get(
|
| 32 |
+
num_repeticion=technique.repeticion,
|
| 33 |
+
id_producto=current_product,
|
| 34 |
+
id_tecnica=technique,
|
| 35 |
+
id_catador=self.tester
|
| 36 |
+
)
|
| 37 |
+
except Calificacion.DoesNotExist:
|
| 38 |
+
# Si no hay calificacion mandamos el producto actual y todas la palabras
|
| 39 |
+
use_product = current_product
|
| 40 |
+
use_words = words
|
| 41 |
+
break
|
| 42 |
+
|
| 43 |
+
# Si no hay producto que falta por calificar finalizar sesion para el Catador
|
| 44 |
+
if not use_product:
|
| 45 |
+
updated_participation = ParticipacionController.finishSession(
|
| 46 |
+
self.participation)
|
| 47 |
+
params = {
|
| 48 |
+
"code_sesion": self.session.codigo_sesion
|
| 49 |
+
}
|
| 50 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 51 |
+
|
| 52 |
+
self.context["product"] = use_product
|
| 53 |
+
self.context["words"] = use_words
|
| 54 |
+
|
| 55 |
+
return render(request, self.current_directory, self.context)
|
tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_napping_controller.py
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import redirect, render
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from django.db.models import F
|
| 5 |
+
from tecnicas.models import Participacion, Producto, TecnicaModalidad, DatoPunto, Calificacion, Modalidad, Palabra, GrupoProducto
|
| 6 |
+
from tecnicas.forms import ListWordsForm
|
| 7 |
+
from tecnicas.utils import noValidTechnique
|
| 8 |
+
from tecnicas.controllers import ParticipacionController
|
| 9 |
+
from .general_test_controller import GenetalTestController
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class TestNappingController(GenetalTestController):
|
| 13 |
+
def __init__(self, sensorial_session, user_tester):
|
| 14 |
+
super().__init__(sensorial_session, user_tester)
|
| 15 |
+
self.napping_test = "tecnicas/forms_tester/test_napping.html"
|
| 16 |
+
self.napping_puf_test = "tecnicas/forms_tester/test_napping_puf.html"
|
| 17 |
+
self.sort_direction = "tecnicas/forms_tester/test_napping_sort.html"
|
| 18 |
+
|
| 19 |
+
def controllGet(self, request: HttpRequest):
|
| 20 |
+
technique = self.session.tecnica
|
| 21 |
+
|
| 22 |
+
self.participation = Participacion.objects.get(
|
| 23 |
+
tecnica=technique, catador=request.user.user_catador)
|
| 24 |
+
|
| 25 |
+
# Comprobar que el Catador no haya finalizado
|
| 26 |
+
if self.participation.finalizado:
|
| 27 |
+
params = {
|
| 28 |
+
"code_sesion": self.session.codigo_sesion
|
| 29 |
+
}
|
| 30 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 31 |
+
|
| 32 |
+
name_mode_activate = TecnicaModalidad.objects.get(
|
| 33 |
+
tecnica=technique).modalidad.nombre
|
| 34 |
+
|
| 35 |
+
if name_mode_activate == "sin modalidad":
|
| 36 |
+
self.context["mode"] = "sin modalidad"
|
| 37 |
+
return self.nappingTest(request)
|
| 38 |
+
|
| 39 |
+
if name_mode_activate == "perfil ultra flash":
|
| 40 |
+
self.context["mode"] = "perfil ultra flash"
|
| 41 |
+
return self.nappingPufTest(request)
|
| 42 |
+
|
| 43 |
+
if name_mode_activate == "sorting":
|
| 44 |
+
self.context["mode"] = "sorting"
|
| 45 |
+
return self.nappingSort(request)
|
| 46 |
+
|
| 47 |
+
else:
|
| 48 |
+
return noValidTechnique(
|
| 49 |
+
name_view=self.previus_directory,
|
| 50 |
+
query_params={
|
| 51 |
+
"error": f"Trabajando en la modalidad: {name_mode_activate}"
|
| 52 |
+
},
|
| 53 |
+
params={
|
| 54 |
+
"code_sesion": self.session.codigo_sesion
|
| 55 |
+
}
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
def nappingTest(self, request: HttpRequest):
|
| 59 |
+
self.context["session"] = self.session
|
| 60 |
+
technique = self.session.tecnica
|
| 61 |
+
|
| 62 |
+
products_in_technique = Producto.objects.filter(id_tecnica=technique)
|
| 63 |
+
self.context["products"] = products_in_technique
|
| 64 |
+
|
| 65 |
+
self.setCoordinates()
|
| 66 |
+
|
| 67 |
+
return render(request, self.napping_test, self.context)
|
| 68 |
+
|
| 69 |
+
def nappingPufTest(self, request: HttpRequest):
|
| 70 |
+
maked_previus_napping = TecnicaModalidad.objects.get(
|
| 71 |
+
tecnica=self.session.tecnica)
|
| 72 |
+
|
| 73 |
+
self.context["maked_napping"] = True if maked_previus_napping else False
|
| 74 |
+
self.context["mode"] = "perfil ultra flash"
|
| 75 |
+
self.context["form"] = ListWordsForm()
|
| 76 |
+
|
| 77 |
+
self.context["session"] = self.session
|
| 78 |
+
technique = self.session.tecnica
|
| 79 |
+
products_in_technique = Producto.objects.filter(id_tecnica=technique)
|
| 80 |
+
self.context["products"] = products_in_technique
|
| 81 |
+
self.setCoordinates()
|
| 82 |
+
self.setWords()
|
| 83 |
+
|
| 84 |
+
return render(request, self.napping_puf_test, self.context)
|
| 85 |
+
|
| 86 |
+
def nappingSort(self, request: HttpRequest):
|
| 87 |
+
self.context["session"] = self.session
|
| 88 |
+
technique = self.session.tecnica
|
| 89 |
+
|
| 90 |
+
products_in_technique = Producto.objects.filter(id_tecnica=technique)
|
| 91 |
+
self.context["products"] = products_in_technique
|
| 92 |
+
|
| 93 |
+
self.context["form"] = ListWordsForm()
|
| 94 |
+
self.setCoordinates()
|
| 95 |
+
self.setGroups()
|
| 96 |
+
|
| 97 |
+
return render(request, self.sort_direction, self.context)
|
| 98 |
+
|
| 99 |
+
def setCoordinates(self):
|
| 100 |
+
technique = self.session.tecnica
|
| 101 |
+
|
| 102 |
+
ratings = Calificacion.objects.filter(
|
| 103 |
+
num_repeticion=0,
|
| 104 |
+
id_tecnica=technique,
|
| 105 |
+
id_catador=self.participation.catador
|
| 106 |
+
)
|
| 107 |
+
|
| 108 |
+
data_points = DatoPunto.objects.filter(
|
| 109 |
+
calificacion__in=ratings
|
| 110 |
+
).values(
|
| 111 |
+
code=F("calificacion__id_producto__codigoProducto"),
|
| 112 |
+
px=F("x"),
|
| 113 |
+
py=F("y"),
|
| 114 |
+
id_product=F("calificacion__id_producto__id")
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
self.context["data_points"] = list(data_points)
|
| 118 |
+
|
| 119 |
+
def setGroups(self):
|
| 120 |
+
technique = self.session.tecnica
|
| 121 |
+
|
| 122 |
+
# Get all product groups for this tester
|
| 123 |
+
grupos_producto = GrupoProducto.objects.filter(
|
| 124 |
+
tecnica=technique,
|
| 125 |
+
catador=self.participation.catador
|
| 126 |
+
).prefetch_related('productos', 'palabras')
|
| 127 |
+
|
| 128 |
+
groups = []
|
| 129 |
+
for group in grupos_producto:
|
| 130 |
+
# Get products in this group
|
| 131 |
+
products_list = []
|
| 132 |
+
for product in group.productos.all():
|
| 133 |
+
products_list.append({
|
| 134 |
+
'id': product.id,
|
| 135 |
+
'codigoProducto': product.codigoProducto
|
| 136 |
+
})
|
| 137 |
+
|
| 138 |
+
# Get words for this group
|
| 139 |
+
words_list = list(group.palabras.values_list(
|
| 140 |
+
'nombre_palabra', flat=True))
|
| 141 |
+
|
| 142 |
+
groups.append({
|
| 143 |
+
'id': group.id,
|
| 144 |
+
'products': products_list,
|
| 145 |
+
'words': words_list
|
| 146 |
+
})
|
| 147 |
+
|
| 148 |
+
self.context["groups"] = groups
|
| 149 |
+
|
| 150 |
+
def setWords(self):
|
| 151 |
+
technique = self.session.tecnica
|
| 152 |
+
|
| 153 |
+
ratings = Calificacion.objects.filter(
|
| 154 |
+
num_repeticion=0,
|
| 155 |
+
id_tecnica=technique,
|
| 156 |
+
id_catador=self.participation.catador
|
| 157 |
+
).prefetch_related('palabras', 'id_producto')
|
| 158 |
+
|
| 159 |
+
words_by_product = {}
|
| 160 |
+
for rating in ratings:
|
| 161 |
+
product_code = rating.id_producto.codigoProducto
|
| 162 |
+
words_list = list(rating.palabras.values_list(
|
| 163 |
+
'nombre_palabra', flat=True))
|
| 164 |
+
if words_list:
|
| 165 |
+
words_by_product[product_code] = words_list
|
| 166 |
+
|
| 167 |
+
self.context["words_by_product"] = words_by_product
|
| 168 |
+
|
| 169 |
+
def controllPost(self, request: HttpRequest):
|
| 170 |
+
action = request.POST.get("action")
|
| 171 |
+
|
| 172 |
+
if action == "finish_session":
|
| 173 |
+
# Get technique and mode
|
| 174 |
+
technique = self.session.tecnica
|
| 175 |
+
self.participation = Participacion.objects.get(
|
| 176 |
+
tecnica=technique, catador=request.user.user_catador)
|
| 177 |
+
|
| 178 |
+
name_mode_activate = TecnicaModalidad.objects.get(
|
| 179 |
+
tecnica=technique).modalidad.nombre
|
| 180 |
+
|
| 181 |
+
# Validate based on mode
|
| 182 |
+
validation_error = self.validateSessionCompletion(
|
| 183 |
+
technique, name_mode_activate)
|
| 184 |
+
|
| 185 |
+
if validation_error:
|
| 186 |
+
# Return to the appropriate template with error
|
| 187 |
+
if name_mode_activate == "sin modalidad":
|
| 188 |
+
return self.nappingTest(request)
|
| 189 |
+
elif name_mode_activate == "perfil ultra flash":
|
| 190 |
+
return self.nappingPufTest(request)
|
| 191 |
+
|
| 192 |
+
# If validation passes, finish the session
|
| 193 |
+
ParticipacionController.finishSession(self.participation)
|
| 194 |
+
params = {"code_sesion": self.session.codigo_sesion}
|
| 195 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 196 |
+
|
| 197 |
+
# For other actions, call parent's controllPost
|
| 198 |
+
return super().controllPost(request)
|
| 199 |
+
|
| 200 |
+
def validateSessionCompletion(self, technique, mode_name):
|
| 201 |
+
# Get all products in technique
|
| 202 |
+
products = Producto.objects.filter(id_tecnica=technique)
|
| 203 |
+
product_count = products.count()
|
| 204 |
+
|
| 205 |
+
# Get all ratings for this tester
|
| 206 |
+
ratings = Calificacion.objects.filter(
|
| 207 |
+
num_repeticion=0,
|
| 208 |
+
id_tecnica=technique,
|
| 209 |
+
id_catador=self.participation.catador
|
| 210 |
+
).select_related('id_producto').prefetch_related('palabras')
|
| 211 |
+
|
| 212 |
+
# Check if all products have ratings
|
| 213 |
+
if ratings.count() != product_count:
|
| 214 |
+
missing_count = product_count - ratings.count()
|
| 215 |
+
return f"Faltan {missing_count} producto(s) por evaluar."
|
| 216 |
+
|
| 217 |
+
# Check if all ratings have DatoPunto (coordinates)
|
| 218 |
+
ratings_with_points = DatoPunto.objects.filter(
|
| 219 |
+
calificacion__in=ratings
|
| 220 |
+
).values_list('calificacion_id', flat=True)
|
| 221 |
+
|
| 222 |
+
ratings_without_points = ratings.exclude(id__in=ratings_with_points)
|
| 223 |
+
if ratings_without_points.exists():
|
| 224 |
+
missing_products = [
|
| 225 |
+
r.id_producto.codigoProducto for r in ratings_without_points
|
| 226 |
+
]
|
| 227 |
+
return f"Los siguientes productos no tienen coordenadas: {', '.join(missing_products)}"
|
| 228 |
+
|
| 229 |
+
# Additional validation for "perfil ultra flash" mode
|
| 230 |
+
if mode_name == "perfil ultra flash":
|
| 231 |
+
# Check that each rating has at least one word
|
| 232 |
+
ratings_without_words = []
|
| 233 |
+
for rating in ratings:
|
| 234 |
+
if rating.palabras.count() < 1:
|
| 235 |
+
ratings_without_words.append(
|
| 236 |
+
rating.id_producto.codigoProducto)
|
| 237 |
+
|
| 238 |
+
if ratings_without_words:
|
| 239 |
+
return f"Los siguientes productos deben tener al menos 1 palabra: {', '.join(ratings_without_words)}"
|
| 240 |
+
|
| 241 |
+
# All validations passed
|
| 242 |
+
return None
|
tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_pf_controller.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import redirect, render
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import Producto, Participacion, Palabra, Calificacion, ListaPalabras, Dato
|
| 5 |
+
from tecnicas.controllers import ParticipacionController, PalabrasController, EscalaController
|
| 6 |
+
from tecnicas.forms import ListWordsForm
|
| 7 |
+
from .general_test_controller import GenetalTestController
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class TestPFController(GenetalTestController):
|
| 11 |
+
skip_phases = 2
|
| 12 |
+
|
| 13 |
+
def __init__(self, sensorial_session, user_tester):
|
| 14 |
+
super().__init__(sensorial_session, user_tester)
|
| 15 |
+
|
| 16 |
+
def controllGet(self, request: HttpRequest, error=""):
|
| 17 |
+
self.participation = Participacion.objects.get(
|
| 18 |
+
tecnica=self.session.tecnica, catador=request.user.user_catador)
|
| 19 |
+
self.context["session"] = self.session
|
| 20 |
+
|
| 21 |
+
if error:
|
| 22 |
+
self.context["error"] = error
|
| 23 |
+
|
| 24 |
+
rep = self.session.tecnica.repeticion
|
| 25 |
+
|
| 26 |
+
if rep == 1:
|
| 27 |
+
self.current_directory = "tecnicas/forms_tester/test_pf_list_words.html"
|
| 28 |
+
response = self.getFirstPhase(request)
|
| 29 |
+
elif rep == 2:
|
| 30 |
+
self.current_directory = "tecnicas/forms_tester/test_pf_list_words.html"
|
| 31 |
+
response = self.getSecondPhase(request)
|
| 32 |
+
elif rep >= 3:
|
| 33 |
+
self.current_directory = "tecnicas/forms_tester/test_pf_rating_list.html"
|
| 34 |
+
response = self.getRepetitionPhase(request)
|
| 35 |
+
else:
|
| 36 |
+
response = self.getErrorRepetition(request)
|
| 37 |
+
|
| 38 |
+
return response
|
| 39 |
+
|
| 40 |
+
def controllPost(self, request: HttpRequest):
|
| 41 |
+
action = request.POST["action"]
|
| 42 |
+
|
| 43 |
+
if action == "finish_session":
|
| 44 |
+
self.participation = Participacion.objects.get(
|
| 45 |
+
tecnica=self.session.tecnica, catador=request.user.user_catador)
|
| 46 |
+
ParticipacionController.finishSession(self.participation)
|
| 47 |
+
params = {"code_sesion": self.session.codigo_sesion}
|
| 48 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 49 |
+
|
| 50 |
+
else:
|
| 51 |
+
return self.controllGet(request, error="Acción no permitida")
|
| 52 |
+
|
| 53 |
+
def getFirstPhase(self, request: HttpRequest):
|
| 54 |
+
self.participation.refresh_from_db()
|
| 55 |
+
|
| 56 |
+
if self.participation.finalizado:
|
| 57 |
+
params = {
|
| 58 |
+
"code_sesion": self.session.codigo_sesion
|
| 59 |
+
}
|
| 60 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 61 |
+
|
| 62 |
+
self.context["form"] = ListWordsForm()
|
| 63 |
+
self.context["initial_phase"] = True
|
| 64 |
+
|
| 65 |
+
try:
|
| 66 |
+
tester_list = ListaPalabras.objects.get(
|
| 67 |
+
tecnica=self.session.tecnica,
|
| 68 |
+
catador=request.user.user_catador,
|
| 69 |
+
es_final=False
|
| 70 |
+
)
|
| 71 |
+
list_words = list(tester_list.palabras.all())
|
| 72 |
+
self.context["words"] = list_words
|
| 73 |
+
except ListaPalabras.DoesNotExist:
|
| 74 |
+
self.context["words"] = []
|
| 75 |
+
|
| 76 |
+
return render(request, self.current_directory, self.context)
|
| 77 |
+
|
| 78 |
+
def getSecondPhase(self, request: HttpRequest):
|
| 79 |
+
self.participation.refresh_from_db()
|
| 80 |
+
|
| 81 |
+
if self.participation.finalizado:
|
| 82 |
+
params = {
|
| 83 |
+
"code_sesion": self.session.codigo_sesion
|
| 84 |
+
}
|
| 85 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 86 |
+
|
| 87 |
+
try:
|
| 88 |
+
tester_list = ListaPalabras.objects.get(
|
| 89 |
+
tecnica=self.session.tecnica,
|
| 90 |
+
catador=request.user.user_catador,
|
| 91 |
+
es_final=True
|
| 92 |
+
)
|
| 93 |
+
except ListaPalabras.DoesNotExist:
|
| 94 |
+
tester_list = ListaPalabras.objects.get(
|
| 95 |
+
tecnica=self.session.tecnica,
|
| 96 |
+
catador=request.user.user_catador,
|
| 97 |
+
es_final=False
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
list_words = list(tester_list.palabras.all())
|
| 101 |
+
|
| 102 |
+
self.context["form"] = ListWordsForm()
|
| 103 |
+
self.context["initial_phase"] = False
|
| 104 |
+
self.context["words"] = list_words
|
| 105 |
+
|
| 106 |
+
return render(request, self.current_directory, self.context)
|
| 107 |
+
|
| 108 |
+
def getRepetitionPhase(self, request: HttpRequest):
|
| 109 |
+
'''
|
| 110 |
+
- Obtener todos los productos que se evaluan en la tecnica
|
| 111 |
+
- Obtener todas las palabras de la lista de palabras del catador
|
| 112 |
+
- Para cada palabra, comprobar que el numero de Dato sea igual al numero de Productos
|
| 113 |
+
- Si no hay datos mandar esa palabra por contexto con todos los productos
|
| 114 |
+
- De las palabras que falten tomar la primera y mandarla en el contexto
|
| 115 |
+
- Mandar todos los productos por el contexto
|
| 116 |
+
Nota: Para esta fase no hay necesidad de mandar una escala, la escala se creara en el cliente
|
| 117 |
+
'''
|
| 118 |
+
self.participation.refresh_from_db()
|
| 119 |
+
|
| 120 |
+
if self.participation.finalizado:
|
| 121 |
+
params = {"code_sesion": self.session.codigo_sesion}
|
| 122 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 123 |
+
|
| 124 |
+
technique = self.session.tecnica
|
| 125 |
+
|
| 126 |
+
# Obtener todos los productos que se evaluan en la técnica
|
| 127 |
+
products_in_technique = Producto.objects.filter(id_tecnica=technique)
|
| 128 |
+
|
| 129 |
+
# Obtener todas las palabras de la lista del catador (preferir lista final)
|
| 130 |
+
try:
|
| 131 |
+
words = list(ListaPalabras.objects.get(
|
| 132 |
+
tecnica=self.session.tecnica,
|
| 133 |
+
catador=request.user.user_catador,
|
| 134 |
+
es_final=True
|
| 135 |
+
).palabras.all())
|
| 136 |
+
except ListaPalabras.DoesNotExist:
|
| 137 |
+
words = []
|
| 138 |
+
|
| 139 |
+
use_word: Palabra = None
|
| 140 |
+
|
| 141 |
+
# Revisar que palabra no ha sido calificada en todos los productos
|
| 142 |
+
for word in words:
|
| 143 |
+
current_num_data = Dato.objects.filter(
|
| 144 |
+
id_calificacion__num_repeticion=technique.repeticion,
|
| 145 |
+
id_calificacion__id_tecnica=technique,
|
| 146 |
+
id_calificacion__id_catador=request.user.user_catador,
|
| 147 |
+
id_palabra=word
|
| 148 |
+
).count()
|
| 149 |
+
|
| 150 |
+
if not current_num_data:
|
| 151 |
+
use_word = word
|
| 152 |
+
break
|
| 153 |
+
elif current_num_data < len(products_in_technique):
|
| 154 |
+
self.context["error"] = "Se ha detectado una inconsistencia en los datos que se deben calificar, algunos productos no han sido calificados"
|
| 155 |
+
return render(request, self.current_directory, self.context)
|
| 156 |
+
|
| 157 |
+
if not use_word:
|
| 158 |
+
self.participation = Participacion.objects.get(
|
| 159 |
+
tecnica=self.session.tecnica, catador=request.user.user_catador)
|
| 160 |
+
ParticipacionController.finishSession(self.participation)
|
| 161 |
+
params = {"code_sesion": self.session.codigo_sesion}
|
| 162 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 163 |
+
|
| 164 |
+
self.context["word"] = use_word
|
| 165 |
+
self.context["products"] = products_in_technique
|
| 166 |
+
self.context["repetition"] = technique.repeticion - self.skip_phases
|
| 167 |
+
|
| 168 |
+
return render(request, self.current_directory, self.context)
|
| 169 |
+
|
| 170 |
+
def getErrorRepetition(self, request: HttpRequest):
|
| 171 |
+
params = {
|
| 172 |
+
"code_sesion": self.session.codigo_sesion
|
| 173 |
+
}
|
| 174 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_rata_controller.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import redirect, render
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import Participacion, Producto, Calificacion, Palabra
|
| 5 |
+
from tecnicas.controllers import ParticipacionController, PalabrasController, EscalaController
|
| 6 |
+
from .general_test_controller import GenetalTestController
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class TestRataController(GenetalTestController):
|
| 10 |
+
def __init__(self, sensorial_session, user_tester):
|
| 11 |
+
super().__init__(sensorial_session, user_tester)
|
| 12 |
+
self.current_directory = "tecnicas/forms_tester/test_convencional.html"
|
| 13 |
+
|
| 14 |
+
def controllGet(self, request: HttpRequest):
|
| 15 |
+
technique = self.session.tecnica
|
| 16 |
+
self.participation = Participacion.objects.get(
|
| 17 |
+
tecnica=technique, catador=request.user.user_catador)
|
| 18 |
+
|
| 19 |
+
self.context["session"] = self.session
|
| 20 |
+
|
| 21 |
+
products_in_technique = Producto.objects.filter(id_tecnica=technique)
|
| 22 |
+
|
| 23 |
+
words = PalabrasController.getWordsInTechnique(technique=technique)
|
| 24 |
+
|
| 25 |
+
use_product: Producto = None
|
| 26 |
+
use_words: list[Palabra] = None
|
| 27 |
+
|
| 28 |
+
# Revisamos el producto que le falten calificaciones
|
| 29 |
+
for current_product in products_in_technique:
|
| 30 |
+
try:
|
| 31 |
+
rating = Calificacion.objects.get(
|
| 32 |
+
num_repeticion=technique.repeticion,
|
| 33 |
+
id_producto=current_product,
|
| 34 |
+
id_tecnica=technique,
|
| 35 |
+
id_catador=self.tester
|
| 36 |
+
)
|
| 37 |
+
except Calificacion.DoesNotExist:
|
| 38 |
+
# Si no hay calificacion mandamos el producto actual y todas la palabras
|
| 39 |
+
use_product = current_product
|
| 40 |
+
use_words = words
|
| 41 |
+
break
|
| 42 |
+
|
| 43 |
+
# Obtener los datos asociados para la calificacion para ver que palabras quedan por calificar
|
| 44 |
+
recoreded_data = rating.dato_calificacion.all()
|
| 45 |
+
|
| 46 |
+
if not recoreded_data:
|
| 47 |
+
# Si no hay datos entonces devolver el producto con todas las palabras
|
| 48 |
+
use_product = current_product
|
| 49 |
+
use_words = words
|
| 50 |
+
break
|
| 51 |
+
else:
|
| 52 |
+
words_to_use = PalabrasController.getWordsWithoutData(
|
| 53 |
+
recoreded_data=recoreded_data, words=words)
|
| 54 |
+
|
| 55 |
+
# Si quedan palabras por calificar mandar las palabras con el producto
|
| 56 |
+
if not isinstance(words_to_use, dict) and words_to_use:
|
| 57 |
+
use_product = current_product
|
| 58 |
+
use_words = words_to_use
|
| 59 |
+
break
|
| 60 |
+
|
| 61 |
+
# Si no hay producto que falta por calificar finalizar sesion para el Catador
|
| 62 |
+
if not use_product:
|
| 63 |
+
updated_participation = ParticipacionController.finishSession(
|
| 64 |
+
self.participation)
|
| 65 |
+
params = {
|
| 66 |
+
"code_sesion": self.session.codigo_sesion
|
| 67 |
+
}
|
| 68 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 69 |
+
|
| 70 |
+
self.context["product"] = use_product
|
| 71 |
+
self.context["words"] = use_words
|
| 72 |
+
|
| 73 |
+
# Agregar informacion de la escala
|
| 74 |
+
scale = EscalaController.getScaleByTechnique(technique=technique)
|
| 75 |
+
self.context["scale"] = scale
|
| 76 |
+
self.context["type_scale"] = scale.id_tipo_escala.nombre_escala
|
| 77 |
+
|
| 78 |
+
use_tags = EscalaController.getRelatedTagsInScale(scale=scale)
|
| 79 |
+
self.context["tags"] = use_tags
|
| 80 |
+
|
| 81 |
+
if self.context["type_scale"] == "continua":
|
| 82 |
+
self.context["size_scale"] = {
|
| 83 |
+
"max_size": scale.longitud * 100,
|
| 84 |
+
"middle_size": (scale.longitud * 100)/2
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
return render(request, self.current_directory, self.context)
|