diff --git a/tecnicas/admin.py b/tecnicas/admin.py index d7219cac074557f3e2a7359c6f1a2715c630a8f3..44ab063ed71fdc05d3134bc4ebf6998ace41d14a 100644 --- a/tecnicas/admin.py +++ b/tecnicas/admin.py @@ -14,7 +14,7 @@ from .models import Producto, Participacion from .models import Orden, Posicion -from .models import Dato, ValorDecimal, ValorBooleano, Calificacion, ListaPalabras +from .models import Dato, ValorDecimal, ValorBooleano, Calificacion, ListaPalabras, GrupoProducto # Register your models here. admin.site.register(CategoriaTecnica) @@ -47,3 +47,4 @@ admin.site.register(ValorDecimal) admin.site.register(ValorBooleano) admin.site.register(Calificacion) admin.site.register(ListaPalabras) +admin.site.register(GrupoProducto) diff --git a/tecnicas/controllers/__init__.py b/tecnicas/controllers/__init__.py index 0ee51c10274ba128f39f4ec81cc8d8e959616bf8..9221c48c567fe62e62100d0ac07d5d2c1393c1e2 100644 --- a/tecnicas/controllers/__init__.py +++ b/tecnicas/controllers/__init__.py @@ -16,18 +16,26 @@ from .views_controller.create_session.panel_basic_controller import PanelBasicCo from .views_controller.create_session.panel_tags_controller import PanelTagsController from .views_controller.create_session.panel_codes_controller import PanelCodesController from .views_controller.create_session.panel_words_controller import PanelWordsController -from .views_controller.create_session.panel_create_controller import PanelCreateController -from .views_controller.session_management.details_controller import DetallesController -from .views_controller.session_management.details_escala_controller import DetallesEscalasController -from .views_controller.session_management.details_rata_controller import DetallesRATAController -from .views_controller.session_management.details_cata_controller import DetallesCATAController -from .views_controller.session_management.details_pf_controller import DetallesPFController +from .views_controller.create_session.panels_create.panel_create_escalas_controller import PanelCreateEscalasController +from .views_controller.create_session.panels_create.panel_create_rata_controller import PanelCreateRataController +from .views_controller.create_session.panels_create.panel_create_cata_controller import PanelCreateCataController +from .views_controller.create_session.panels_create.panel_create_pf_controller import PanelCreatePFController +from .views_controller.create_session.panels_create.panel_create_sort_controller import PanelCreateSortController +from .views_controller.create_session.panels_create.panel_create_napping_controller import PanelCreateNappingController -from .views_controller.session_management.monitor_controller import MonitorController -from .views_controller.session_management.monitor_escalas_controller import MonitorEscalasController -from .views_controller.session_management.monitor_rata_controller import MonitorRATAController -from .views_controller.session_management.monitor_pf_controller import MonitorPFController + +from .views_controller.session_management.details.details_controller import DetallesController +from .views_controller.session_management.details.details_escala_controller import DetallesEscalasController +from .views_controller.session_management.details.details_rata_controller import DetallesRATAController +from .views_controller.session_management.details.details_cata_controller import DetallesCATAController +from .views_controller.session_management.details.details_pf_controller import DetallesPFController +from .views_controller.session_management.details.details_sort_controller import DetallesSortController + +from .views_controller.session_management.monitor.monitor_escalas_controller import MonitorEscalasController +from .views_controller.session_management.monitor.monitor_rata_controller import MonitorRATAController +from .views_controller.session_management.monitor.monitor_pf_controller import MonitorPFController +from .views_controller.session_management.monitor.monitor_sort_controller import MonitorSortController from .views_controller.sessions_tester.login_session_tester_controller import LoginSessionTesterController from .views_controller.sessions_tester.list_sessions_tester_controller import ListSessionsTesterController @@ -36,10 +44,12 @@ from .views_controller.sessions_tester.tests_forms.test_scales_controller import from .views_controller.sessions_tester.tests_forms.test_rata_controller import TestRataController from .views_controller.sessions_tester.tests_forms.test_cata_controller import TestCataController from .views_controller.sessions_tester.tests_forms.test_pf_controller import TestPFController +from .views_controller.sessions_tester.tests_forms.test_sort_controller import TestSortController from .views_controller.sessions_tester.init_session.init_session_escalas_controller import InitSessionEscalasController from .views_controller.sessions_tester.init_session.init_session_rata_controller import InitSessionRATAController from .views_controller.sessions_tester.init_session.init_session_pf_controller import InitSessionPFController +from .views_controller.sessions_tester.init_session.init_session_sort_controller import InitSessionSortController from .views_controller.vocabulary_manage.create_vocabulary_controller import CreateVocabularyController from .views_controller.vocabulary_manage.list_vocabulary_controller import ListVocabularyController @@ -48,3 +58,4 @@ from .api_controller.rating_sacales_controller import RatingScalesController from .api_controller.rating_cata_controller import RatingCataController from .api_controller.rating_pf_list_controller import RatingPFListController from .views_controller.tester_list_controller import TesterListController +from .api_controller.rating_sort_controller import RatingSortController diff --git a/tecnicas/controllers/api_controller/rating_sort_controller.py b/tecnicas/controllers/api_controller/rating_sort_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..c7f105bbabb19f9b7ab091596c55a144179301c9 --- /dev/null +++ b/tecnicas/controllers/api_controller/rating_sort_controller.py @@ -0,0 +1,67 @@ +from django.http import JsonResponse, HttpRequest +from django.db import transaction +from tecnicas.models import Participacion, Palabra, GrupoProducto, Producto + + +class RatingSortController(): + def __init__(self): + pass + + @staticmethod + def saveRating(request: HttpRequest, data: list[dict]): + try: + with transaction.atomic(): + participation = Participacion.objects.get( + id=request.session["id_participation"]) + + technique = participation.tecnica + catador = participation.catador + + # Obtener productos de la técnica + technique_products = Producto.objects.filter( + id_tecnica=technique) + technique_product_ids = set(p.id for p in technique_products) + + # Recolectar IDs de productos enviados + sent_product_ids = set() + for group in data: + for product in group["products"]: + sent_product_ids.add(int(product["id"])) + + # Validar que los productos enviados existan en la técnica + if not sent_product_ids.issubset(technique_product_ids): + return JsonResponse({"error": "Productos enviados no pertenecen a la técnica"}) + + # Validar que todos los productos de la técnica estén presentes + if sent_product_ids != technique_product_ids: + return JsonResponse({"error": "Faltan productos por clasificar"}) + + for group in data: + words_data = group["words"] + products_data = group["products"] + + # Crear u obtener palabras + words_objs = [] + for word_name in words_data: + word, created = Palabra.objects.get_or_create(nombre_palabra=word_name) + words_objs.append(word) + + # Crear GrupoProducto + group_product = GrupoProducto.objects.create( + tecnica=technique, + catador=catador + ) + + # Asignar palabras + group_product.palabras.set(words_objs) + + # Asignar productos + product_ids = [p["id"] for p in products_data] + group_product.productos.set(product_ids) + + return JsonResponse({"message": "Valores guardados"}) + except Participacion.DoesNotExist: + return JsonResponse({"error": "Participación no encontrada"}) + except Exception as e: + print(f"Error de calificacion: {e}") + return JsonResponse({"error": "Error al guardar los datos"}) diff --git a/tecnicas/controllers/models_controller/tecnica_controller.py b/tecnicas/controllers/models_controller/tecnica_controller.py index 71265258841e5c3bcbc1843d6438bfa749275262..30403356cf310c8ed2b1bf57790a2d140657eafb 100644 --- a/tecnicas/controllers/models_controller/tecnica_controller.py +++ b/tecnicas/controllers/models_controller/tecnica_controller.py @@ -16,7 +16,7 @@ class TecnicaController(): def setTechniqueFromBasicData(self, basic): self.technique = Tecnica( tipo_tecnica=TipoTecnica.objects.get(nombre_tecnica=basic["name_tecnica"]), - id_estilo=EstiloPalabra.objects.get(id=basic["estilo_palabras"]), + id_estilo=EstiloPalabra.objects.get(nombre_estilo=basic["estilo_palabras"]), repeticiones_max=basic["numero_repeticiones"] or 1, limite_catadores=basic["numero_catadores"], instrucciones=basic["instrucciones"] or "Espere instrucciones del Presentador", diff --git a/tecnicas/controllers/views_controller/create_session/panel_basic_controller.py b/tecnicas/controllers/views_controller/create_session/panel_basic_controller.py index 4b336e39a3e41fba805fe7d1dd38a7ab7ea69549..ff5aef6023629a56c115dff41cc7b6259696c469 100644 --- a/tecnicas/controllers/views_controller/create_session/panel_basic_controller.py +++ b/tecnicas/controllers/views_controller/create_session/panel_basic_controller.py @@ -1,4 +1,4 @@ -from tecnicas.forms import SesionBasicForm, SesionBasicCATAForm, SesionBasicPFForm +from tecnicas.forms import SesionBasicForm, SesionBasicCATAForm, SesionBasicPFForm, SesionBasicSortForm, SesionBasicNappingForm from django.http import HttpRequest from django.shortcuts import redirect, render from django.urls import reverse @@ -10,9 +10,11 @@ class PanelBasicController(): "numero_repeticiones": 1 } - url_panel_basic = "tecnicas/create_sesion/configuracion-panel-basic.html" + url_panel_basic = "tecnicas/create_sesion/conf-panel-basic.html" url_panel_basic_cata = "tecnicas/create_sesion/panel-basic-cata.html" url_panel_basic_pf = "tecnicas/create_sesion/panel-basic-pf.html" + url_panel_basic_sort = "tecnicas/create_sesion/panel-basic-sort.html" + url_panel_basic_napping = "tecnicas/create_sesion/panel-basic-napping.html" url_next_panel_tags = "cata_system:panel_configuracion_tags" url_next_panel_codes = "cata_system:panel_configuracion_codes" @@ -43,7 +45,7 @@ class PanelBasicController(): if form.is_valid(): values = {} for name, value in form.cleaned_data.items(): - if name == "estilo_palabras" or name == "tipo_escala": + if name == "tipo_escala": values[name] = value.id else: values[name] = value @@ -84,7 +86,7 @@ class PanelBasicController(): if form.is_valid(): values = {} for name, value in form.cleaned_data.items(): - if name == "estilo_palabras" or name == "tipo_escala": + if name == "tipo_escala": values[name] = value.id else: values[name] = value @@ -132,10 +134,7 @@ class PanelBasicController(): if form.is_valid(): values = {} for name, value in form.cleaned_data.items(): - if name == "estilo_palabras": - values[name] = value.id - else: - values[name] = value + values[name] = value values["name_tecnica"] = name_tecnica request.session['form_basic'] = values @@ -164,7 +163,6 @@ class PanelBasicController(): form = SesionBasicPFForm(request.POST) if form.is_valid(): - print(form.cleaned_data) values = {} for name, value in form.cleaned_data.items(): values[name] = value @@ -178,3 +176,65 @@ class PanelBasicController(): "form_sesion": form, "error": "Información no valida"}) return response + + @staticmethod + def controllGetSort(request: HttpRequest): + form_sesion = SesionBasicSortForm() + + view_context = { + "form_sesion": form_sesion, + "use_technique": "sort" + } + + return render( + request, PanelBasicController.url_panel_basic_sort, view_context) + + @staticmethod + def controllPostSort(request: HttpRequest, name_tecnica: str): + form = SesionBasicSortForm(request.POST) + + if form.is_valid(): + values = {} + for name, value in form.cleaned_data.items(): + values[name] = value + + values["name_tecnica"] = name_tecnica + request.session['form_basic'] = values + response = redirect( + reverse(PanelBasicController.url_next_panel_codes)) + else: + response = render(request, PanelBasicController.url_panel_basic_sort, { + "form_sesion": form, "error": "Información no valida"}) + + return response + + @staticmethod + def controllGetNapping(request: HttpRequest): + form_sesion = SesionBasicNappingForm() + + view_context = { + "form_sesion": form_sesion, + "use_technique": "napping" + } + + return render( + request, PanelBasicController.url_panel_basic_napping, view_context) + + @staticmethod + def controllPostNapping(request: HttpRequest, name_tecnica: str): + form = SesionBasicNappingForm(request.POST) + + if form.is_valid(): + values = {} + for name, value in form.cleaned_data.items(): + values[name] = value + + values["name_tecnica"] = name_tecnica + request.session['form_basic'] = values + response = redirect( + reverse(PanelBasicController.url_next_panel_codes)) + else: + response = render(request, PanelBasicController.url_panel_basic_napping, { + "form_sesion": form, "error": "Información no valida"}) + + return response diff --git a/tecnicas/controllers/views_controller/create_session/panel_codes_controller.py b/tecnicas/controllers/views_controller/create_session/panel_codes_controller.py index 1bf68ba805beee53dcd109f6b75e851e018513a1..9488be3de2ee34951e292860c64d59ccd920f398 100644 --- a/tecnicas/controllers/views_controller/create_session/panel_codes_controller.py +++ b/tecnicas/controllers/views_controller/create_session/panel_codes_controller.py @@ -7,7 +7,7 @@ import json class PanelCodesController(): - url_current_panel = "tecnicas/create_sesion/configuracion-panel-codes.html" + url_current_panel = "tecnicas/create_sesion/conf-panel-codes.html" url_words = "cata_system:panel_configuracion_words" url_create_session = "cata_system:creando_sesion" @@ -66,7 +66,7 @@ class PanelCodesController(): return render(request, PanelCodesController.url_current_panel, context_codes_form) @staticmethod - def controllGetRATA(request: HttpRequest, data, name_technique: str): + def controllGetWithoutOrders(request: HttpRequest, data, name_technique: str): num_products = data["numero_productos"] codes_products = generarCodigos(num_products) form_codes = CodesForm(codes=codes_products) @@ -80,7 +80,7 @@ class PanelCodesController(): return render(request, PanelCodesController.url_current_panel, context_codes_form) @staticmethod - def controllPostRATA(request: HttpRequest, is_rata=True): + def controllPostWithWords(request: HttpRequest, name_technique: str): codes = [] context_codes_form = {} @@ -92,7 +92,7 @@ class PanelCodesController(): context_codes_form = { "form_codes": form_codes, - "use_technique": "rata" if is_rata else "cata" + "use_technique": name_technique } if form_codes.is_valid(): @@ -117,7 +117,7 @@ class PanelCodesController(): return render(request, PanelCodesController.url_current_panel, context_codes_form) @staticmethod - def controllPostPF(request: HttpRequest): + def controllPostWithoutOrdersWords(request: HttpRequest, name_technique: str): codes = [] context_codes_form = {} @@ -129,7 +129,7 @@ class PanelCodesController(): context_codes_form = { "form_codes": form_codes, - "use_technique": "perfil flash" + "use_technique": name_technique } if form_codes.is_valid(): diff --git a/tecnicas/controllers/views_controller/create_session/panel_create_controller.py b/tecnicas/controllers/views_controller/create_session/panel_create_controller.py deleted file mode 100644 index afa0f59014213ec847e4219fdf576e1b846424e7..0000000000000000000000000000000000000000 --- a/tecnicas/controllers/views_controller/create_session/panel_create_controller.py +++ /dev/null @@ -1,540 +0,0 @@ -from django.http import HttpRequest, JsonResponse -from django.db import transaction -from django.shortcuts import render -from tecnicas.utils import general_error -from tecnicas.models import EsAtributo, EsVocabulario, Vocabulario, Tecnica, TipoTecnica, EstiloPalabra, Producto, Palabra, SesionSensorial, Escala, TipoEscala, EtiquetasEscala -from tecnicas.controllers import TecnicaController, EscalaController, ProductosController, OrdenesController, EstiloPalabrasController, PalabrasController, SesionController -from tecnicas.utils import deleteDataSession - - -class PanelCreateController(): - def __init__(self): - pass - - @staticmethod - def controllGetEscalas(request: HttpRequest): - return render( - request, 'tecnicas/create_sesion/creando_sesion.html') - - @staticmethod - def controllPostEscalas(request: HttpRequest): - if request.POST.get('action') == 'create_session': - if not request.session.get("form_tags") or not request.session.get("form_codes") or not request.session.get("form_words"): - deleteDataSession(request) - return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo") - try: - with transaction.atomic(): - # ////////////////////////////////////////////////////// # - # - # First step: Create technique and scale with their tags # - # - # ////////////////////////////////////////////////////// # - data_basic = request.session["form_basic"] - controllerTechnique = TecnicaController() - controllerTechnique.setTechniqueFromBasicData( - basic=data_basic) - technique = controllerTechnique.saveTechnique() - if not technique: - raise ValueError("Error al guardar la técnica") - - data_scale = { - "id_scale": data_basic["tipo_escala"], - "size": data_basic["tamano_escala"], - "technique": technique - } - - controllerScale = EscalaController(data=data_scale) - - scale = controllerScale.saveScale() - if isinstance(scale, dict): - raise ValueError(scale["error"]) - - dict_tags = request.session["form_tags"] - saved_related_tags = controllerScale.realteTags(dict_tags) - if "error" in saved_related_tags: - raise ValueError(saved_related_tags["error"]) - - # ////////////////////////////////////////////////////////// # - # - # Second step: Create orders, productos and set the position # - # - # ////////////////////////////////////////////////////////// # - data_codes = request.session["form_codes"] - - list_codes_dict = data_codes["product_codes"] - - codes = [] - for product in list_codes_dict: - code = next(iter(product.values())) - codes.append(code) - - controllerProducts = ProductosController( - codes=codes, - technique=technique - ) - - controllerProducts.setProductsNoSave() - saved_prodcuts = controllerProducts.saveProducts() - if isinstance(saved_prodcuts, dict): - raise ValueError(saved_prodcuts["error"]) - - raw_sort_codes = data_codes["sort_codes"] - controllerOrdes = OrdenesController( - raw_orders=raw_sort_codes, - list_products=saved_prodcuts, - technique=technique - ) - - controllerOrdes.setOrdersToSave() - saved_orders = controllerOrdes.saveOrders() - if isinstance(saved_orders, dict): - raise ValueError(saved_orders["error"]) - - seded_positions = controllerOrdes.setPositions() - if isinstance(seded_positions, dict): - raise ValueError(seded_positions["error"]) - - saved_postions = controllerOrdes.savePositions() - if isinstance(saved_postions, dict): - raise ValueError(saved_prodcuts["error"]) - - # /////////////////////////////////////////////////////// # - # - # Third step: Create relations technique with Words Style # - # - # /////////////////////////////////////////////////////// # - style_words = technique.id_estilo.nombre_estilo - if style_words == "atributos": - ids_words = request.session["form_words"] - words_controller = PalabrasController(ids=ids_words) - - words_to_use = words_controller.setWords() - if isinstance(words_to_use, dict): - raise ValueError(words_to_use["error"]) - - style_controller = EstiloPalabrasController( - technique=technique, words=words_to_use) - - instace_style = style_controller.createAndSaveInstaceStyle() - if isinstance(instace_style, dict): - raise ValueError(instace_style["error"]) - - words_using = style_controller.relatedWords() - if isinstance(words_using, dict): - raise ValueError(words_using["error"]) - elif style_words == "vocabulario": - name_vocabulary = request.session["form_words"] - vocabulary = Vocabulario.objects.get( - nombre_vocabulario=name_vocabulary) - - es_vocabulary = EsVocabulario.objects.create( - id_tecnica=technique, - id_vocabulario=vocabulary - ) - else: - raise ValueError("Estilo de palabas no permitido") - - # //////////////////////////////////////////////////////// # - # - # Fourth step: Create session and relat with the technique # - # - # //////////////////////////////////////////////////////// # - session_controller = SesionController( - name_session=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None, - technique=technique, - creator=request.user.user_presentador - ) - - setting_session = session_controller.setSession() - if isinstance(setting_session, dict): - raise ValueError(setting_session["error"]) - - saved_session = session_controller.saveSession() - if isinstance(saved_session, dict): - raise ValueError(saved_session["error"]) - - context = { - "message": "sesión creada", - "data": { - "codigo_sesion": saved_session.codigo_sesion, - "nombre_sesion": saved_session.nombre_sesion - } - } - - # ////////////////////////////////// # - # - # Final step: Delete date in session # - # - # ////////////////////////////////// # - - deleteDataSession(request) - return JsonResponse(context) - except ValueError as e: - return general_error(f"Error: {e}") - else: - return general_error("No se ha establecido acción") - - @staticmethod - def controllPostRATA(request: HttpRequest): - if request.POST.get('action') == 'create_session': - if not request.session.get("form_tags") or not request.session.get("form_codes") or not request.session.get("form_words"): - deleteDataSession(request) - return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo") - try: - with transaction.atomic(): - # ////////////////////////////////////////////////////// # - # - # First step: Create technique and scale with their tags # - # - # ////////////////////////////////////////////////////// # - data_basic = request.session["form_basic"] - data_basic["numero_catadores"] = 0 - data_basic["numero_repeticiones"] = 1 - - technique = Tecnica.objects.create( - tipo_tecnica=TipoTecnica.objects.get( - nombre_tecnica=data_basic["name_tecnica"]), - id_estilo=EstiloPalabra.objects.get( - id=data_basic["estilo_palabras"]), - repeticiones_max=data_basic["numero_repeticiones"] or 1, - limite_catadores=data_basic["numero_catadores"], - instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador", - ) - - if not technique: - raise ValueError("Error al guardar la técnica") - - data_scale = { - "id_scale": data_basic["tipo_escala"], - "size": data_basic["tamano_escala"], - "technique": technique - } - - controllerScale = EscalaController(data=data_scale) - - scale = controllerScale.saveScale() - if isinstance(scale, dict): - raise ValueError(scale["error"]) - - dict_tags = request.session["form_tags"] - saved_related_tags = controllerScale.realteTags(dict_tags) - if "error" in saved_related_tags: - raise ValueError(saved_related_tags["error"]) - - # ////////////////////////////////////////////// # - # - # Second step: Create productos with their codes # - # - # ////////////////////////////////////////////// # - codes = request.session["form_codes"] - - if not codes: - raise ValueError("No hay códigos de productos") - - products_without_save = [] - for code in codes: - product = Producto( - codigoProducto=code, - id_tecnica=technique - ) - products_without_save.append(product) - - Producto.objects.bulk_create(products_without_save) - - # /////////////////////////////////////////////////////// # - # - # Third step: Create relations technique with Words Style # - # - # /////////////////////////////////////////////////////// # - style_words = technique.id_estilo.nombre_estilo - - if style_words == "atributos": - raw_ids_words = request.session["form_words"] - ids_words = [int(id_w) for id_w in raw_ids_words] - - words = Palabra.objects.filter(id__in=ids_words) - - style_atribute = EsAtributo.objects.create( - id_tecnica=technique - ) - - if not style_atribute: - raise ValueError( - "Error al intentar relacionar las palabras con la técnica") - - style_atribute.palabras.set(words) - - elif style_words == "vocabulario": - name_vocabulary = request.session["form_words"] - try: - vocabulary = Vocabulario.objects.get( - nombre_vocabulario=name_vocabulary) - except Vocabulario.DoesNotExist: - raise ValueError("Vocabulario no encontrado") - - es_vocabulary = EsVocabulario.objects.create( - id_tecnica=technique, - id_vocabulario=vocabulary - ) - if not es_vocabulary: - raise ValueError( - "Error al intentar relacionar el vocabulario con la técnica") - - else: - raise ValueError("Estilo de palabas no permitido") - - # //////////////////////////////////////////////////////// # - # - # Fourth step: Create session and relat with the technique # - # - # //////////////////////////////////////////////////////// # - session = SesionSensorial.objects.create( - nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else "", - tecnica=technique, - creadoPor=request.user.user_presentador - ) - - if not session: - raise ValueError("Error al crear sesion sensorial") - - context = { - "message": "sesión creada", - "data": { - "codigo_sesion": session.codigo_sesion, - "nombre_sesion": session.nombre_sesion - } - } - - # ////////////////////////////////// # - # - # Final step: Delete date en session # - # - # ////////////////////////////////// # - - deleteDataSession(request) - return JsonResponse(context) - except ValueError as e: - return general_error(f"Error: {e}") - else: - return general_error("No se ha establecido acción") - - @staticmethod - def controllPostCATA(request: HttpRequest): - if request.POST.get('action') == 'create_session': - if not request.session.get("form_codes") or not request.session.get("form_words"): - deleteDataSession(request) - return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo") - try: - with transaction.atomic(): - # //////////////////////////// # - # - # First step: Create technique # - # - # //////////////////////////// # - data_basic = request.session["form_basic"] - data_basic["numero_catadores"] = 0 - data_basic["numero_repeticiones"] = 1 - - technique = Tecnica.objects.create( - tipo_tecnica=TipoTecnica.objects.get( - nombre_tecnica=data_basic["name_tecnica"]), - id_estilo=EstiloPalabra.objects.get( - id=data_basic["estilo_palabras"]), - repeticiones_max=data_basic["numero_repeticiones"] or 1, - limite_catadores=data_basic["numero_catadores"], - instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador", - ) - - if not technique: - raise ValueError("Error al guardar la técnica") - - # ////////////////////////////////////////////// # - # - # Second step: Create productos with their codes # - # - # ////////////////////////////////////////////// # - codes = request.session["form_codes"] - - if not codes: - raise ValueError("No hay códigos de productos") - - products_without_save = [] - for code in codes: - product = Producto( - codigoProducto=code, - id_tecnica=technique - ) - products_without_save.append(product) - - Producto.objects.bulk_create(products_without_save) - - # /////////////////////////////////////////////////////// # - # - # Third step: Create relations technique with Words Style # - # - # /////////////////////////////////////////////////////// # - style_words = technique.id_estilo.nombre_estilo - - if style_words == "atributos": - raw_ids_words = request.session["form_words"] - ids_words = [int(id_w) for id_w in raw_ids_words] - - words = Palabra.objects.filter(id__in=ids_words) - - style_atribute = EsAtributo.objects.create( - id_tecnica=technique - ) - - if not style_atribute: - raise ValueError( - "Error al intentar relacionar las palabras con la técnica") - - style_atribute.palabras.set(words) - - elif style_words == "vocabulario": - name_vocabulary = request.session["form_words"] - try: - vocabulary = Vocabulario.objects.get( - nombre_vocabulario=name_vocabulary) - except Vocabulario.DoesNotExist: - raise ValueError("Vocabulario no encontrado") - - es_vocabulary = EsVocabulario.objects.create( - id_tecnica=technique, - id_vocabulario=vocabulary - ) - if not es_vocabulary: - raise ValueError( - "Error al intentar relacionar el vocabulario con la técnica") - - else: - raise ValueError("Estilo de palabas no permitido") - - # //////////////////////////////////////////////////////// # - # - # Fourth step: Create session and relat with the technique # - # - # //////////////////////////////////////////////////////// # - session = SesionSensorial.objects.create( - nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None, - tecnica=technique, - creadoPor=request.user.user_presentador - ) - - if not session: - raise ValueError("Error al crear sesion sensorial") - - context = { - "message": "sesión creada", - "data": { - "codigo_sesion": session.codigo_sesion, - "nombre_sesion": session.nombre_sesion - } - } - - # ////////////////////////////////// # - # - # Final step: Delete date en session # - # - # ////////////////////////////////// # - deleteDataSession(request) - return JsonResponse(context) - - except ValueError as e: - return general_error(f"Error: {e}") - else: - return general_error("No se ha establecido acción") - - @staticmethod - def controllPostPF(request: HttpRequest): - if request.POST.get('action') == 'create_session': - if not request.session.get("form_codes"): - deleteDataSession(request) - return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo") - try: - with transaction.atomic(): - # ////////////////////////////////////// # - # - # First step: Create technique and scale # - # - # ////////////////////////////////////// # - data_basic = request.session["form_basic"] - phases_before_reptition = 2 - - technique = Tecnica.objects.create( - tipo_tecnica=TipoTecnica.objects.get( - nombre_tecnica=data_basic["name_tecnica"]), - id_estilo=EstiloPalabra.objects.get( - nombre_estilo="vocabulario"), - repeticiones_max=data_basic["numero_repeticiones"] + phases_before_reptition, - limite_catadores=data_basic["numero_catadores"], - instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Analista", - ) - - if not technique: - raise ValueError("Error al guardar la técnica") - - created_scale = Escala.objects.create( - id_tipo_escala=TipoEscala.objects.get( - nombre_escala="estructurada"), - longitud=data_basic["numero_productos"], - tecnica=technique - ) - - if not created_scale: - raise ValueError("No se ha podido crear la escala") - - # ////////////////////////////////////////////// # - # - # Second step: Create productos with their codes # - # - # ////////////////////////////////////////////// # - codes = request.session["form_codes"] - - if not codes: - raise ValueError("No hay códigos de productos") - - products_without_save = [] - for code in codes: - product = Producto( - codigoProducto=code, - id_tecnica=technique - ) - products_without_save.append(product) - - Producto.objects.bulk_create(products_without_save) - - # /////////////////////////////////////////////////////// # - # - # Third step: Create session and relat with the technique # - # - # /////////////////////////////////////////////////////// # - session = SesionSensorial.objects.create( - nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None, - tecnica=technique, - creadoPor=request.user.user_presentador - ) - - if not session: - raise ValueError("Error al crear sesion sensorial") - - context = { - "message": "sesión creada", - "data": { - "codigo_sesion": session.codigo_sesion, - "nombre_sesion": session.nombre_sesion - } - } - - # ////////////////////////////////// # - # - # Final step: Delete date en session # - # - # ////////////////////////////////// # - deleteDataSession(request) - return JsonResponse(context) - - except ValueError as e: - return general_error(f"Error: {e}") - else: - return general_error("No se ha establecido acción") diff --git a/tecnicas/controllers/views_controller/create_session/panel_tags_controller.py b/tecnicas/controllers/views_controller/create_session/panel_tags_controller.py index 852bd7d245c22894b486e2fd0f5a65e462a8b201..c41da248ea799117732f622804a8918f762de421 100644 --- a/tecnicas/controllers/views_controller/create_session/panel_tags_controller.py +++ b/tecnicas/controllers/views_controller/create_session/panel_tags_controller.py @@ -25,7 +25,7 @@ class PanelTagsController(): "form_new_tag": form_new_etiqueta } - return render(request, "tecnicas/create_sesion/configuracion-panel-tags.html", context_tags) + return render(request, "tecnicas/create_sesion/conf-panel-tags.html", context_tags) @staticmethod def controllPostEscalas(request: HttpRequest, data): @@ -54,7 +54,7 @@ class PanelTagsController(): else: context_tags["error"] = "ha ocurrido un error" response = render( - request, "tecnicas/create_sesion/configuracion-panel-tags.html", context_tags) + request, "tecnicas/create_sesion/conf-panel-tags.html", context_tags) return response diff --git a/tecnicas/controllers/views_controller/create_session/panel_words_controller.py b/tecnicas/controllers/views_controller/create_session/panel_words_controller.py index 92d454c44096a43608ec5fbe936f3d873e99d5ff..d748614782dcac27a93bedb03f1ee355447adea6 100644 --- a/tecnicas/controllers/views_controller/create_session/panel_words_controller.py +++ b/tecnicas/controllers/views_controller/create_session/panel_words_controller.py @@ -7,7 +7,7 @@ import json class PanelWordsController(): - current_url_escalas_atribute = "tecnicas/create_sesion/configuracion-panel-words.html" + current_url_escalas_atribute = "tecnicas/create_sesion/conf-panel-words.html" current_url_escalas_vocabulary = "tecnicas/create_sesion/conf-panel-vocabulary.html" def __init__(self): diff --git a/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_cata_controller.py b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_cata_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..79a6329a92f3a51852a670792a14a9fa778ea687 --- /dev/null +++ b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_cata_controller.py @@ -0,0 +1,137 @@ +from .panel_create_controller import PanelCreateController +from django.http import HttpRequest, JsonResponse +from django.db import transaction +from tecnicas.models import EsVocabulario, Tecnica, TipoTecnica, EstiloPalabra, EsAtributo, Vocabulario, Palabra, SesionSensorial, Producto +from tecnicas.utils import deleteDataSession, general_error + + +class PanelCreateCataController(PanelCreateController): + def __init__(self): + super().__init__() + + @staticmethod + def controllPost(request: HttpRequest): + if request.POST.get('action') == 'create_session': + if not request.session.get("form_codes") or not request.session.get("form_words"): + deleteDataSession(request) + return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo") + try: + with transaction.atomic(): + # //////////////////////////// # + # + # First step: Create technique # + # + # //////////////////////////// # + data_basic = request.session["form_basic"] + data_basic["numero_catadores"] = 0 + data_basic["numero_repeticiones"] = 1 + + technique = Tecnica.objects.create( + tipo_tecnica=TipoTecnica.objects.get( + nombre_tecnica=data_basic["name_tecnica"]), + id_estilo=EstiloPalabra.objects.get( + nombre_estilo=data_basic["estilo_palabras"]), + repeticiones_max=data_basic["numero_repeticiones"] or 1, + limite_catadores=data_basic["numero_catadores"], + instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador", + ) + + if not technique: + raise ValueError("Error al guardar la técnica") + + # ////////////////////////////////////////////// # + # + # Second step: Create productos with their codes # + # + # ////////////////////////////////////////////// # + codes = request.session["form_codes"] + + if not codes: + raise ValueError("No hay códigos de productos") + + products_without_save = [] + for code in codes: + product = Producto( + codigoProducto=code, + id_tecnica=technique + ) + products_without_save.append(product) + + Producto.objects.bulk_create(products_without_save) + + # /////////////////////////////////////////////////////// # + # + # Third step: Create relations technique with Words Style # + # + # /////////////////////////////////////////////////////// # + style_words = technique.id_estilo.nombre_estilo + + if style_words == "atributos": + raw_ids_words = request.session["form_words"] + ids_words = [int(id_w) for id_w in raw_ids_words] + + words = Palabra.objects.filter(id__in=ids_words) + + style_atribute = EsAtributo.objects.create( + id_tecnica=technique + ) + + if not style_atribute: + raise ValueError( + "Error al intentar relacionar las palabras con la técnica") + + style_atribute.palabras.set(words) + + elif style_words == "vocabulario": + name_vocabulary = request.session["form_words"] + try: + vocabulary = Vocabulario.objects.get( + nombre_vocabulario=name_vocabulary) + except Vocabulario.DoesNotExist: + raise ValueError("Vocabulario no encontrado") + + es_vocabulary = EsVocabulario.objects.create( + id_tecnica=technique, + id_vocabulario=vocabulary + ) + if not es_vocabulary: + raise ValueError( + "Error al intentar relacionar el vocabulario con la técnica") + + else: + raise ValueError("Estilo de palabas no permitido") + + # //////////////////////////////////////////////////////// # + # + # Fourth step: Create session and relat with the technique # + # + # //////////////////////////////////////////////////////// # + session = SesionSensorial.objects.create( + nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None, + tecnica=technique, + creadoPor=request.user.user_presentador + ) + + if not session: + raise ValueError("Error al crear sesion sensorial") + + context = { + "message": "sesión creada", + "data": { + "codigo_sesion": session.codigo_sesion, + "nombre_sesion": session.nombre_sesion + } + } + + # ////////////////////////////////// # + # + # Final step: Delete date en session # + # + # ////////////////////////////////// # + deleteDataSession(request) + return JsonResponse(context) + + except ValueError as e: + return general_error(f"Error: {e}") + else: + return general_error("No se ha establecido acción") diff --git a/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_controller.py b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..ea4a8559c91137c4b8a6c6e27f8f1f9293461869 --- /dev/null +++ b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_controller.py @@ -0,0 +1,17 @@ +from django.http import JsonResponse, HttpRequest +from django.shortcuts import render + +class PanelCreateController(): + url_template = 'tecnicas/create_sesion/creating_session.html' + + def __init__(self): + pass + + @staticmethod + def controllGet(request: HttpRequest): + return render( + request, PanelCreateController.url_template) + + @staticmethod + def controllPost(request: HttpRequest): + return JsonResponse({"message": "Método no permitido"}) diff --git a/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_escalas_controller.py b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_escalas_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..727ebde507273373c4746ded1290bde26c3aed81 --- /dev/null +++ b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_escalas_controller.py @@ -0,0 +1,169 @@ +from .panel_create_controller import PanelCreateController +from django.http import HttpRequest, JsonResponse +from django.db import transaction +from tecnicas.controllers import TecnicaController, EscalaController, ProductosController, OrdenesController, PalabrasController, EstiloPalabrasController, SesionController +from tecnicas.models import EsVocabulario, Vocabulario +from tecnicas.utils import deleteDataSession, general_error + + +class PanelCreateEscalasController(PanelCreateController): + def __init__(self): + super().__init__() + + @staticmethod + def controllPost(request: HttpRequest): + if request.POST.get('action') == 'create_session': + if not request.session.get("form_tags") or not request.session.get("form_codes") or not request.session.get("form_words"): + deleteDataSession(request) + return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo") + try: + with transaction.atomic(): + # ////////////////////////////////////////////////////// # + # + # First step: Create technique and scale with their tags # + # + # ////////////////////////////////////////////////////// # + data_basic = request.session["form_basic"] + controllerTechnique = TecnicaController() + controllerTechnique.setTechniqueFromBasicData( + basic=data_basic) + technique = controllerTechnique.saveTechnique() + if not technique: + raise ValueError("Error al guardar la técnica") + + data_scale = { + "id_scale": data_basic["tipo_escala"], + "size": data_basic["tamano_escala"], + "technique": technique + } + + controllerScale = EscalaController(data=data_scale) + + scale = controllerScale.saveScale() + if isinstance(scale, dict): + raise ValueError(scale["error"]) + + dict_tags = request.session["form_tags"] + saved_related_tags = controllerScale.realteTags(dict_tags) + if "error" in saved_related_tags: + raise ValueError(saved_related_tags["error"]) + + # ////////////////////////////////////////////////////////// # + # + # Second step: Create orders, productos and set the position # + # + # ////////////////////////////////////////////////////////// # + data_codes = request.session["form_codes"] + + list_codes_dict = data_codes["product_codes"] + + codes = [] + for product in list_codes_dict: + code = next(iter(product.values())) + codes.append(code) + + controllerProducts = ProductosController( + codes=codes, + technique=technique + ) + + controllerProducts.setProductsNoSave() + saved_prodcuts = controllerProducts.saveProducts() + if isinstance(saved_prodcuts, dict): + raise ValueError(saved_prodcuts["error"]) + + raw_sort_codes = data_codes["sort_codes"] + controllerOrdes = OrdenesController( + raw_orders=raw_sort_codes, + list_products=saved_prodcuts, + technique=technique + ) + + controllerOrdes.setOrdersToSave() + saved_orders = controllerOrdes.saveOrders() + if isinstance(saved_orders, dict): + raise ValueError(saved_orders["error"]) + + seded_positions = controllerOrdes.setPositions() + if isinstance(seded_positions, dict): + raise ValueError(seded_positions["error"]) + + saved_postions = controllerOrdes.savePositions() + if isinstance(saved_postions, dict): + raise ValueError(saved_prodcuts["error"]) + + # /////////////////////////////////////////////////////// # + # + # Third step: Create relations technique with Words Style # + # + # /////////////////////////////////////////////////////// # + style_words = technique.id_estilo.nombre_estilo + if style_words == "atributos": + ids_words = request.session["form_words"] + words_controller = PalabrasController(ids=ids_words) + + words_to_use = words_controller.setWords() + if isinstance(words_to_use, dict): + raise ValueError(words_to_use["error"]) + + style_controller = EstiloPalabrasController( + technique=technique, words=words_to_use) + + instace_style = style_controller.createAndSaveInstaceStyle() + if isinstance(instace_style, dict): + raise ValueError(instace_style["error"]) + + words_using = style_controller.relatedWords() + if isinstance(words_using, dict): + raise ValueError(words_using["error"]) + elif style_words == "vocabulario": + name_vocabulary = request.session["form_words"] + vocabulary = Vocabulario.objects.get( + nombre_vocabulario=name_vocabulary) + + es_vocabulary = EsVocabulario.objects.create( + id_tecnica=technique, + id_vocabulario=vocabulary + ) + else: + raise ValueError("Estilo de palabas no permitido") + + # //////////////////////////////////////////////////////// # + # + # Fourth step: Create session and relat with the technique # + # + # //////////////////////////////////////////////////////// # + session_controller = SesionController( + name_session=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None, + technique=technique, + creator=request.user.user_presentador + ) + + setting_session = session_controller.setSession() + if isinstance(setting_session, dict): + raise ValueError(setting_session["error"]) + + saved_session = session_controller.saveSession() + if isinstance(saved_session, dict): + raise ValueError(saved_session["error"]) + + context = { + "message": "sesión creada", + "data": { + "codigo_sesion": saved_session.codigo_sesion, + "nombre_sesion": saved_session.nombre_sesion + } + } + + # ////////////////////////////////// # + # + # Final step: Delete date in session # + # + # ////////////////////////////////// # + + deleteDataSession(request) + return JsonResponse(context) + except ValueError as e: + return general_error(f"Error: {e}") + else: + return general_error("No se ha establecido acción") diff --git a/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_napping_controller.py b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_napping_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..5d9729dff0bc2c033046f5079b33606a971dc53c --- /dev/null +++ b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_napping_controller.py @@ -0,0 +1,95 @@ +from .panel_create_controller import PanelCreateController +from django.http import HttpRequest, JsonResponse +from tecnicas.models import Tecnica, TipoTecnica, EstiloPalabra, Producto, SesionSensorial +from django.db import transaction +from tecnicas.utils import deleteDataSession + + +class PanelCreateNappingController(PanelCreateController): + def __init__(self): + super().__init__() + + @staticmethod + def controllPost(request: HttpRequest): + if request.POST.get('action') == 'create_session': + if not request.session.get("form_basic") or not request.session.get("form_codes"): + deleteDataSession(request) + return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo") + try: + with transaction.atomic(): + # //////////////////////////// # + # + # First step: Create technique # + # + # //////////////////////////// # + data_basic = request.session["form_basic"] + data_basic["numero_catadores"] = data_basic["numero_catadores"] or 2 + data_basic["numero_repeticiones"] = 0 + + technique = Tecnica.objects.create( + tipo_tecnica=TipoTecnica.objects.get( + nombre_tecnica=data_basic["name_tecnica"]), + id_estilo=EstiloPalabra.objects.get( + nombre_estilo="napping"), + repeticiones_max=data_basic["numero_repeticiones"], + limite_catadores=data_basic["numero_catadores"], + instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador", + ) + + if not technique: + raise ValueError("Error al guardar la técnica") + + # ////////////////////////////////////////////// # + # + # Second step: Create productos with their codes # + # + # ////////////////////////////////////////////// # + codes = request.session["form_codes"] + + if not codes: + raise ValueError("No hay códigos de productos") + + products_without_save = [] + for code in codes: + product = Producto( + codigoProducto=code, + id_tecnica=technique + ) + products_without_save.append(product) + + Producto.objects.bulk_create(products_without_save) + + # /////////////////////////////////////////////////////// # + # + # Third step: Create session and relat with the technique # + # + # /////////////////////////////////////////////////////// # + session = SesionSensorial.objects.create( + nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None, + tecnica=technique, + creadoPor=request.user.user_presentador + ) + + if not session: + raise ValueError("Error al crear sesion sensorial") + + context = { + "message": "sesión creada", + "data": { + "codigo_sesion": session.codigo_sesion, + "nombre_sesion": session.nombre_sesion + } + } + + # ////////////////////////////////// # + # + # Final step: Delete date en session # + # + # ////////////////////////////////// # + deleteDataSession(request) + return JsonResponse(context) + + except ValueError as e: + return general_error(f"Error: {e}") + else: + return general_error("No se ha establecido acción") diff --git a/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_pf_controller.py b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_pf_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..b6e368c0f62f1919f6d5c082a2b852d482aa319d --- /dev/null +++ b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_pf_controller.py @@ -0,0 +1,105 @@ +from .panel_create_controller import PanelCreateController +from django.http import HttpRequest, JsonResponse +from django.db import transaction +from tecnicas.models import Tecnica, TipoTecnica, EstiloPalabra, SesionSensorial, Escala, TipoEscala, Producto +from tecnicas.utils import deleteDataSession, general_error + + +class PanelCreatePFController(PanelCreateController): + def __init__(self): + super().__init__() + + @staticmethod + def controllPost(request: HttpRequest): + if request.POST.get('action') == 'create_session': + if not request.session.get("form_codes"): + deleteDataSession(request) + return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo") + try: + with transaction.atomic(): + # ////////////////////////////////////// # + # + # First step: Create technique and scale # + # + # ////////////////////////////////////// # + data_basic = request.session["form_basic"] + phases_before_reptition = 2 + + technique = Tecnica.objects.create( + tipo_tecnica=TipoTecnica.objects.get( + nombre_tecnica=data_basic["name_tecnica"]), + id_estilo=EstiloPalabra.objects.get( + nombre_estilo="perfil flash"), + repeticiones_max=data_basic["numero_repeticiones"] + + phases_before_reptition, + limite_catadores=data_basic["numero_catadores"], + instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Analista", + ) + + if not technique: + raise ValueError("Error al guardar la técnica") + + created_scale = Escala.objects.create( + id_tipo_escala=TipoEscala.objects.get( + nombre_escala="estructurada"), + longitud=data_basic["numero_productos"], + tecnica=technique + ) + + if not created_scale: + raise ValueError("No se ha podido crear la escala") + + # ////////////////////////////////////////////// # + # + # Second step: Create productos with their codes # + # + # ////////////////////////////////////////////// # + codes = request.session["form_codes"] + + if not codes: + raise ValueError("No hay códigos de productos") + + products_without_save = [] + for code in codes: + product = Producto( + codigoProducto=code, + id_tecnica=technique + ) + products_without_save.append(product) + + Producto.objects.bulk_create(products_without_save) + + # /////////////////////////////////////////////////////// # + # + # Third step: Create session and relat with the technique # + # + # /////////////////////////////////////////////////////// # + session = SesionSensorial.objects.create( + nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None, + tecnica=technique, + creadoPor=request.user.user_presentador + ) + + if not session: + raise ValueError("Error al crear sesion sensorial") + + context = { + "message": "sesión creada", + "data": { + "codigo_sesion": session.codigo_sesion, + "nombre_sesion": session.nombre_sesion + } + } + + # ////////////////////////////////// # + # + # Final step: Delete date en session # + # + # ////////////////////////////////// # + deleteDataSession(request) + return JsonResponse(context) + + except ValueError as e: + return general_error(f"Error: {e}") + else: + return general_error("No se ha establecido acción") diff --git a/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_rata_controller.py b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_rata_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..eee8462ae591dc099c787e9d964230173cb98209 --- /dev/null +++ b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_rata_controller.py @@ -0,0 +1,155 @@ +from .panel_create_controller import PanelCreateController +from django.http import HttpRequest, JsonResponse +from django.db import transaction +from tecnicas.controllers import EscalaController +from tecnicas.models import EsVocabulario, Tecnica, TipoTecnica, EstiloPalabra, EsAtributo, Vocabulario, Palabra, SesionSensorial, Producto +from tecnicas.utils import deleteDataSession, general_error + + +class PanelCreateRataController(PanelCreateController): + def __init__(self): + super().__init__() + + @staticmethod + def controllPost(request: HttpRequest): + if request.POST.get('action') == 'create_session': + if not request.session.get("form_tags") or not request.session.get("form_codes") or not request.session.get("form_words"): + deleteDataSession(request) + return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo") + try: + with transaction.atomic(): + # ////////////////////////////////////////////////////// # + # + # First step: Create technique and scale with their tags # + # + # ////////////////////////////////////////////////////// # + data_basic = request.session["form_basic"] + data_basic["numero_catadores"] = 0 + data_basic["numero_repeticiones"] = 1 + + technique = Tecnica.objects.create( + tipo_tecnica=TipoTecnica.objects.get( + nombre_tecnica=data_basic["name_tecnica"]), + id_estilo=EstiloPalabra.objects.get( + nombre_estilo=data_basic["estilo_palabras"]), + repeticiones_max=data_basic["numero_repeticiones"] or 1, + limite_catadores=data_basic["numero_catadores"], + instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador", + ) + + if not technique: + raise ValueError("Error al guardar la técnica") + + data_scale = { + "id_scale": data_basic["tipo_escala"], + "size": data_basic["tamano_escala"], + "technique": technique + } + + controllerScale = EscalaController(data=data_scale) + + scale = controllerScale.saveScale() + if isinstance(scale, dict): + raise ValueError(scale["error"]) + + dict_tags = request.session["form_tags"] + saved_related_tags = controllerScale.realteTags(dict_tags) + if "error" in saved_related_tags: + raise ValueError(saved_related_tags["error"]) + + # ////////////////////////////////////////////// # + # + # Second step: Create productos with their codes # + # + # ////////////////////////////////////////////// # + codes = request.session["form_codes"] + + if not codes: + raise ValueError("No hay códigos de productos") + + products_without_save = [] + for code in codes: + product = Producto( + codigoProducto=code, + id_tecnica=technique + ) + products_without_save.append(product) + + Producto.objects.bulk_create(products_without_save) + + # /////////////////////////////////////////////////////// # + # + # Third step: Create relations technique with Words Style # + # + # /////////////////////////////////////////////////////// # + style_words = technique.id_estilo.nombre_estilo + + if style_words == "atributos": + raw_ids_words = request.session["form_words"] + ids_words = [int(id_w) for id_w in raw_ids_words] + + words = Palabra.objects.filter(id__in=ids_words) + + style_atribute = EsAtributo.objects.create( + id_tecnica=technique + ) + + if not style_atribute: + raise ValueError( + "Error al intentar relacionar las palabras con la técnica") + + style_atribute.palabras.set(words) + + elif style_words == "vocabulario": + name_vocabulary = request.session["form_words"] + try: + vocabulary = Vocabulario.objects.get( + nombre_vocabulario=name_vocabulary) + except Vocabulario.DoesNotExist: + raise ValueError("Vocabulario no encontrado") + + es_vocabulary = EsVocabulario.objects.create( + id_tecnica=technique, + id_vocabulario=vocabulary + ) + if not es_vocabulary: + raise ValueError( + "Error al intentar relacionar el vocabulario con la técnica") + + else: + raise ValueError("Estilo de palabas no permitido") + + # //////////////////////////////////////////////////////// # + # + # Fourth step: Create session and relat with the technique # + # + # //////////////////////////////////////////////////////// # + session = SesionSensorial.objects.create( + nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else "", + tecnica=technique, + creadoPor=request.user.user_presentador + ) + + if not session: + raise ValueError("Error al crear sesion sensorial") + + context = { + "message": "sesión creada", + "data": { + "codigo_sesion": session.codigo_sesion, + "nombre_sesion": session.nombre_sesion + } + } + + # ////////////////////////////////// # + # + # Final step: Delete date en session # + # + # ////////////////////////////////// # + + deleteDataSession(request) + return JsonResponse(context) + except ValueError as e: + return general_error(f"Error: {e}") + else: + return general_error("No se ha establecido acción") diff --git a/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_sort_controller.py b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_sort_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..4d98ce32fe5948f299738bf230be6783c1d13080 --- /dev/null +++ b/tecnicas/controllers/views_controller/create_session/panels_create/panel_create_sort_controller.py @@ -0,0 +1,95 @@ +from .panel_create_controller import PanelCreateController +from django.http import HttpRequest, JsonResponse +from django.db import transaction +from tecnicas.models import Tecnica, TipoTecnica, EstiloPalabra, SesionSensorial, Producto +from tecnicas.utils import deleteDataSession, general_error + + +class PanelCreateSortController(PanelCreateController): + def __init__(self): + super().__init__() + + @staticmethod + def controllPost(request: HttpRequest): + if request.POST.get('action') == 'create_session': + if not request.session.get("form_basic") or not request.session.get("form_codes"): + deleteDataSession(request) + return general_error("No se ha especificado información necesaria para la creación de la sesión, por favor, vuelve a intentarlo") + try: + with transaction.atomic(): + # //////////////////////////// # + # + # First step: Create technique # + # + # //////////////////////////// # + data_basic = request.session["form_basic"] + data_basic["numero_catadores"] = data_basic["numero_catadores"] or 1 + data_basic["numero_repeticiones"] = 1 + + technique = Tecnica.objects.create( + tipo_tecnica=TipoTecnica.objects.get( + nombre_tecnica=data_basic["name_tecnica"]), + id_estilo=EstiloPalabra.objects.get( + nombre_estilo="sort"), + repeticiones_max=data_basic["numero_repeticiones"], + limite_catadores=data_basic["numero_catadores"], + instrucciones=data_basic["instrucciones"] or "Espere instrucciones del Presentador", + ) + + if not technique: + raise ValueError("Error al guardar la técnica") + + # ////////////////////////////////////////////// # + # + # Second step: Create productos with their codes # + # + # ////////////////////////////////////////////// # + codes = request.session["form_codes"] + + if not codes: + raise ValueError("No hay códigos de productos") + + products_without_save = [] + for code in codes: + product = Producto( + codigoProducto=code, + id_tecnica=technique + ) + products_without_save.append(product) + + Producto.objects.bulk_create(products_without_save) + + # /////////////////////////////////////////////////////// # + # + # Third step: Create session and relat with the technique # + # + # /////////////////////////////////////////////////////// # + session = SesionSensorial.objects.create( + nombre_sesion=data_basic["nombre_sesion"] if data_basic["nombre_sesion"] != "" else None, + tecnica=technique, + creadoPor=request.user.user_presentador + ) + + if not session: + raise ValueError("Error al crear sesion sensorial") + + context = { + "message": "sesión creada", + "data": { + "codigo_sesion": session.codigo_sesion, + "nombre_sesion": session.nombre_sesion + } + } + + # ////////////////////////////////// # + # + # Final step: Delete date en session # + # + # ////////////////////////////////// # + deleteDataSession(request) + return JsonResponse(context) + + except ValueError as e: + return general_error(f"Error: {e}") + else: + return general_error("No se ha establecido acción") diff --git a/tecnicas/controllers/views_controller/session_management/details_cata_controller.py b/tecnicas/controllers/views_controller/session_management/details/details_cata_controller.py similarity index 97% rename from tecnicas/controllers/views_controller/session_management/details_cata_controller.py rename to tecnicas/controllers/views_controller/session_management/details/details_cata_controller.py index e1d5442b594b93687846535d092620c649dc4c1b..4b21cde747f701a2ed7ab95a6737339954c638a2 100644 --- a/tecnicas/controllers/views_controller/session_management/details_cata_controller.py +++ b/tecnicas/controllers/views_controller/session_management/details/details_cata_controller.py @@ -9,7 +9,7 @@ from collections import defaultdict class DetallesCATAController(DetallesController): def __init__(self, session: SesionSensorial): super().__init__(session) - self.url_template = "tecnicas/manage_sesions/detalles-sesion-cata.html" + self.url_template = "tecnicas/manage_sesions/details-session-cata.html" self.url_next = "cata_system:monitor_sesion" def getContext(self): diff --git a/tecnicas/controllers/views_controller/session_management/details_controller.py b/tecnicas/controllers/views_controller/session_management/details/details_controller.py similarity index 98% rename from tecnicas/controllers/views_controller/session_management/details_controller.py rename to tecnicas/controllers/views_controller/session_management/details/details_controller.py index f03aea65e6dc205c2ea332ca51658ee73de46f55..78c404de0c9c86b776d59016853e2bcec1c3e46f 100644 --- a/tecnicas/controllers/views_controller/session_management/details_controller.py +++ b/tecnicas/controllers/views_controller/session_management/details/details_controller.py @@ -7,7 +7,7 @@ from tecnicas.controllers import ParticipacionController class DetallesController(): url_template: str - url_next: str + url_next = "cata_system:monitor_sesion" def __init__(self, session: SesionSensorial): self.session = session diff --git a/tecnicas/controllers/views_controller/session_management/details_escala_controller.py b/tecnicas/controllers/views_controller/session_management/details/details_escala_controller.py similarity index 87% rename from tecnicas/controllers/views_controller/session_management/details_escala_controller.py rename to tecnicas/controllers/views_controller/session_management/details/details_escala_controller.py index 9fd3b1b712a42f442131bbe1bf566ba606dd933b..d9534e3d6c327ee72bd0f80bb15424cb8f3f57f1 100644 --- a/tecnicas/controllers/views_controller/session_management/details_escala_controller.py +++ b/tecnicas/controllers/views_controller/session_management/details/details_escala_controller.py @@ -11,20 +11,17 @@ Encabezados de como deben de aparecer los datos juntos | Repeticion | Codigo Producto | Catador | P1 | P2 | P3 | Pn | ''' -from django.http import HttpRequest -from django.shortcuts import render, redirect -from django.urls import reverse -from tecnicas.models import SesionSensorial, Presentador, Participacion, Calificacion, Escala -from tecnicas.controllers import DatoController, PalabrasController, ParticipacionController +from tecnicas.models import SesionSensorial, Calificacion, Escala +from tecnicas.controllers import DatoController, PalabrasController from .details_controller import DetallesController -from tecnicas.utils import defaultdict_to_dict, controller_error +from tecnicas.utils import defaultdict_to_dict from collections import defaultdict class DetallesEscalasController(DetallesController): def __init__(self, session: SesionSensorial): super().__init__(session) - self.url_template = "tecnicas/manage_sesions/detalles-sesion.html" + self.url_template = "tecnicas/manage_sesions/details-session.html" self.url_next = "cata_system:monitor_sesion" def getContext(self): diff --git a/tecnicas/controllers/views_controller/session_management/details_pf_controller.py b/tecnicas/controllers/views_controller/session_management/details/details_pf_controller.py similarity index 94% rename from tecnicas/controllers/views_controller/session_management/details_pf_controller.py rename to tecnicas/controllers/views_controller/session_management/details/details_pf_controller.py index 325fa14addaacedb3985b75ecc42b236d0539c6d..988373bcc5aad10007aedac6779ca1591bf6afff 100644 --- a/tecnicas/controllers/views_controller/session_management/details_pf_controller.py +++ b/tecnicas/controllers/views_controller/session_management/details/details_pf_controller.py @@ -1,8 +1,5 @@ -from django.http import HttpRequest -from django.shortcuts import redirect -from django.urls import reverse -from tecnicas.models import SesionSensorial, Presentador, Participacion, ListaPalabras, Calificacion, Catador -from tecnicas.controllers import ParticipacionController, DatoController +from tecnicas.models import SesionSensorial, ListaPalabras, Calificacion, Catador +from tecnicas.controllers import DatoController from tecnicas.utils import defaultdict_to_dict from .details_controller import DetallesController from collections import defaultdict @@ -20,9 +17,7 @@ class DetallesPFController(DetallesController): self.context = { "sesion": self.session, "use_technique": technique, - "existen_calificaciones": False, "tipo_escala": technique.escala_tecnica.id_tipo_escala.nombre_escala, - "valor_max": technique.escala_tecnica.longitud, "repeticiones_max": technique.repeticiones_max - 2 } diff --git a/tecnicas/controllers/views_controller/session_management/details/details_rata_controller.py b/tecnicas/controllers/views_controller/session_management/details/details_rata_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..71dae2b469f24c2dd1a2ec969a32a329d62c574a --- /dev/null +++ b/tecnicas/controllers/views_controller/session_management/details/details_rata_controller.py @@ -0,0 +1,7 @@ +from tecnicas.models import SesionSensorial +from .details_controller import DetallesController + + +class DetallesRATAController(DetallesController): + def __init__(self, session: SesionSensorial): + super().__init__(session) diff --git a/tecnicas/controllers/views_controller/session_management/details/details_sort_controller.py b/tecnicas/controllers/views_controller/session_management/details/details_sort_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..542df448c230782658ce5d12142c38e733b60405 --- /dev/null +++ b/tecnicas/controllers/views_controller/session_management/details/details_sort_controller.py @@ -0,0 +1,91 @@ +from .details_controller import DetallesController +from tecnicas.models import SesionSensorial, GrupoProducto, Producto, Participacion +from collections import defaultdict + + +class DetallesSortController(DetallesController): + def __init__(self, session: SesionSensorial): + super().__init__(session) + self.url_template = "tecnicas/manage_sesions/details-session-sort.html" + self.url_next = "cata_system:monitor_sesion" + + def getContext(self): + technique = self.session.tecnica + + finished = False + status = "" + + if technique.repeticion < technique.repeticiones_max and not self.session.activo: + status = "En espera para iniciar la sesión" + elif technique.repeticion >= technique.repeticiones_max and not self.session.activo: + status = "Esta sesión ha sido finalizada" + finished = True + else: + status = "La sesión está en progreso" + + self.context = { + "sesion": self.session, + "technique": technique, + "status": status, + "finished": finished + } + + self.context["data_groups"] = { + "data": self.setDataSort(), + "testers": self.setHeaders() + } + + return self.context + + def setDataSort(self): + data = [] + technique = self.session.tecnica + + products = Producto.objects.filter(id_tecnica=technique) + + groups = GrupoProducto.objects.select_related("catador").filter( + tecnica=technique + ) + + if len(groups): + self.context["there_data"] = True + else: + self.context["there_data"] = False + return [] + + for product in products: + product_data = { + "codigo_producto": product.codigoProducto, + "palabras": {} + } + + related_groups = groups.filter(productos=product).select_related( + "catador__user" + ).prefetch_related("palabras") + + data_words = defaultdict(set) + + for group in related_groups: + catador_username = group.catador.user.username + + for word in group.palabras.all(): + data_words[catador_username].add(word.nombre_palabra) + + product_data["palabras"] = { + username: list(words) + for username, words in data_words.items() + } + + data.append(product_data) + + return data + + def setHeaders(self): + participacions = list(Participacion.objects.filter( + tecnica=self.session.tecnica + ).only("catador").select_related("catador__user")) + + testers = [ + participacion.catador.user.username for participacion in participacions] + + return testers diff --git a/tecnicas/controllers/views_controller/session_management/details_rata_controller.py b/tecnicas/controllers/views_controller/session_management/details_rata_controller.py deleted file mode 100644 index a6f7e2e6e26d3685899a1cdc552b9e647c5ef302..0000000000000000000000000000000000000000 --- a/tecnicas/controllers/views_controller/session_management/details_rata_controller.py +++ /dev/null @@ -1,12 +0,0 @@ -from django.http import HttpRequest -from django.shortcuts import render, redirect -from tecnicas.models import SesionSensorial -from tecnicas.controllers import PalabrasController, DatoController, CalificacionController -from tecnicas.utils import defaultdict_to_dict -from .details_controller import DetallesController -from collections import defaultdict - - -class DetallesRATAController(DetallesController): - def __init__(self, session: SesionSensorial): - super().__init__(session) diff --git a/tecnicas/controllers/views_controller/session_management/monitor_controller.py b/tecnicas/controllers/views_controller/session_management/monitor/monitor_controller.py similarity index 88% rename from tecnicas/controllers/views_controller/session_management/monitor_controller.py rename to tecnicas/controllers/views_controller/session_management/monitor/monitor_controller.py index c1c8b97f260f14d640b2b81e6c1aafb5e856e2b6..16aa77587372d74b5abcf710927f69fce4143cc2 100644 --- a/tecnicas/controllers/views_controller/session_management/monitor_controller.py +++ b/tecnicas/controllers/views_controller/session_management/monitor/monitor_controller.py @@ -1,9 +1,7 @@ from django.http import HttpRequest from django.shortcuts import render, redirect from django.urls import reverse -from tecnicas.models import SesionSensorial, Producto, EsAtributo, EsVocabulario -from tecnicas.controllers import ParticipacionController, SesionController -from tecnicas.utils import controller_error +from tecnicas.models import SesionSensorial, Producto, EsAtributo, EsVocabulario, Participacion class MonitorController(): @@ -14,20 +12,20 @@ class MonitorController(): self.sensorial_session = session def controllPostFinishSession(self, request: HttpRequest): - self.setContext() (is_all_end, message) = self.checkAllFinish() if not is_all_end: + self.setContext() self.context["error"] = message return render(request, self.url_view, self.context) self.finishSession() return redirect(reverse(self.previus_view, kwargs={"session_code": self.sensorial_session.codigo_sesion})) - def checkAllFinish(self): + def checkAllFinish(self) -> (bool, str): return (False, "Función sin implementar") def setContext(self): - self.participations = ParticipacionController.getParticipationsInTechinique( - self.sensorial_session.tecnica) + self.participations = Participacion.objects.filter( + tecnica=self.sensorial_session.tecnica) self.context = { "code_session": self.sensorial_session.codigo_sesion, diff --git a/tecnicas/controllers/views_controller/session_management/monitor_escalas_controller.py b/tecnicas/controllers/views_controller/session_management/monitor/monitor_escalas_controller.py similarity index 100% rename from tecnicas/controllers/views_controller/session_management/monitor_escalas_controller.py rename to tecnicas/controllers/views_controller/session_management/monitor/monitor_escalas_controller.py diff --git a/tecnicas/controllers/views_controller/session_management/monitor_pf_controller.py b/tecnicas/controllers/views_controller/session_management/monitor/monitor_pf_controller.py similarity index 96% rename from tecnicas/controllers/views_controller/session_management/monitor_pf_controller.py rename to tecnicas/controllers/views_controller/session_management/monitor/monitor_pf_controller.py index 1b32905a6d6bf6e0791ef0bf2b30c0a2e2ded406..d15d1356635910a50e8ea628a7d3fcac337952a4 100644 --- a/tecnicas/controllers/views_controller/session_management/monitor_pf_controller.py +++ b/tecnicas/controllers/views_controller/session_management/monitor/monitor_pf_controller.py @@ -1,6 +1,3 @@ -from django.http import HttpRequest -from django.shortcuts import render, redirect -from django.urls import reverse from tecnicas.models import Dato, Participacion, Catador, ListaPalabras, Producto from tecnicas.controllers import SesionController from .monitor_controller import MonitorController diff --git a/tecnicas/controllers/views_controller/session_management/monitor_rata_controller.py b/tecnicas/controllers/views_controller/session_management/monitor/monitor_rata_controller.py similarity index 100% rename from tecnicas/controllers/views_controller/session_management/monitor_rata_controller.py rename to tecnicas/controllers/views_controller/session_management/monitor/monitor_rata_controller.py diff --git a/tecnicas/controllers/views_controller/session_management/monitor/monitor_sort_controller.py b/tecnicas/controllers/views_controller/session_management/monitor/monitor_sort_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..faf9890bf613eb704b8a9556d6f4c54307622891 --- /dev/null +++ b/tecnicas/controllers/views_controller/session_management/monitor/monitor_sort_controller.py @@ -0,0 +1,27 @@ +from tecnicas.models import SesionSensorial +from tecnicas.models import Participacion +from .monitor_controller import MonitorController + + +class MonitorSortController(MonitorController): + def __init__(self, session: SesionSensorial): + super().__init__(session) + self.url_view = "tecnicas/manage_sesions/monitor-session-sort.html" + self.previus_view = "cata_system:detalles_sesion" + + def checkAllFinish(self): + technique = self.sensorial_session.tecnica + + num_participations = Participacion.objects.filter( + tecnica=technique).count() + + if num_participations < technique.limite_catadores: + return (False, "No se ha alcanzado el número máximo de catadores") + + unfinished_participations = Participacion.objects.filter( + tecnica=technique, finalizado=False).count() + + if unfinished_participations > 0: + return (False, "No todos los catadores han finalizado su evaluación") + + return (True, "Puedes finalizar la sesión") \ No newline at end of file diff --git a/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_controller.py b/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_controller.py index 5d89da3a05492aef4d39813dba33e32296e28fbb..3aae41371be88f624386caa5841f8277d6495eed 100644 --- a/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_controller.py +++ b/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_controller.py @@ -11,7 +11,7 @@ class InitSessionController(): session: SesionSensorial order: Orden | dict current_direction: str - current_direction = "tecnicas/forms_tester/init_session.html" + current_direction = "tecnicas/forms_tester/init_scales_test.html" escalas_direction = "cata_system:session_convencional" def __init__(self, sensorial_session: SesionSensorial, user_tester: Catador): diff --git a/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_escalas_controller.py b/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_escalas_controller.py index 271577d22927c7cb0b9a23c4722080d3b6c84b21..2fb4e970f749193123cb785775eed700a21cfa7a 100644 --- a/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_escalas_controller.py +++ b/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_escalas_controller.py @@ -13,7 +13,7 @@ class InitSessionEscalasController(InitSessionController): def __init__(self, sensorial_session, user_tester): super().__init__(sensorial_session, user_tester) - self.current_direction = "tecnicas/forms_tester/init_session.html" + self.current_direction = "tecnicas/forms_tester/init_scales_test.html" self.escalas_direction = "cata_system:session_convencional" self.cata_direction = "cata_system:session_cata" diff --git a/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_pf_controller.py b/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_pf_controller.py index 991fcc19107622835b2e4ad32da6a0a945f2c4a5..299272eb21efb751ecec9362a0f0cbe9b7f324a0 100644 --- a/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_pf_controller.py +++ b/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_pf_controller.py @@ -9,7 +9,7 @@ from .init_session_controller import InitSessionController class InitSessionPFController(InitSessionController): def __init__(self, sensorial_session, user_tester): super().__init__(sensorial_session, user_tester) - self.current_direction = "tecnicas/forms_tester/init_session_pf.html" + self.current_direction = "tecnicas/forms_tester/init_pf_test.html" self.pf_direction = "cata_system:session_pf" def controllGet(self, request: HttpRequest): diff --git a/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_rata_controller.py b/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_rata_controller.py index 9eea35cd6c5f67102b8f296995aca5814e82f270..405986dbfbd0a93c1b00c61f0b0d2bd7e1068876 100644 --- a/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_rata_controller.py +++ b/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_rata_controller.py @@ -6,7 +6,7 @@ from .init_session_controller import InitSessionController class InitSessionRATAController(InitSessionController): def __init__(self, sensorial_session, user_tester): super().__init__(sensorial_session, user_tester) - self.current_direction = "tecnicas/forms_tester/init_session.html" + self.current_direction = "tecnicas/forms_tester/init_scales_test.html" def controllGet(self, request: HttpRequest): context = { diff --git a/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_sort_controller.py b/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_sort_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..7d21f8c5f23157563b2dfbb826118980ac426b2f --- /dev/null +++ b/tecnicas/controllers/views_controller/sessions_tester/init_session/init_session_sort_controller.py @@ -0,0 +1,77 @@ +from django.http import HttpRequest +from django.shortcuts import render, redirect +from django.urls import reverse +from tecnicas.models import Participacion +from tecnicas.controllers import ParticipacionController +from .init_session_controller import InitSessionController + + +class InitSessionSortController(InitSessionController): + def __init__(self, sensorial_session, user_tester): + super().__init__(sensorial_session, user_tester) + self.current_direction = "tecnicas/forms_tester/init_test_sort.html" + self.sort_direction = "cata_system:session_sort" + + def controllGet(self, request: HttpRequest, error=""): + context = { + "session": self.session, + "type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica + } + + is_end = self.isEndedSession() + + context["has_ended"] = is_end + + if is_end: + context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador" + + if "error" in request.GET: + context["error"] = request.GET["error"] + + return render(request, self.current_direction, context) + + def isEndedSession(self): + participation = Participacion.objects.get( + catador=self.tester, tecnica=self.session.tecnica) + + return participation.finalizado + + def controllPost(self, request: HttpRequest): + context = { + "session": self.session, + "type_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica + } + + use_action = request.POST["action"] + + if use_action == "start_posting": + parameters = { + "code_sesion": self.session.codigo_sesion + } + + is_end = self.isEndedSession() + if is_end: + context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador" + return render(request, self.current_direction, context) + + update_participation = ParticipacionController.enterSession( + tester=request.user.user_catador, session=self.session) + + if isinstance(update_participation, dict): + context["error"] = update_participation["error"] + return render(request, self.current_direction, context) + + request.session["id_participation"] = update_participation.id + + return redirect(reverse(self.sort_direction, kwargs=parameters)) + + elif use_action == "exit_session": + response = ParticipacionController.outSession( + tester=request.user.user_catador, session=self.session) + if isinstance(response, dict): + context["error"] = response["error"] + return render(request, self.current_direction, context) + + else: + context["error"] = "Acción sin especificar" + return render(request, self.current_direction, context) diff --git a/tecnicas/controllers/views_controller/sessions_tester/login_session_tester_controller.py b/tecnicas/controllers/views_controller/sessions_tester/login_session_tester_controller.py index 611c106d2815da8ea9c4b18f9a3b9fcb57c0525d..f8dbdd7a62d656a51d931d49996707afe791950d 100644 --- a/tecnicas/controllers/views_controller/sessions_tester/login_session_tester_controller.py +++ b/tecnicas/controllers/views_controller/sessions_tester/login_session_tester_controller.py @@ -98,5 +98,51 @@ class LoginSessionTesterController(): context["error"] = "Imposible acceder a esta sesión" return render(request, self.current_direcction, context) + def validateEntrySort(self, request: HttpRequest): + context = {} + if not self.session.activo: + context["error"] = "La sesión no está activa actualmente" + return render(request, self.current_direcction, context) + + if self.session.tecnica.repeticion == 1: + try: + self.taster_participation = Participacion.objects.get( + tecnica=self.session.tecnica, catador=self.tester) + context["error"] = "Usted ya esta dentro de la sesión" + return render(request, self.current_direcction, context) + + except Participacion.DoesNotExist: + try: + with transaction.atomic(): + code_session = self.session.codigo_sesion + self.session = SesionSensorial.objects.select_for_update().get( + codigo_sesion=code_session) + + max_testers = self.session.tecnica.limite_catadores + current_num_testers = Participacion.objects.filter( + tecnica=self.session.tecnica).count() + + if current_num_testers >= max_testers: + raise ValueError( + "La sesión ha alcanzado el número máximo de catadores") + + self.taster_participation = Participacion.objects.create( + tecnica=self.session.tecnica, + catador=self.tester, + finalizado=False + ) + params = { + "code_sesion": self.session.codigo_sesion + } + return redirect(reverse(self.destinity_direcction, kwargs=params)) + + except ValueError as e: + context["error"] = str(e) + return render(request, self.current_direcction, context) + + else: + context["error"] = "Ya no es posible ingresar a la sesión" + return render(request, self.current_direcction, context) + def validateEntryPF(self, request=HttpRequest): return self.validateEntryEscalas(request=request) diff --git a/tecnicas/controllers/views_controller/sessions_tester/tests_forms/general_test_controller.py b/tecnicas/controllers/views_controller/sessions_tester/tests_forms/general_test_controller.py index 5cfc2e37746557838b9947caa7de4abc098c348a..ddfc0941a4c6cd166456f1eb4170c232a97d1fbc 100644 --- a/tecnicas/controllers/views_controller/sessions_tester/tests_forms/general_test_controller.py +++ b/tecnicas/controllers/views_controller/sessions_tester/tests_forms/general_test_controller.py @@ -1,7 +1,8 @@ from django.http import HttpRequest from django.shortcuts import redirect, render from django.urls import reverse -from tecnicas.models import SesionSensorial, Catador +from tecnicas.models import SesionSensorial, Catador, Participacion +from tecnicas.controllers import ParticipacionController class GenetalTestController(): @@ -12,3 +13,16 @@ class GenetalTestController(): def __init__(self, sensorial_session: SesionSensorial, user_tester: Catador): self.tester = user_tester self.session = sensorial_session + + def controllPost(self, request: HttpRequest): + action = request.POST["action"] + + if action == "finish_session": + self.participation = Participacion.objects.get( + tecnica=self.session.tecnica, catador=request.user.user_catador) + ParticipacionController.finishSession(self.participation) + params = {"code_sesion": self.session.codigo_sesion} + return redirect(reverse(self.previus_directory, kwargs=params)) + + else: + return self.controllGet(request, error="Acción no permitida") diff --git a/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_cata_controller.py b/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_cata_controller.py index 19743636e3075434a97face6c0005c9f87099560..13f1badfa70504e81dce9a1819170e24031c311c 100644 --- a/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_cata_controller.py +++ b/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_cata_controller.py @@ -9,7 +9,7 @@ from .general_test_controller import GenetalTestController class TestCataController(GenetalTestController): def __init__(self, sensorial_session, user_tester): super().__init__(sensorial_session, user_tester) - self.current_directory = "tecnicas/forms_tester/cata.html" + self.current_directory = "tecnicas/forms_tester/test_cata.html" def controllGet(self, request: HttpRequest): technique = self.session.tecnica diff --git a/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_rata_controller.py b/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_rata_controller.py index fbbb570973d83ab5b8860e1c75c4b18c0075dbbc..ed51287a1f54f164cb93011693d689a097136019 100644 --- a/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_rata_controller.py +++ b/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_rata_controller.py @@ -9,7 +9,7 @@ from .general_test_controller import GenetalTestController class TestRataController(GenetalTestController): def __init__(self, sensorial_session, user_tester): super().__init__(sensorial_session, user_tester) - self.current_directory = "tecnicas/forms_tester/convencional.html" + self.current_directory = "tecnicas/forms_tester/test_convencional.html" def controllGet(self, request: HttpRequest): technique = self.session.tecnica diff --git a/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_scales_controller.py b/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_scales_controller.py index 2e0e60f82acb8b1516126bc7697b5c2a14e23d9b..19985ddd5d666bc206c8f9e2d11f6226d96a2800 100644 --- a/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_scales_controller.py +++ b/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_scales_controller.py @@ -9,7 +9,7 @@ from .general_test_controller import GenetalTestController class TestScalesController(GenetalTestController): def __init__(self, sensorial_session, user_tester): super().__init__(sensorial_session, user_tester) - self.current_directory = "tecnicas/forms_tester/convencional.html" + self.current_directory = "tecnicas/forms_tester/test_convencional.html" def controllGet(self, request: HttpRequest): technique = self.session.tecnica diff --git a/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_sort_controller.py b/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_sort_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..51956d64a1f58ce084f33e5425eab2b3de3fbe08 --- /dev/null +++ b/tecnicas/controllers/views_controller/sessions_tester/tests_forms/test_sort_controller.py @@ -0,0 +1,50 @@ +from django.http import HttpRequest +from django.shortcuts import redirect, render +from django.urls import reverse +from tecnicas.models import Participacion, Producto, Calificacion, Palabra, GrupoProducto +from tecnicas.controllers import ParticipacionController, PalabrasController, EscalaController +from tecnicas.forms import ListWordsForm +from .general_test_controller import GenetalTestController + + +class TestSortController(GenetalTestController): + def __init__(self, sensorial_session, user_tester): + super().__init__(sensorial_session, user_tester) + self.current_directory = "tecnicas/forms_tester/test_sort.html" + + def controllGet(self, request: HttpRequest): + ''' + Objetivo: Entregar al cliente los grupos de productos guardados hechos por el catador en una lista, de lo contrario solo mandar una lista vacia + - Comprobar que el Catador aun no finalice su la sesion + - Obtener todos los productos en la tecnica + - Obtener todos los grupos creadas por el usuario + - Si hay grupos, cada item de la lista a mandar debe incluir los productos asociados al grupo como las palabras que describen al grupo + - Si no hay grupos, solo mandar una lista vacia + - Mandar la lista de grupos como la lista de productos + - Agregar el formulario para describir los grupo + ''' + self.context["session"] = self.session + technique = self.session.tecnica + + self.participation = Participacion.objects.get( + tecnica=technique, catador=request.user.user_catador) + + # Comprobar que el Catador no haya finalizado + if self.participation.finalizado: + params = { + "code_sesion": self.session.codigo_sesion + } + return redirect(reverse(self.previus_directory, kwargs=params)) + + products_in_technique = Producto.objects.filter(id_tecnica=technique) + self.context["products"] = products_in_technique + + grups_products = GrupoProducto.objects.filter( + tecnica=technique, catador=request.user.user_catador).select_related("productos", "palabras") + + self.context["grups_products"] = grups_products if grups_products else [] + + self.context["form_word"] = ListWordsForm() + + return render(request, self.current_directory, self.context) + diff --git a/tecnicas/forms/__init__.py b/tecnicas/forms/__init__.py index ff154ded014eb604b67d8688abd8ddfbfe11cbd7..1add46c25cd8a274807116652797d50b80795081 100644 --- a/tecnicas/forms/__init__.py +++ b/tecnicas/forms/__init__.py @@ -2,6 +2,8 @@ from .create_session.sesion_basic_form import SesionBasicForm from .create_session.sesiob_basic_cata_form import SesionBasicCATAForm from .create_session.sesion_basic_pf_form import SesionBasicPFForm from .create_session.sesion_tags_form import SesionTagsForm +from .create_session.sesion_basic_sort_form import SesionBasicSortForm +from .create_session.sesion_basic_napping import SesionBasicNappingForm from .etiqueta_form import EtiquetaForm from .codes_form import CodesForm diff --git a/tecnicas/forms/create_session/sesiob_basic_cata_form.py b/tecnicas/forms/create_session/sesiob_basic_cata_form.py index b578857573b1257f2dc2dc27b36d488def2f559a..4a58d9be5dcbbe55aff7bda0b2f684cce657f293 100644 --- a/tecnicas/forms/create_session/sesiob_basic_cata_form.py +++ b/tecnicas/forms/create_session/sesiob_basic_cata_form.py @@ -22,6 +22,11 @@ class SesionBasicCATAForm(forms.Form): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields['estilo_palabras'] = forms.ModelChoiceField(queryset=EstiloPalabra.objects.all(), widget=forms.RadioSelect(attrs={ + options = [ + ("atributos", "atributos"), + ("vocabulario", "vocabulario") + ] + + self.fields['estilo_palabras'] = forms.ChoiceField(choices=options, widget=forms.RadioSelect(attrs={ "class": "uppercase text-lg tracking-wider font-medium p-2 px-4 active:px-5 transition-all rounded-xl bg-blue-500 text-white", - }), required=True, initial=EstiloPalabra.objects.first()) + }), required=True, initial=options[0]) diff --git a/tecnicas/forms/create_session/sesion_basic_form.py b/tecnicas/forms/create_session/sesion_basic_form.py index 34fef6e39575562583ac21e8e470be0eeb7874af..1fd90dcac0ce54d36a342d3af94080f08aa5da47 100644 --- a/tecnicas/forms/create_session/sesion_basic_form.py +++ b/tecnicas/forms/create_session/sesion_basic_form.py @@ -38,9 +38,14 @@ class SesionBasicForm(forms.Form): if initial_conf is None: initial_conf = {} - self.fields['estilo_palabras'] = forms.ModelChoiceField(queryset=EstiloPalabra.objects.all(), widget=forms.RadioSelect(attrs={ + options = [ + ("atributos", "atributos"), + ("vocabulario", "vocabulario") + ] + + self.fields['estilo_palabras'] = forms.ChoiceField(choices=options, widget=forms.RadioSelect(attrs={ "class": "uppercase text-lg tracking-wider font-medium p-2 px-4 active:px-5 transition-all rounded-xl bg-blue-500 text-white", - }), required=True, initial=EstiloPalabra.objects.first()) + }), required=True, initial=options[0]) self.fields['tipo_escala'] = forms.ModelChoiceField(queryset=TipoEscala.objects.all(), widget=forms.RadioSelect(attrs={ "class": "uppercase text-lg tracking-wider font-medium p-2 px-4 active:px-5 transition-all rounded-xl bg-blue-500 text-white", diff --git a/tecnicas/forms/create_session/sesion_basic_napping.py b/tecnicas/forms/create_session/sesion_basic_napping.py new file mode 100644 index 0000000000000000000000000000000000000000..22854573bd93aeea285ef95f25b687df17cd828a --- /dev/null +++ b/tecnicas/forms/create_session/sesion_basic_napping.py @@ -0,0 +1,24 @@ +from django import forms + + +class SesionBasicNappingForm(forms.Form): + nombre_sesion = forms.CharField(max_length=255, widget=forms.TextInput(attrs={ + "class": "bg-surface-ligt border-b-1 text-center w-full p-1", + "name": "nombre_sesion", + "placeholder": "Ej. Mermelada de mango picante" + }), required=False) + + numero_productos = forms.IntegerField(widget=forms.NumberInput(attrs={ + "class": "bg-surface-ligt p-1 border-b-1 text-center w-full", + "placeholder": "Solo números" + }), required=True) + + numero_catadores = forms.IntegerField(widget=forms.NumberInput(attrs={ + "class": "bg-surface-ligt p-1 border-b-1 text-center w-full", + "placeholder": "Solo números" + }), required=True) + + instrucciones = forms.CharField(max_length=255, widget=forms.TextInput(attrs={ + "class": "bg-surface-ligt border-b-1 text-center w-full p-1", + "placeholder": "Este campo es opcional" + }), required=False) diff --git a/tecnicas/forms/create_session/sesion_basic_pf_form.py b/tecnicas/forms/create_session/sesion_basic_pf_form.py index 819d44d89a188a5002b3873f236629ac5efe242c..d1609d4b8e95a3dc7cc405ca1b095f2fc7420ff2 100644 --- a/tecnicas/forms/create_session/sesion_basic_pf_form.py +++ b/tecnicas/forms/create_session/sesion_basic_pf_form.py @@ -1,5 +1,4 @@ from django import forms -from tecnicas.models import TipoEscala class SesionBasicPFForm(forms.Form): diff --git a/tecnicas/forms/create_session/sesion_basic_sort_form.py b/tecnicas/forms/create_session/sesion_basic_sort_form.py new file mode 100644 index 0000000000000000000000000000000000000000..bb2f0c70775cd838a064c4670b04a2ab587d5fce --- /dev/null +++ b/tecnicas/forms/create_session/sesion_basic_sort_form.py @@ -0,0 +1,24 @@ +from django import forms + + +class SesionBasicSortForm(forms.Form): + nombre_sesion = forms.CharField(max_length=255, widget=forms.TextInput(attrs={ + "class": "bg-surface-ligt border-b-1 text-center w-full p-1", + "name": "nombre_sesion", + "placeholder": "Ej. Mermelada de mango picante" + }), required=False) + + numero_productos = forms.IntegerField(widget=forms.NumberInput(attrs={ + "class": "bg-surface-ligt p-1 border-b-1 text-center w-full", + "placeholder": "Solo números" + }), required=True) + + numero_catadores = forms.IntegerField(widget=forms.NumberInput(attrs={ + "class": "bg-surface-ligt p-1 border-b-1 text-center w-full", + "placeholder": "Solo números" + }), required=True) + + instrucciones = forms.CharField(max_length=255, widget=forms.TextInput(attrs={ + "class": "bg-surface-ligt border-b-1 text-center w-full p-1", + "placeholder": "Este campo es opcional" + }), required=False) diff --git a/tecnicas/migrations/0024_alter_sesionsensorial_codigo_sesion_grupoproducto.py b/tecnicas/migrations/0024_alter_sesionsensorial_codigo_sesion_grupoproducto.py new file mode 100644 index 0000000000000000000000000000000000000000..0504ee42d9cada10afede1de43c835e2ff75b8ae --- /dev/null +++ b/tecnicas/migrations/0024_alter_sesionsensorial_codigo_sesion_grupoproducto.py @@ -0,0 +1,30 @@ +# Generated by Django 5.2.1 on 2025-11-25 01:18 + +import django.db.models.deletion +import shortuuid.main +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tecnicas', '0023_alter_sesionsensorial_codigo_sesion_listapalabras'), + ] + + operations = [ + migrations.AlterField( + model_name='sesionsensorial', + name='codigo_sesion', + field=models.CharField(default=shortuuid.main.ShortUUID.uuid, editable=False, max_length=22, primary_key=True, serialize=False), + ), + migrations.CreateModel( + name='GrupoProducto', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('catador', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='catador_grupo_producto', to='tecnicas.catador')), + ('palabras', models.ManyToManyField(related_name='grupo_producto', to='tecnicas.palabra')), + ('productos', models.ManyToManyField(related_name='grupo_producto', to='tecnicas.producto')), + ('tecnica', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tecnica_grupo_producto', to='tecnicas.tecnica')), + ], + ), + ] diff --git a/tecnicas/models/__init__.py b/tecnicas/models/__init__.py index b642d98eb1d61d58cae1e397890c3daeab492f23..8f81308d70330373dd54f858cbb50c4b9be8d9bf 100644 --- a/tecnicas/models/__init__.py +++ b/tecnicas/models/__init__.py @@ -30,3 +30,4 @@ from .orden import Posicion from .participacion import Participacion from .lista_palabras import ListaPalabras +from .grupo_producto import GrupoProducto diff --git a/tecnicas/models/grupo_producto.py b/tecnicas/models/grupo_producto.py new file mode 100644 index 0000000000000000000000000000000000000000..ae21abdb5ef2d69322bf8dec4880b74d7f5bf166 --- /dev/null +++ b/tecnicas/models/grupo_producto.py @@ -0,0 +1,19 @@ +from django.db import models +from tecnicas.models import Tecnica, Catador, Palabra, Producto + + +class GrupoProducto(models.Model): + tecnica = models.ForeignKey( + Tecnica, on_delete=models.CASCADE, related_name="tecnica_grupo_producto") + + catador = models.ForeignKey( + Catador, on_delete=models.CASCADE, related_name="catador_grupo_producto") + + productos = models.ManyToManyField( + Producto, related_name="grupo_producto") + + palabras = models.ManyToManyField( + Palabra, related_name="grupo_producto") + + def __str__(self): + return f"{self.tecnica.sesion_tecnica.codigo_sesion} - {self.catador.user.username}" diff --git a/tecnicas/static/js/download-table-csv.js b/tecnicas/static/js/download-table-csv.js index 1e525453c2a5aa0bf5fbe1a55babcf923d65a13a..27afdf85556badce4f412b9da43405f8d50c8f16 100644 --- a/tecnicas/static/js/download-table-csv.js +++ b/tecnicas/static/js/download-table-csv.js @@ -4,7 +4,7 @@ document.addEventListener("DOMContentLoaded", function () { btn.addEventListener("click", function () { // Try set the table in the page - let table = document.getElementById("convencional-table"); + let table = document.getElementById("generic-donwload-table"); if (!table) { const section = btn.closest("section"); if (section) table = section.querySelector("table"); diff --git a/tecnicas/static/js/download-table-sort-csv.js b/tecnicas/static/js/download-table-sort-csv.js new file mode 100644 index 0000000000000000000000000000000000000000..0253a18129d6369de6a96b5b99e841800f292b03 --- /dev/null +++ b/tecnicas/static/js/download-table-sort-csv.js @@ -0,0 +1,79 @@ +document.addEventListener("DOMContentLoaded", function () { + const btn = document.getElementById("download-csv-btn"); + if (!btn) return; + + btn.addEventListener("click", function () { + // Try set the table in the page + let table = document.getElementById("generic-donwload-table"); + if (!table) { + const section = btn.closest("section"); + if (section) table = section.querySelector("table"); + } + if (!table) { + console.warn("No se encontró la tabla para descargar."); + return; + } + + // helper to trim and normalize cell text + const cellText = (cell) => { + if (!cell) return ""; + return String(cell.textContent || "").trim(); + }; + + // Collect headers + const headers = []; + const ths = table.querySelectorAll("thead th"); + ths.forEach((th) => headers.push(cellText(th))); + + // Collect rows + const rows = []; + const trs = table.querySelectorAll("tbody tr"); + trs.forEach((tr) => { + const cols = []; + const tds = tr.querySelectorAll("td"); + tds.forEach((td) => cols.push(cellText(td))); + rows.push(cols); + }); + + // Convert to CSV string (escape quotes, wrap in quotes if needed) + const escapeValue = (val) => { + if (val == null) return ""; + let normalVal = val.replace(/[\u0300-\u036f]/g, ""); + normalVal = normalVal.replace(/(\r\n|\n|\r|\s)/gm, ''); + const needsQuotes = /[",\n,;]/.test(normalVal); + let v = normalVal.replace(/"/g, '""'); + if (needsQuotes) v = `"${v}"`; + return v; + }; + + const lines = []; + if (headers.length) lines.push(headers.map(escapeValue).join(",")); + rows.forEach((r) => lines.push(r.map(escapeValue).join(","))); + + const csvContent = lines.join("\n"); + + // File name: data_{nombre_sesion or codigo_sesion} + const rawName = (btn.dataset.sessionName || "").trim(); + const code = (btn.dataset.sessionCode || "").trim() || "session"; + const namePart = rawName + ? rawName.replace(/[^a-zA-Z0-9-_áéíóúÁÉÍÓÚ ]/g, "").replace(/\s+/g, "_") + : code; + const fileName = `data_${namePart}.csv`; + + // Create blob and force download + const blob = new Blob([csvContent], { type: "text/csv;charset=UTF-8;" }); + if (navigator.msSaveBlob) { + navigator.msSaveBlob(blob, fileName); + } else { + const link = document.createElement("a"); + const url = URL.createObjectURL(blob); + link.setAttribute("href", url); + link.setAttribute("download", fileName); + link.style.visibility = "hidden"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); + } + }); +}); diff --git a/tecnicas/static/js/test-sort.js b/tecnicas/static/js/test-sort.js new file mode 100644 index 0000000000000000000000000000000000000000..0d46731c1b35bc5d8c3e4d6627a5267db9579347 --- /dev/null +++ b/tecnicas/static/js/test-sort.js @@ -0,0 +1,554 @@ +let dragged = null; + +const productsPlaceHolder = ` +
+ Agrupación de productos +
`; + +const wordsPlaceHolder = ` ++ Lista de atributos +
`; + +const products = document.querySelectorAll(".draggable"); +const zonesDrop = document.querySelectorAll(".dropzone"); + +const DATA_GRUPS = {}; + +products.forEach(manageDragables); +zonesDrop.forEach(manageDropZone); + + +/* +//// +////// +//////// Add new grups +////// +//// +*/ + +function addNewGrup() { + const container = document.getElementById("containers"); + const newGrup = document.createElement("section"); + const styles = "w-fit space-y-4 border rounded p-2 bg-surface-sweet"; + newGrup.classList.add(...styles.split(" ")); + + const formWord = document.getElementById("form-word"); + const formWordClone = formWord.cloneNode(true); + formWordClone.classList.remove("hidden"); + + newGrup.innerHTML = ` +| Producto | + {% for tester in data_groups.testers %} ++ Consumidor {{ forloop.counter }}: {{ tester }} + | + {% endfor %} +
|---|---|
| {{ data_words.codigo_producto }} + | + {% for tester in data_groups.testers %} ++ {% for word in data_words.palabras|get_item:tester %} + {{word}}{% if not forloop.last %} ;{% endif %} + {% endfor %} + | + {% endfor %} +
| Usuario | diff --git a/tecnicas/templates/tecnicas/components/table_pf.html b/tecnicas/templates/tecnicas/components/table_pf.html index 4f640fd4102293ed5d38365e86f622e3d49ebfb3..6a4bff6e25eefdd0f0ab5447fcdce4a7138208f4 100644 --- a/tecnicas/templates/tecnicas/components/table_pf.html +++ b/tecnicas/templates/tecnicas/components/table_pf.html @@ -5,7 +5,7 @@
|---|
| Repetición | diff --git a/tecnicas/templates/tecnicas/create_sesion/configuracion-panel-basic.html b/tecnicas/templates/tecnicas/create_sesion/conf-panel-basic.html similarity index 100% rename from tecnicas/templates/tecnicas/create_sesion/configuracion-panel-basic.html rename to tecnicas/templates/tecnicas/create_sesion/conf-panel-basic.html diff --git a/tecnicas/templates/tecnicas/create_sesion/configuracion-panel-codes.html b/tecnicas/templates/tecnicas/create_sesion/conf-panel-codes.html similarity index 100% rename from tecnicas/templates/tecnicas/create_sesion/configuracion-panel-codes.html rename to tecnicas/templates/tecnicas/create_sesion/conf-panel-codes.html diff --git a/tecnicas/templates/tecnicas/create_sesion/configuracion-panel-tags.html b/tecnicas/templates/tecnicas/create_sesion/conf-panel-tags.html similarity index 100% rename from tecnicas/templates/tecnicas/create_sesion/configuracion-panel-tags.html rename to tecnicas/templates/tecnicas/create_sesion/conf-panel-tags.html diff --git a/tecnicas/templates/tecnicas/create_sesion/configuracion-panel-words.html b/tecnicas/templates/tecnicas/create_sesion/conf-panel-words.html similarity index 100% rename from tecnicas/templates/tecnicas/create_sesion/configuracion-panel-words.html rename to tecnicas/templates/tecnicas/create_sesion/conf-panel-words.html diff --git a/tecnicas/templates/tecnicas/create_sesion/creando_sesion.html b/tecnicas/templates/tecnicas/create_sesion/creating_session.html similarity index 100% rename from tecnicas/templates/tecnicas/create_sesion/creando_sesion.html rename to tecnicas/templates/tecnicas/create_sesion/creating_session.html diff --git a/tecnicas/templates/tecnicas/create_sesion/panel-basic-napping.html b/tecnicas/templates/tecnicas/create_sesion/panel-basic-napping.html new file mode 100644 index 0000000000000000000000000000000000000000..dfcc30a68152cac87120fca90b5283ad483b7a36 --- /dev/null +++ b/tecnicas/templates/tecnicas/create_sesion/panel-basic-napping.html @@ -0,0 +1,71 @@ +{% extends 'tecnicas/layouts/base.html' %} +{% load static %} + +{% block title %}Panel Configuracion{% endblock %} + +{% block content %} +
|---|