Spaces:
Running
Running
Merge pull request #25 from CascoArcilla/HU9
Browse files- Dockerfile +35 -0
- docker-compose.yml +0 -0
- tecnicas/controllers/__init__.py +1 -0
- tecnicas/controllers/models_controller/calificacion_controller.py +42 -55
- tecnicas/controllers/models_controller/dato_controller.py +13 -14
- tecnicas/controllers/models_controller/particiapacion_controller.py +6 -9
- tecnicas/controllers/models_controller/sesion_controller.py +0 -8
- tecnicas/controllers/views_controller/api_rating_controller.py +6 -53
- tecnicas/controllers/views_controller/session_management/details_escala_controller.py +27 -12
- tecnicas/controllers/views_controller/session_management/monitor_controller.py +0 -4
- tecnicas/controllers/views_controller/session_management/monitor_escalas_controller.py +1 -1
- tecnicas/controllers/views_controller/sessions_tester/convencional_scales_controller.py +158 -0
- tecnicas/controllers/views_controller/sessions_tester/init_session_tester_controller.py +14 -8
- tecnicas/controllers/views_controller/sessions_tester/login_session_tester_controller.py +23 -23
- tecnicas/models/calificacion.py +4 -1
- tecnicas/models/dato.py +1 -1
- tecnicas/models/dato_valor.py +2 -2
- tecnicas/static/js/created-scale.js +2 -0
- tecnicas/templates/tecnicas/components/form-scale-continue.html +62 -0
- tecnicas/templates/tecnicas/components/form-scale-structure.html +52 -0
- tecnicas/templates/tecnicas/forms_tester/convencional.html +19 -128
- tecnicas/templates/tecnicas/forms_tester/init_session.html +1 -1
- tecnicas/templates/tecnicas/manage_sesions/detalles-sesion.html +12 -1
- tecnicas/utils/general_controllers.py +2 -2
- tecnicas/views/apis/rating_word.py +5 -4
- tecnicas/views/sessions_management/session_details.py +1 -1
- tecnicas/views/tester_forms/convencional_scales.py +15 -67
- tecnicas/views/tester_forms/init_tester_form.py +2 -5
Dockerfile
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM ubuntu:24.04
|
| 2 |
+
|
| 3 |
+
ENV DEBIAN_FRONTEND=noninteractive
|
| 4 |
+
|
| 5 |
+
RUN apt-get update && apt-get install -y \
|
| 6 |
+
build-essential \
|
| 7 |
+
libpq-dev \
|
| 8 |
+
python3 python3-dev python3-pip python3-venv \
|
| 9 |
+
gcc pkg-config \
|
| 10 |
+
default-libmysqlclient-dev \
|
| 11 |
+
nodejs npm \
|
| 12 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 13 |
+
|
| 14 |
+
WORKDIR /cata_system
|
| 15 |
+
|
| 16 |
+
RUN npm install -g pnpm
|
| 17 |
+
|
| 18 |
+
COPY requirements.txt .
|
| 19 |
+
|
| 20 |
+
RUN python3 -m venv /opt/venv
|
| 21 |
+
ENV PATH="/opt/venv/bin:$PATH"
|
| 22 |
+
|
| 23 |
+
RUN pip install --upgrade pip && \
|
| 24 |
+
pip install wheel && \
|
| 25 |
+
pip install -r requirements.txt
|
| 26 |
+
|
| 27 |
+
COPY . .
|
| 28 |
+
|
| 29 |
+
RUN python3 manage.py tailwind install
|
| 30 |
+
RUN python3 manage.py tailwind build
|
| 31 |
+
RUN python3 manage.py collectstatic --noinput
|
| 32 |
+
|
| 33 |
+
EXPOSE 7860
|
| 34 |
+
|
| 35 |
+
CMD ["python3", "manage.py", "runserver", "0.0.0.0:7860"]
|
docker-compose.yml
ADDED
|
File without changes
|
tecnicas/controllers/__init__.py
CHANGED
|
@@ -26,6 +26,7 @@ from .views_controller.session_management.monitor_escalas_controller import Moni
|
|
| 26 |
|
| 27 |
from .views_controller.sessions_tester.login_session_tester_controller import LoginSessionTesterController
|
| 28 |
from .views_controller.sessions_tester.init_session_tester_controller import InitSessionTesterController
|
|
|
|
| 29 |
|
| 30 |
from .views_controller.api_rating_controller import ApiRatingController
|
| 31 |
from .views_controller.tester_list_controller import TesterListController
|
|
|
|
| 26 |
|
| 27 |
from .views_controller.sessions_tester.login_session_tester_controller import LoginSessionTesterController
|
| 28 |
from .views_controller.sessions_tester.init_session_tester_controller import InitSessionTesterController
|
| 29 |
+
from .views_controller.sessions_tester.convencional_scales_controller import ConvencionalScalesController
|
| 30 |
|
| 31 |
from .views_controller.api_rating_controller import ApiRatingController
|
| 32 |
from .views_controller.tester_list_controller import TesterListController
|
tecnicas/controllers/models_controller/calificacion_controller.py
CHANGED
|
@@ -6,49 +6,22 @@ from tecnicas.utils import controller_error, getId
|
|
| 6 |
|
| 7 |
class CalificacionController():
|
| 8 |
def __init__(self, product: Producto | int, technique: Tecnica | int, tester: Catador | int):
|
|
|
|
|
|
|
|
|
|
| 9 |
atributes = {
|
| 10 |
-
"num_repeticion":
|
| 11 |
-
"
|
| 12 |
"id_producto_id": getId(product),
|
| 13 |
"id_catador_id": getId(tester),
|
| 14 |
}
|
| 15 |
|
| 16 |
-
self.rating = Calificacion(**atributes)
|
| 17 |
-
|
| 18 |
-
def validateRating(self):
|
| 19 |
-
try:
|
| 20 |
-
self.rating.clean()
|
| 21 |
-
return self.rating
|
| 22 |
-
except ValidationError as e:
|
| 23 |
-
return controller_error("No es posible validar la calificación")
|
| 24 |
-
|
| 25 |
-
def setRepetition(self, repetition: int = None) -> int | dict:
|
| 26 |
-
try:
|
| 27 |
-
if repetition is not None:
|
| 28 |
-
self.rating.num_repeticion = repetition
|
| 29 |
-
else:
|
| 30 |
-
self.rating.num_repeticion = self.rating.id_tecnica.repeticion
|
| 31 |
-
|
| 32 |
-
return self.rating.num_repeticion
|
| 33 |
-
except ValidationError as e:
|
| 34 |
-
return controller_error(e)
|
| 35 |
-
|
| 36 |
-
def saveRating(self):
|
| 37 |
-
try:
|
| 38 |
-
self.rating.save()
|
| 39 |
-
return self.rating
|
| 40 |
-
except ValidationError as e:
|
| 41 |
-
return controller_error(e)
|
| 42 |
|
| 43 |
@staticmethod
|
| 44 |
def getRatingsByTechnique(technique: Tecnica):
|
| 45 |
repetition = technique.repeticion
|
| 46 |
-
|
| 47 |
-
if not repetition:
|
| 48 |
-
return controller_error("Sin datos calificados aún")
|
| 49 |
-
|
| 50 |
ratings = list(Calificacion.objects.filter(id_tecnica=technique))
|
| 51 |
-
|
| 52 |
return ratings
|
| 53 |
|
| 54 |
@staticmethod
|
|
@@ -94,39 +67,53 @@ class CalificacionController():
|
|
| 94 |
return ratings
|
| 95 |
|
| 96 |
@staticmethod
|
| 97 |
-
def
|
| 98 |
positions: list[Posicion] = None,
|
| 99 |
-
user_cata: str = None,
|
| 100 |
repetition: int = None,
|
| 101 |
-
technique: Tecnica = None,
|
| 102 |
-
id_technique: int = None,
|
| 103 |
num_words: int = None):
|
| 104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
|
| 106 |
filters = {
|
| 107 |
-
"
|
| 108 |
-
"
|
| 109 |
}
|
| 110 |
|
| 111 |
-
if
|
| 112 |
-
filters["
|
| 113 |
-
|
| 114 |
-
filters["
|
|
|
|
| 115 |
|
| 116 |
-
ratings =
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
|
|
|
|
| 118 |
if len(ratings) == 0:
|
| 119 |
-
return positions
|
| 120 |
|
| 121 |
-
|
|
|
|
| 122 |
|
| 123 |
-
for
|
| 124 |
-
|
| 125 |
|
| 126 |
-
|
| 127 |
-
|
| 128 |
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
class CalificacionController():
|
| 8 |
def __init__(self, product: Producto | int, technique: Tecnica | int, tester: Catador | int):
|
| 9 |
+
technique = Tecnica.objects.only(
|
| 10 |
+
"repeticion").get(id=getId(technique))
|
| 11 |
+
|
| 12 |
atributes = {
|
| 13 |
+
"num_repeticion": technique.repeticion,
|
| 14 |
+
"id_tecnica": technique,
|
| 15 |
"id_producto_id": getId(product),
|
| 16 |
"id_catador_id": getId(tester),
|
| 17 |
}
|
| 18 |
|
| 19 |
+
(self.rating, created) = Calificacion.objects.get_or_create(**atributes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
@staticmethod
|
| 22 |
def getRatingsByTechnique(technique: Tecnica):
|
| 23 |
repetition = technique.repeticion
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
ratings = list(Calificacion.objects.filter(id_tecnica=technique))
|
|
|
|
| 25 |
return ratings
|
| 26 |
|
| 27 |
@staticmethod
|
|
|
|
| 67 |
return ratings
|
| 68 |
|
| 69 |
@staticmethod
|
| 70 |
+
def checkPositionWithoutRating(
|
| 71 |
positions: list[Posicion] = None,
|
| 72 |
+
user_cata: Catador | str = None,
|
| 73 |
repetition: int = None,
|
| 74 |
+
technique: Tecnica | int = None,
|
|
|
|
| 75 |
num_words: int = None):
|
| 76 |
+
end_rating = False
|
| 77 |
+
|
| 78 |
+
# Obtener lista con codigos de productos
|
| 79 |
+
check_products = [
|
| 80 |
+
position.id_producto.codigoProducto for position in positions]
|
| 81 |
|
| 82 |
filters = {
|
| 83 |
+
"num_repeticion": repetition,
|
| 84 |
+
"id_tecnica": getId(technique)
|
| 85 |
}
|
| 86 |
|
| 87 |
+
if isinstance(user_cata, Catador):
|
| 88 |
+
filters["id_catador"] = user_cata
|
| 89 |
+
else:
|
| 90 |
+
filters["id_catador"] = Catador.objects.get(
|
| 91 |
+
user__username=user_cata)
|
| 92 |
|
| 93 |
+
ratings = list(Calificacion.objects.filter(**filters).select_related(
|
| 94 |
+
"id_producto",
|
| 95 |
+
"id_tecnica",
|
| 96 |
+
"id_catador",
|
| 97 |
+
))
|
| 98 |
|
| 99 |
+
# Si no hay calificaciones regresar las posiciones
|
| 100 |
if len(ratings) == 0:
|
| 101 |
+
return (positions, end_rating)
|
| 102 |
|
| 103 |
+
rating_products = [
|
| 104 |
+
rating.id_producto.codigoProducto for rating in ratings]
|
| 105 |
|
| 106 |
+
for index, rating in enumerate(ratings):
|
| 107 |
+
data_rating = rating.dato_calificacion.all()
|
| 108 |
|
| 109 |
+
if len(data_rating) < num_words or len(data_rating) == 0:
|
| 110 |
+
return (positions[index], end_rating)
|
| 111 |
|
| 112 |
+
next_product = list(set(check_products) - set(rating_products))
|
| 113 |
+
if len(next_product) != 0:
|
| 114 |
+
next_position = [
|
| 115 |
+
position for position in positions if position.id_producto.codigoProducto == next_product[0]][0]
|
| 116 |
+
return (next_position, end_rating)
|
| 117 |
+
else:
|
| 118 |
+
end_rating = True
|
| 119 |
+
return (positions[-1], end_rating)
|
tecnicas/controllers/models_controller/dato_controller.py
CHANGED
|
@@ -12,7 +12,11 @@ class DatoController():
|
|
| 12 |
}
|
| 13 |
|
| 14 |
self.data = Dato(**atributes)
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
def setRating(self, new_rating: Calificacion):
|
| 18 |
try:
|
|
@@ -35,19 +39,14 @@ class DatoController():
|
|
| 35 |
except ValidationError as e:
|
| 36 |
return controller_error(e.message)
|
| 37 |
|
| 38 |
-
def
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
valor=self.value_data.valor
|
| 45 |
-
)
|
| 46 |
else:
|
| 47 |
-
self.value_data =
|
| 48 |
-
id_dato=self.data,
|
| 49 |
-
valor=self.value_data.valor
|
| 50 |
-
)
|
| 51 |
|
| 52 |
return self.value_data
|
| 53 |
|
|
@@ -88,7 +87,7 @@ class DatoController():
|
|
| 88 |
repeticion=F("id_dato__id_calificacion__num_repeticion"),
|
| 89 |
producto_code=F(
|
| 90 |
"id_dato__id_calificacion__id_producto__codigoProducto"),
|
| 91 |
-
|
| 92 |
"id_dato__id_calificacion__id_catador__user__username"),
|
| 93 |
dato_valor=F("valor")
|
| 94 |
)
|
|
|
|
| 12 |
}
|
| 13 |
|
| 14 |
self.data = Dato(**atributes)
|
| 15 |
+
|
| 16 |
+
if isinstance(value_rating, bool):
|
| 17 |
+
self.value_data = ValorBooleano(valor=value_rating)
|
| 18 |
+
else:
|
| 19 |
+
self.value_data = ValorDecimal(valor=value_rating)
|
| 20 |
|
| 21 |
def setRating(self, new_rating: Calificacion):
|
| 22 |
try:
|
|
|
|
| 39 |
except ValidationError as e:
|
| 40 |
return controller_error(e.message)
|
| 41 |
|
| 42 |
+
def setValue(self, new_value=None):
|
| 43 |
+
if new_value:
|
| 44 |
+
if isinstance(new_value, bool):
|
| 45 |
+
self.value_data = ValorBooleano(valor=new_value)
|
| 46 |
+
else:
|
| 47 |
+
self.value_data = ValorDecimal(valor=new_value)
|
|
|
|
|
|
|
| 48 |
else:
|
| 49 |
+
self.value_data.id_dato = self.data
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
return self.value_data
|
| 52 |
|
|
|
|
| 87 |
repeticion=F("id_dato__id_calificacion__num_repeticion"),
|
| 88 |
producto_code=F(
|
| 89 |
"id_dato__id_calificacion__id_producto__codigoProducto"),
|
| 90 |
+
usuario_catador=F(
|
| 91 |
"id_dato__id_calificacion__id_catador__user__username"),
|
| 92 |
dato_valor=F("valor")
|
| 93 |
)
|
tecnicas/controllers/models_controller/particiapacion_controller.py
CHANGED
|
@@ -16,15 +16,12 @@ class ParticipacionController():
|
|
| 16 |
return controller_error("No se ha encontrado la participación")
|
| 17 |
|
| 18 |
@staticmethod
|
| 19 |
-
def finishSession(
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
return participation
|
| 26 |
-
except Participacion.DoesNotExist:
|
| 27 |
-
return controller_error("No se ha encontrado la participación")
|
| 28 |
|
| 29 |
@staticmethod
|
| 30 |
def outSession(tester: Catador, session: SesionSensorial):
|
|
|
|
| 16 |
return controller_error("No se ha encontrado la participación")
|
| 17 |
|
| 18 |
@staticmethod
|
| 19 |
+
def finishSession(participation: Participacion):
|
| 20 |
+
participation.refresh_from_db()
|
| 21 |
+
participation.finalizado = True
|
| 22 |
+
participation.activo = False
|
| 23 |
+
participation.save()
|
| 24 |
+
return participation
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
@staticmethod
|
| 27 |
def outSession(tester: Catador, session: SesionSensorial):
|
tecnicas/controllers/models_controller/sesion_controller.py
CHANGED
|
@@ -131,14 +131,6 @@ class SesionController():
|
|
| 131 |
else:
|
| 132 |
use_session = session
|
| 133 |
|
| 134 |
-
(is_update_participations,
|
| 135 |
-
message) = ParticipacionController.outAllInSession(use_session)
|
| 136 |
-
|
| 137 |
-
if not is_update_participations:
|
| 138 |
-
return controller_error(message)
|
| 139 |
-
|
| 140 |
use_session.activo = False
|
| 141 |
-
|
| 142 |
use_session.save()
|
| 143 |
-
|
| 144 |
return session
|
|
|
|
| 131 |
else:
|
| 132 |
use_session = session
|
| 133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
use_session.activo = False
|
|
|
|
| 135 |
use_session.save()
|
|
|
|
| 136 |
return session
|
tecnicas/controllers/views_controller/api_rating_controller.py
CHANGED
|
@@ -7,65 +7,18 @@ class ApiRatingController():
|
|
| 7 |
self.rating_controller = rating_controller
|
| 8 |
self.data_controller = data_controller
|
| 9 |
|
| 10 |
-
def
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
return repetition
|
| 15 |
|
| 16 |
-
def saveRating(self):
|
| 17 |
-
rating = self.rating_controller.saveRating()
|
| 18 |
-
if isinstance(rating, dict):
|
| 19 |
-
return controller_error(rating["error"])
|
| 20 |
-
return rating
|
| 21 |
-
|
| 22 |
-
def setRatingInData(self):
|
| 23 |
-
update_rating = self.data_controller.setRating(
|
| 24 |
-
self.rating_controller.rating)
|
| 25 |
-
if isinstance(update_rating, dict):
|
| 26 |
-
return controller_error(update_rating["error"])
|
| 27 |
-
return update_rating
|
| 28 |
-
|
| 29 |
-
def saveData(self):
|
| 30 |
data = self.data_controller.saveData()
|
| 31 |
-
if isinstance(data, dict):
|
| 32 |
-
return controller_error(data["error"])
|
| 33 |
-
return data
|
| 34 |
-
|
| 35 |
-
def setValueRating(self):
|
| 36 |
-
self.data_controller.setInstanceValue()
|
| 37 |
-
|
| 38 |
-
def saveValue(self):
|
| 39 |
-
value = self.data_controller.saveValue()
|
| 40 |
-
if isinstance(value, dict):
|
| 41 |
-
return controller_error(value["error"])
|
| 42 |
-
|
| 43 |
-
def logicView(self) -> dict:
|
| 44 |
-
validate = self.rating_controller.validateRating()
|
| 45 |
-
if isinstance(validate, dict):
|
| 46 |
-
return controller_error(validate["error"])
|
| 47 |
-
|
| 48 |
-
reptition = self.setRating()
|
| 49 |
-
if isinstance(reptition, dict):
|
| 50 |
-
return controller_error(reptition["error"])
|
| 51 |
-
|
| 52 |
-
rating = self.saveRating()
|
| 53 |
-
if isinstance(rating, dict):
|
| 54 |
-
return controller_error(rating["error"])
|
| 55 |
-
|
| 56 |
-
rating_data = self.setRatingInData()
|
| 57 |
-
if isinstance(rating_data, dict):
|
| 58 |
-
return controller_error(rating_data["error"])
|
| 59 |
-
|
| 60 |
-
data = self.saveData()
|
| 61 |
if isinstance(data, dict):
|
| 62 |
return controller_error(data["error"])
|
| 63 |
|
| 64 |
-
|
| 65 |
-
if isinstance(value, dict):
|
| 66 |
-
return controller_error(value["error"])
|
| 67 |
|
| 68 |
-
value_save = self.saveValue()
|
| 69 |
if isinstance(value_save, dict):
|
| 70 |
return controller_error(value_save["error"])
|
| 71 |
|
|
|
|
| 7 |
self.rating_controller = rating_controller
|
| 8 |
self.data_controller = data_controller
|
| 9 |
|
| 10 |
+
def controllPostScales(self) -> dict:
|
| 11 |
+
self.data_controller.setRating(
|
| 12 |
+
new_rating=self.rating_controller.rating
|
| 13 |
+
)
|
|
|
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
data = self.data_controller.saveData()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
if isinstance(data, dict):
|
| 17 |
return controller_error(data["error"])
|
| 18 |
|
| 19 |
+
self.data_controller.setValue()
|
|
|
|
|
|
|
| 20 |
|
| 21 |
+
value_save = self.data_controller.saveValue()
|
| 22 |
if isinstance(value_save, dict):
|
| 23 |
return controller_error(value_save["error"])
|
| 24 |
|
tecnicas/controllers/views_controller/session_management/details_escala_controller.py
CHANGED
|
@@ -14,8 +14,8 @@ Encabezados de como deben de aparecer los datos juntos
|
|
| 14 |
from django.http import HttpRequest
|
| 15 |
from django.shortcuts import render, redirect
|
| 16 |
from django.urls import reverse
|
| 17 |
-
from tecnicas.models import SesionSensorial, Presentador,
|
| 18 |
-
from tecnicas.controllers import DatoController,
|
| 19 |
from .details_controller import DetallesController
|
| 20 |
from tecnicas.utils import defaultdict_to_dict, controller_error
|
| 21 |
from collections import defaultdict
|
|
@@ -34,7 +34,7 @@ class DetallesEscalasController(DetallesController):
|
|
| 34 |
context["error"] = error
|
| 35 |
if message != "" or message:
|
| 36 |
context["message"] = message
|
| 37 |
-
|
| 38 |
return render(
|
| 39 |
request, self.url_template, context)
|
| 40 |
|
|
@@ -43,16 +43,19 @@ class DetallesEscalasController(DetallesController):
|
|
| 43 |
"use_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 44 |
}
|
| 45 |
self.context["sesion"] = self.session
|
|
|
|
|
|
|
| 46 |
self.words = PalabrasController.getWordsInTechnique(
|
| 47 |
self.session.tecnica)
|
| 48 |
self.context["palabras"] = [word.nombre_palabra for word in self.words]
|
| 49 |
|
|
|
|
| 50 |
ratings_for_repetition = []
|
| 51 |
|
| 52 |
-
ratings =
|
| 53 |
-
|
| 54 |
|
| 55 |
-
if
|
| 56 |
self.context["calificaciones"] = ratings_for_repetition
|
| 57 |
self.context["existen_calificaciones"] = False
|
| 58 |
return self.context
|
|
@@ -64,7 +67,7 @@ class DetallesEscalasController(DetallesController):
|
|
| 64 |
lambda: defaultdict(lambda: defaultdict(list)))
|
| 65 |
|
| 66 |
for item in data:
|
| 67 |
-
user = item["
|
| 68 |
rep = item["repeticion"]
|
| 69 |
prod = item["producto_code"]
|
| 70 |
|
|
@@ -77,18 +80,30 @@ class DetallesEscalasController(DetallesController):
|
|
| 77 |
ratings_for_repetition)
|
| 78 |
self.context["existen_calificaciones"] = True
|
| 79 |
|
|
|
|
|
|
|
|
|
|
| 80 |
return self.context
|
| 81 |
|
| 82 |
-
def startRepetition(self, presenter: Presentador):
|
| 83 |
creator = presenter
|
| 84 |
technique = self.session.tecnica
|
| 85 |
|
| 86 |
if creator.user.username != self.session.creadoPor.user.username:
|
| 87 |
-
return self.getResponse(error="Solo el presentador que crea la sesión puede iniciar la repetición")
|
| 88 |
elif self.session.activo:
|
| 89 |
-
return self.getResponse(error="La sesión ya está activada")
|
| 90 |
-
elif technique.repeticion
|
| 91 |
-
return self.getResponse(error="Se ha alcanzado el número de repeticiones máxima")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
self.session.activo = True
|
| 94 |
technique.repeticion = technique.repeticion + 1
|
|
|
|
| 14 |
from django.http import HttpRequest
|
| 15 |
from django.shortcuts import render, redirect
|
| 16 |
from django.urls import reverse
|
| 17 |
+
from tecnicas.models import SesionSensorial, Presentador, Participacion, Calificacion
|
| 18 |
+
from tecnicas.controllers import DatoController, PalabrasController, ParticipacionController
|
| 19 |
from .details_controller import DetallesController
|
| 20 |
from tecnicas.utils import defaultdict_to_dict, controller_error
|
| 21 |
from collections import defaultdict
|
|
|
|
| 34 |
context["error"] = error
|
| 35 |
if message != "" or message:
|
| 36 |
context["message"] = message
|
| 37 |
+
|
| 38 |
return render(
|
| 39 |
request, self.url_template, context)
|
| 40 |
|
|
|
|
| 43 |
"use_technique": self.session.tecnica.tipo_tecnica.nombre_tecnica
|
| 44 |
}
|
| 45 |
self.context["sesion"] = self.session
|
| 46 |
+
|
| 47 |
+
# Recuperar la palabras de la tecnica
|
| 48 |
self.words = PalabrasController.getWordsInTechnique(
|
| 49 |
self.session.tecnica)
|
| 50 |
self.context["palabras"] = [word.nombre_palabra for word in self.words]
|
| 51 |
|
| 52 |
+
# Se recuperan las calificaciones
|
| 53 |
ratings_for_repetition = []
|
| 54 |
|
| 55 |
+
ratings = list(Calificacion.objects.filter(
|
| 56 |
+
id_tecnica=self.session.tecnica))
|
| 57 |
|
| 58 |
+
if not ratings:
|
| 59 |
self.context["calificaciones"] = ratings_for_repetition
|
| 60 |
self.context["existen_calificaciones"] = False
|
| 61 |
return self.context
|
|
|
|
| 67 |
lambda: defaultdict(lambda: defaultdict(list)))
|
| 68 |
|
| 69 |
for item in data:
|
| 70 |
+
user = item["usuario_catador"]
|
| 71 |
rep = item["repeticion"]
|
| 72 |
prod = item["producto_code"]
|
| 73 |
|
|
|
|
| 80 |
ratings_for_repetition)
|
| 81 |
self.context["existen_calificaciones"] = True
|
| 82 |
|
| 83 |
+
# Se comprueba que ya no se pueda iniciar la repeticion
|
| 84 |
+
self.context["fin_repeticiones"] = self.session.tecnica.repeticion >= self.session.tecnica.repeticiones_max
|
| 85 |
+
|
| 86 |
return self.context
|
| 87 |
|
| 88 |
+
def startRepetition(self, presenter: Presentador, request: HttpRequest):
|
| 89 |
creator = presenter
|
| 90 |
technique = self.session.tecnica
|
| 91 |
|
| 92 |
if creator.user.username != self.session.creadoPor.user.username:
|
| 93 |
+
return self.getResponse(error="Solo el presentador que crea la sesión puede iniciar la repetición", request=request)
|
| 94 |
elif self.session.activo:
|
| 95 |
+
return self.getResponse(error="La sesión ya está activada", request=request)
|
| 96 |
+
elif technique.repeticion >= technique.repeticiones_max:
|
| 97 |
+
return self.getResponse(error="Se ha alcanzado el número de repeticiones máxima", request=request)
|
| 98 |
+
|
| 99 |
+
there_participacions = Participacion.objects.filter(
|
| 100 |
+
tecnica=technique).exists()
|
| 101 |
+
|
| 102 |
+
if there_participacions:
|
| 103 |
+
(is_update_participations,
|
| 104 |
+
message) = ParticipacionController.outAllInSession(self.session)
|
| 105 |
+
if not is_update_participations:
|
| 106 |
+
return self.getResponse(error=message, request=request)
|
| 107 |
|
| 108 |
self.session.activo = True
|
| 109 |
technique.repeticion = technique.repeticion + 1
|
tecnicas/controllers/views_controller/session_management/monitor_controller.py
CHANGED
|
@@ -4,7 +4,3 @@ from tecnicas.models import SesionSensorial
|
|
| 4 |
class MonitorController():
|
| 5 |
def __init__(self, session: SesionSensorial):
|
| 6 |
self.sensorial_session = session
|
| 7 |
-
|
| 8 |
-
def updataSession(self):
|
| 9 |
-
self.sensorial_session = SesionSensorial.objects.get(
|
| 10 |
-
codigo_sesion=self.sensorial_session.codigo_sesion)
|
|
|
|
| 4 |
class MonitorController():
|
| 5 |
def __init__(self, session: SesionSensorial):
|
| 6 |
self.sensorial_session = session
|
|
|
|
|
|
|
|
|
|
|
|
tecnicas/controllers/views_controller/session_management/monitor_escalas_controller.py
CHANGED
|
@@ -89,5 +89,5 @@ class MonitorEscalasController(MonitorController):
|
|
| 89 |
response = SesionController.finishRepetion(self.sensorial_session)
|
| 90 |
if isinstance(response, dict):
|
| 91 |
return controller_error(response["error"])
|
| 92 |
-
self.
|
| 93 |
return self.sensorial_session
|
|
|
|
| 89 |
response = SesionController.finishRepetion(self.sensorial_session)
|
| 90 |
if isinstance(response, dict):
|
| 91 |
return controller_error(response["error"])
|
| 92 |
+
self.sensorial_session.refresh_from_db()
|
| 93 |
return self.sensorial_session
|
tecnicas/controllers/views_controller/sessions_tester/convencional_scales_controller.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.http import HttpRequest
|
| 2 |
+
from django.shortcuts import redirect, render
|
| 3 |
+
from django.urls import reverse
|
| 4 |
+
from tecnicas.models import SesionSensorial, Catador, Participacion, Producto, Calificacion, Palabra
|
| 5 |
+
from tecnicas.controllers import PosicionController, CalificacionController, ParticipacionController, PalabrasController, EscalaController, DatoController
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class ConvencionalScalesController:
|
| 9 |
+
context = {}
|
| 10 |
+
current_directory = "tecnicas/forms_tester/convencional.html"
|
| 11 |
+
previus_directory = "cata_system:catador_init_session"
|
| 12 |
+
|
| 13 |
+
def __init__(self, sensorial_session: SesionSensorial, user_tester: Catador):
|
| 14 |
+
self.tester = user_tester
|
| 15 |
+
self.session = sensorial_session
|
| 16 |
+
|
| 17 |
+
def controllGetEscalas(self, request: HttpRequest):
|
| 18 |
+
technique = self.session.tecnica
|
| 19 |
+
self.participation = Participacion.objects.get(
|
| 20 |
+
tecnica=technique, catador=request.user.user_catador)
|
| 21 |
+
|
| 22 |
+
ctx = self.context
|
| 23 |
+
ctx["session"] = self.session
|
| 24 |
+
|
| 25 |
+
# Obtener posiciones y palabras de la técnica
|
| 26 |
+
positions_in_order = PosicionController.getPostionsInOrder(
|
| 27 |
+
id_order=request.session["id_order"])
|
| 28 |
+
aligned_positions_in_order = sorted(
|
| 29 |
+
positions_in_order, key=lambda p: p.posicion)
|
| 30 |
+
words = PalabrasController.getWordsInTechnique(technique=technique)
|
| 31 |
+
|
| 32 |
+
# Comprobar siguiente posición sin calificar
|
| 33 |
+
(next_position, end_products) = CalificacionController.checkPositionWithoutRating(
|
| 34 |
+
positions=aligned_positions_in_order,
|
| 35 |
+
user_cata=request.user.user_catador,
|
| 36 |
+
repetition=technique.repeticion,
|
| 37 |
+
technique=technique,
|
| 38 |
+
num_words=len(words)
|
| 39 |
+
)
|
| 40 |
+
|
| 41 |
+
# Si no hay productos se finaliza la sesion
|
| 42 |
+
if end_products:
|
| 43 |
+
ParticipacionController.finishSession(self.participation)
|
| 44 |
+
params = {"code_sesion": self.session.codigo_sesion}
|
| 45 |
+
return redirect(reverse('cata_system:catador_init_session', kwargs=params))
|
| 46 |
+
|
| 47 |
+
# Si devuelve una lista, tomar el primer elemento
|
| 48 |
+
if isinstance(next_position, list):
|
| 49 |
+
next_position = next_position[0]
|
| 50 |
+
|
| 51 |
+
# Producto a calificar ahora
|
| 52 |
+
product = next_position.id_producto
|
| 53 |
+
ctx["product"] = product
|
| 54 |
+
|
| 55 |
+
# Revisar las palabras para calificar
|
| 56 |
+
try:
|
| 57 |
+
rating = Calificacion.objects.get(
|
| 58 |
+
num_repeticion=technique.repeticion,
|
| 59 |
+
id_producto=product,
|
| 60 |
+
id_tecnica=technique,
|
| 61 |
+
id_catador=self.tester
|
| 62 |
+
)
|
| 63 |
+
there_rating = True
|
| 64 |
+
except Calificacion.DoesNotExist:
|
| 65 |
+
there_rating = False
|
| 66 |
+
|
| 67 |
+
# Si no hay calificaciones previas, usar todas las palabras
|
| 68 |
+
if not there_rating:
|
| 69 |
+
ctx["words"] = words
|
| 70 |
+
else:
|
| 71 |
+
ratings_product = rating.dato_calificacion.all()
|
| 72 |
+
# Filtrar palabras que faltan
|
| 73 |
+
words_to_use = PalabrasController.getWordsWithoutData(
|
| 74 |
+
recoreded_data=ratings_product,
|
| 75 |
+
words=words
|
| 76 |
+
)
|
| 77 |
+
ctx["words"] = words_to_use
|
| 78 |
+
|
| 79 |
+
# Escala y etiquetas relacionadas
|
| 80 |
+
scale = EscalaController.getScaleByTechnique(technique=technique)
|
| 81 |
+
ctx["scale"] = scale
|
| 82 |
+
ctx["type_scale"] = scale.id_tipo_escala.nombre_escala
|
| 83 |
+
ctx["tags"] = EscalaController.getRelatedTagsInScale(scale=scale)
|
| 84 |
+
|
| 85 |
+
return render(request, self.current_directory, ctx)
|
| 86 |
+
|
| 87 |
+
def controllGetRATA(self, request: HttpRequest):
|
| 88 |
+
technique = self.session.tecnica
|
| 89 |
+
self.participation = Participacion.objects.get(
|
| 90 |
+
tecnica=technique, catador=request.user.user_catador)
|
| 91 |
+
|
| 92 |
+
self.context["session"] = self.session
|
| 93 |
+
|
| 94 |
+
products_in_technique = Producto.objects.filter(id_tecnica=technique)
|
| 95 |
+
|
| 96 |
+
words = PalabrasController.getWordsInTechnique(technique=technique)
|
| 97 |
+
|
| 98 |
+
use_product: Producto = None
|
| 99 |
+
use_words: list[Palabra] = None
|
| 100 |
+
|
| 101 |
+
# Revisamos el producto que le falten calificaciones
|
| 102 |
+
for current_product in products_in_technique:
|
| 103 |
+
try:
|
| 104 |
+
rating = Calificacion.objects.get(
|
| 105 |
+
num_repeticion=technique.repeticion,
|
| 106 |
+
id_producto=current_product,
|
| 107 |
+
id_tecnica=technique,
|
| 108 |
+
id_catador=self.tester
|
| 109 |
+
)
|
| 110 |
+
there_rating = True
|
| 111 |
+
except Calificacion.DoesNotExist:
|
| 112 |
+
there_rating = False
|
| 113 |
+
|
| 114 |
+
# Si no hay calificacion mandamos el producto actual y todas la palabras
|
| 115 |
+
if not there_rating:
|
| 116 |
+
use_product = current_product
|
| 117 |
+
use_words = words
|
| 118 |
+
break
|
| 119 |
+
|
| 120 |
+
# Obtener los datos asociados para la calificacion para ver que palabras quedan por calificar
|
| 121 |
+
recoreded_data = rating.dato_calificacion.all()
|
| 122 |
+
|
| 123 |
+
if not recoreded_data:
|
| 124 |
+
# Si no hay datos entonces devolver el producto con todas las palabras
|
| 125 |
+
use_product = current_product
|
| 126 |
+
use_words = words
|
| 127 |
+
break
|
| 128 |
+
else:
|
| 129 |
+
words_to_use = PalabrasController.getWordsWithoutData(
|
| 130 |
+
recoreded_data=recoreded_data, words=words)
|
| 131 |
+
|
| 132 |
+
# Si quedan palabras por calificar mandar las palabras con el producto
|
| 133 |
+
if not isinstance(words_to_use, dict) and words_to_use:
|
| 134 |
+
use_product = current_product
|
| 135 |
+
use_words = words_to_use
|
| 136 |
+
break
|
| 137 |
+
|
| 138 |
+
# Si no hay producto que falta por calificar finalizar sesion para el Catador
|
| 139 |
+
if not use_product:
|
| 140 |
+
updated_participation = ParticipacionController.finishSession(
|
| 141 |
+
self.participation)
|
| 142 |
+
params = {
|
| 143 |
+
"code_sesion": self.session.codigo_sesion
|
| 144 |
+
}
|
| 145 |
+
return redirect(reverse(self.previus_directory, kwargs=params))
|
| 146 |
+
|
| 147 |
+
self.context["product"] = use_product
|
| 148 |
+
self.context["words"] = use_words
|
| 149 |
+
|
| 150 |
+
# Agregar informacion de la escala
|
| 151 |
+
scale = EscalaController.getScaleByTechnique(technique=technique)
|
| 152 |
+
self.context["scale"] = scale
|
| 153 |
+
self.context["type_scale"] = scale.id_tipo_escala.nombre_escala
|
| 154 |
+
|
| 155 |
+
use_tags = EscalaController.getRelatedTagsInScale(scale=scale)
|
| 156 |
+
self.context["tags"] = use_tags
|
| 157 |
+
|
| 158 |
+
return render(request, self.current_directory, self.context)
|
tecnicas/controllers/views_controller/sessions_tester/init_session_tester_controller.py
CHANGED
|
@@ -2,7 +2,7 @@ from django.db import transaction
|
|
| 2 |
from django.http import HttpRequest
|
| 3 |
from django.shortcuts import render, redirect
|
| 4 |
from django.urls import reverse
|
| 5 |
-
from tecnicas.models import Catador, SesionSensorial, Orden, Participacion, Producto, EsAtributo, Calificacion, EsVocabulario
|
| 6 |
from tecnicas.controllers import ParticipacionController
|
| 7 |
from tecnicas.utils import controller_error, shuffleArray
|
| 8 |
|
|
@@ -37,6 +37,9 @@ class InitSessionTesterController():
|
|
| 37 |
if is_end:
|
| 38 |
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 39 |
|
|
|
|
|
|
|
|
|
|
| 40 |
return render(request, self.current_direction, context)
|
| 41 |
|
| 42 |
def controllPostEscalas(self, request: HttpRequest):
|
|
@@ -54,7 +57,7 @@ class InitSessionTesterController():
|
|
| 54 |
if is_end:
|
| 55 |
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 56 |
return render(request, self.current_direction, context)
|
| 57 |
-
|
| 58 |
update_participation = ParticipacionController.enterSession(
|
| 59 |
tester=request.user.user_catador, session=self.session)
|
| 60 |
if isinstance(update_participation, dict):
|
|
@@ -122,8 +125,8 @@ class InitSessionTesterController():
|
|
| 122 |
|
| 123 |
# ////////////////////////////////////////////////////////////// #
|
| 124 |
#
|
| 125 |
-
#
|
| 126 |
-
# Si
|
| 127 |
# Ha terminado la repeticion
|
| 128 |
#
|
| 129 |
# ////////////////////////////////////////////////////////////// #
|
|
@@ -137,17 +140,20 @@ class InitSessionTesterController():
|
|
| 137 |
|
| 138 |
num_words: int
|
| 139 |
|
| 140 |
-
if style_words
|
| 141 |
num_words = EsAtributo.objects.get(
|
| 142 |
id_tecnica=self.session.tecnica).palabras.count()
|
| 143 |
-
elif style_words
|
| 144 |
num_words = EsVocabulario.objects.get(
|
| 145 |
id_tecnica=self.session.tecnica).id_vocabulario.palabras.count()
|
| 146 |
|
| 147 |
expected_ratings_repetition = num_products * num_words
|
| 148 |
|
| 149 |
-
num_ratings_now =
|
| 150 |
-
|
|
|
|
|
|
|
|
|
|
| 151 |
|
| 152 |
is_end = num_ratings_now >= expected_ratings_repetition
|
| 153 |
|
|
|
|
| 2 |
from django.http import HttpRequest
|
| 3 |
from django.shortcuts import render, redirect
|
| 4 |
from django.urls import reverse
|
| 5 |
+
from tecnicas.models import Catador, SesionSensorial, Orden, Participacion, Producto, EsAtributo, Calificacion, EsVocabulario, Dato
|
| 6 |
from tecnicas.controllers import ParticipacionController
|
| 7 |
from tecnicas.utils import controller_error, shuffleArray
|
| 8 |
|
|
|
|
| 37 |
if is_end:
|
| 38 |
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 39 |
|
| 40 |
+
if "error" in request.GET:
|
| 41 |
+
context["error"] = request.GET["error"]
|
| 42 |
+
|
| 43 |
return render(request, self.current_direction, context)
|
| 44 |
|
| 45 |
def controllPostEscalas(self, request: HttpRequest):
|
|
|
|
| 57 |
if is_end:
|
| 58 |
context["message"] = "El catador ha terminado de realizar su evaluación, espere instrucciones del presentador"
|
| 59 |
return render(request, self.current_direction, context)
|
| 60 |
+
|
| 61 |
update_participation = ParticipacionController.enterSession(
|
| 62 |
tester=request.user.user_catador, session=self.session)
|
| 63 |
if isinstance(update_participation, dict):
|
|
|
|
| 125 |
|
| 126 |
# ////////////////////////////////////////////////////////////// #
|
| 127 |
#
|
| 128 |
+
# numero_datos_esperadas = num_productos * num_palabras
|
| 129 |
+
# Si numero_datos_esperadas es igual a numero_datos_actuales en la repetcion R
|
| 130 |
# Ha terminado la repeticion
|
| 131 |
#
|
| 132 |
# ////////////////////////////////////////////////////////////// #
|
|
|
|
| 140 |
|
| 141 |
num_words: int
|
| 142 |
|
| 143 |
+
if style_words == "atributos":
|
| 144 |
num_words = EsAtributo.objects.get(
|
| 145 |
id_tecnica=self.session.tecnica).palabras.count()
|
| 146 |
+
elif style_words == "vocabulario":
|
| 147 |
num_words = EsVocabulario.objects.get(
|
| 148 |
id_tecnica=self.session.tecnica).id_vocabulario.palabras.count()
|
| 149 |
|
| 150 |
expected_ratings_repetition = num_products * num_words
|
| 151 |
|
| 152 |
+
num_ratings_now = Dato.objects.filter(
|
| 153 |
+
id_calificacion__id_catador=self.tester,
|
| 154 |
+
id_calificacion__id_tecnica=technique,
|
| 155 |
+
id_calificacion__num_repeticion=technique.repeticion
|
| 156 |
+
).count()
|
| 157 |
|
| 158 |
is_end = num_ratings_now >= expected_ratings_repetition
|
| 159 |
|
tecnicas/controllers/views_controller/sessions_tester/login_session_tester_controller.py
CHANGED
|
@@ -33,38 +33,38 @@ class LoginSessionTesterController():
|
|
| 33 |
context["error"] = "La sesión no está activa actualmente"
|
| 34 |
return render(request, self.current_direcction, context)
|
| 35 |
|
| 36 |
-
if self.session.tecnica.repeticion
|
| 37 |
try:
|
| 38 |
self.taster_participation = Participacion.objects.get(
|
| 39 |
tecnica=self.session.tecnica, catador=self.tester)
|
| 40 |
context["error"] = "Usted ya esta dentro de la sesión"
|
| 41 |
return render(request, self.current_direcction, context)
|
| 42 |
except Participacion.DoesNotExist:
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
code_session = self.session.codigo_sesion
|
| 48 |
-
self.session = SesionSensorial.objects.select_for_update().get(
|
| 49 |
-
codigo_sesion=code_session)
|
| 50 |
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
|
|
|
|
|
|
|
|
|
| 68 |
|
| 69 |
def validateEntryRATA(self, request: HttpRequest):
|
| 70 |
context = {}
|
|
|
|
| 33 |
context["error"] = "La sesión no está activa actualmente"
|
| 34 |
return render(request, self.current_direcction, context)
|
| 35 |
|
| 36 |
+
if self.session.tecnica.repeticion == 1:
|
| 37 |
try:
|
| 38 |
self.taster_participation = Participacion.objects.get(
|
| 39 |
tecnica=self.session.tecnica, catador=self.tester)
|
| 40 |
context["error"] = "Usted ya esta dentro de la sesión"
|
| 41 |
return render(request, self.current_direcction, context)
|
| 42 |
except Participacion.DoesNotExist:
|
| 43 |
+
with transaction.atomic():
|
| 44 |
+
code_session = self.session.codigo_sesion
|
| 45 |
+
self.session = SesionSensorial.objects.select_for_update().get(
|
| 46 |
+
codigo_sesion=code_session)
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
+
max_testers = self.session.tecnica.limite_catadores
|
| 49 |
+
current_num_testers = Participacion.objects.filter(
|
| 50 |
+
tecnica=self.session.tecnica).count()
|
| 51 |
|
| 52 |
+
if current_num_testers >= max_testers:
|
| 53 |
+
context["error"] = "La sesión ha alcanzado el número máximo de catadores"
|
| 54 |
+
return render(request, self.current_direcction, context)
|
| 55 |
|
| 56 |
+
self.taster_participation = Participacion.objects.create(
|
| 57 |
+
tecnica=self.session.tecnica,
|
| 58 |
+
catador=self.tester,
|
| 59 |
+
finalizado=False
|
| 60 |
+
)
|
| 61 |
+
params = {
|
| 62 |
+
"code_sesion": self.session.codigo_sesion
|
| 63 |
+
}
|
| 64 |
+
return redirect(reverse(self.destinity_direcction, kwargs=params))
|
| 65 |
+
else:
|
| 66 |
+
context["error"] = "Ya no es posible ingresar a la sesión"
|
| 67 |
+
return render(request, self.current_direcction, context)
|
| 68 |
|
| 69 |
def validateEntryRATA(self, request: HttpRequest):
|
| 70 |
context = {}
|
tecnicas/models/calificacion.py
CHANGED
|
@@ -8,4 +8,7 @@ class Calificacion(models.Model):
|
|
| 8 |
num_repeticion = models.IntegerField()
|
| 9 |
id_producto = models.ForeignKey(Producto, on_delete=models.CASCADE, related_name="calificacion_producto")
|
| 10 |
id_tecnica = models.ForeignKey(Tecnica, on_delete=models.CASCADE, related_name="calificacion_tecnica")
|
| 11 |
-
id_catador = models.ForeignKey(Catador, on_delete=models.CASCADE, related_name="calificacion_catador")
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
num_repeticion = models.IntegerField()
|
| 9 |
id_producto = models.ForeignKey(Producto, on_delete=models.CASCADE, related_name="calificacion_producto")
|
| 10 |
id_tecnica = models.ForeignKey(Tecnica, on_delete=models.CASCADE, related_name="calificacion_tecnica")
|
| 11 |
+
id_catador = models.ForeignKey(Catador, on_delete=models.CASCADE, related_name="calificacion_catador")
|
| 12 |
+
|
| 13 |
+
def __str__(self):
|
| 14 |
+
return f"{self.id} - {self.id_tecnica.sesion_tecnica} - {self.num_repeticion} - {self.id_catador.user.username}"
|
tecnicas/models/dato.py
CHANGED
|
@@ -11,4 +11,4 @@ class Dato(models.Model):
|
|
| 11 |
Calificacion, on_delete=models.CASCADE, related_name="dato_calificacion")
|
| 12 |
|
| 13 |
def __str__(self):
|
| 14 |
-
return f"{self.id_palabra.nombre_palabra} - {self.id_calificacion.id_producto.codigoProducto} - {self.id_calificacion.id_catador.
|
|
|
|
| 11 |
Calificacion, on_delete=models.CASCADE, related_name="dato_calificacion")
|
| 12 |
|
| 13 |
def __str__(self):
|
| 14 |
+
return f"{self.id_calificacion.id_tecnica.sesion_tecnica}- {self.id_calificacion.num_repeticion} - {self.id_palabra.nombre_palabra} - {self.id_calificacion.id_producto.codigoProducto} - {self.id_calificacion.id_catador.user.username}"
|
tecnicas/models/dato_valor.py
CHANGED
|
@@ -9,7 +9,7 @@ class ValorDecimal(models.Model):
|
|
| 9 |
valor = models.FloatField()
|
| 10 |
|
| 11 |
def __str__(self):
|
| 12 |
-
return f"{self.id} - {self.id_dato.id_palabra}: {self.valor} - {self.id_dato.id_calificacion.id_catador.
|
| 13 |
|
| 14 |
|
| 15 |
class ValorBooleano(models.Model):
|
|
@@ -18,4 +18,4 @@ class ValorBooleano(models.Model):
|
|
| 18 |
valor = models.BooleanField()
|
| 19 |
|
| 20 |
def __str__(self):
|
| 21 |
-
return f"{self.id} - {self.id_dato.id_palabra}: {self.valor} - {self.id_dato.id_calificacion.id_catador.
|
|
|
|
| 9 |
valor = models.FloatField()
|
| 10 |
|
| 11 |
def __str__(self):
|
| 12 |
+
return f"{self.id} - {self.id_dato.id_palabra}: {self.valor} - {self.id_dato.id_calificacion.id_catador.user.username}"
|
| 13 |
|
| 14 |
|
| 15 |
class ValorBooleano(models.Model):
|
|
|
|
| 18 |
valor = models.BooleanField()
|
| 19 |
|
| 20 |
def __str__(self):
|
| 21 |
+
return f"{self.id} - {self.id_dato.id_palabra}: {self.valor} - {self.id_dato.id_calificacion.id_catador.user.username}"
|
tecnicas/static/js/created-scale.js
CHANGED
|
@@ -54,11 +54,13 @@ async function sendRating(word) {
|
|
| 54 |
.querySelector(".id-product").textContent;
|
| 55 |
|
| 56 |
const idWord = formRatingWord.querySelector(".id-word").textContent;
|
|
|
|
| 57 |
|
| 58 |
dataForm.set("code-product", codeProduct);
|
| 59 |
dataForm.set("id-product", idProduct);
|
| 60 |
dataForm.set("name-word", word);
|
| 61 |
dataForm.set("id-word", idWord);
|
|
|
|
| 62 |
|
| 63 |
try {
|
| 64 |
const respone = await fetch(url, {
|
|
|
|
| 54 |
.querySelector(".id-product").textContent;
|
| 55 |
|
| 56 |
const idWord = formRatingWord.querySelector(".id-word").textContent;
|
| 57 |
+
const idTechnique = document.querySelector(".ct-input-id-tech").value
|
| 58 |
|
| 59 |
dataForm.set("code-product", codeProduct);
|
| 60 |
dataForm.set("id-product", idProduct);
|
| 61 |
dataForm.set("name-word", word);
|
| 62 |
dataForm.set("id-word", idWord);
|
| 63 |
+
dataForm.set("id-technique", idTechnique);
|
| 64 |
|
| 65 |
try {
|
| 66 |
const respone = await fetch(url, {
|
tecnicas/templates/tecnicas/components/form-scale-continue.html
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<form action="" method="post" class="form-rating-{{word}} w-full">
|
| 2 |
+
{% csrf_token %}
|
| 3 |
+
<article class="overflow-x-scroll w-full">
|
| 4 |
+
<article class="bg-surface-card p-6 rounded-lg mb-3 w-fit">
|
| 5 |
+
<label for="id-range-word-{{word}}"
|
| 6 |
+
class="text-xl font-bold tracking-wide block mb-6 first-letter:uppercase">{{ word }}</label>
|
| 7 |
+
|
| 8 |
+
<span class="hidden id-word">{{ word.id }}</span>
|
| 9 |
+
|
| 10 |
+
<section class="block">
|
| 11 |
+
<div class="relative mx-6">
|
| 12 |
+
<input type="range" type="range" min="0" max="1000" value="500" name="rating-word"
|
| 13 |
+
class="range range-md text-blue-400 [--range-bg:orange] [--range-thumb:blue] [--range-fill:0]"
|
| 14 |
+
style="width: {{scale.longitud}}cm;">
|
| 15 |
+
|
| 16 |
+
<div class="absolute top-0 left-0 w-0.5 transform -translate-x-1/2 h-full bg-red-500 z-10">
|
| 17 |
+
</div>
|
| 18 |
+
|
| 19 |
+
<div class="absolute top-1/5 left-1/2 w-0.5 transform -translate-x-1/2 h-4/5 bg-red-500 z-10">
|
| 20 |
+
</div>
|
| 21 |
+
|
| 22 |
+
<div class="absolute top-0 right-0 w-0.5 transform -translate-x-1/2 h-full bg-red-500 z-10">
|
| 23 |
+
</div>
|
| 24 |
+
</div>
|
| 25 |
+
|
| 26 |
+
<div class="flex justify-between mt-4">
|
| 27 |
+
<div class="flex flex-col items-start text-left w-[100px]">
|
| 28 |
+
<span class="text-xs font-medium text-gray-700 break-words first-letter:capitalize">
|
| 29 |
+
{{ tags.0.id_etiqueta }}
|
| 30 |
+
</span>
|
| 31 |
+
</div>
|
| 32 |
+
<div class="flex flex-col items-start text-center w-[100px]">
|
| 33 |
+
<span class="text-xs font-medium text-gray-700 break-words first-letter:capitalize">
|
| 34 |
+
{{ tags.1.id_etiqueta }}
|
| 35 |
+
</span>
|
| 36 |
+
</div>
|
| 37 |
+
<div class="flex flex-col items-start text-right w-[100px]">
|
| 38 |
+
<span class="text-xs font-medium text-gray-700 break-words first-letter:capitalize">
|
| 39 |
+
{{ tags.2.id_etiqueta }}
|
| 40 |
+
</span>
|
| 41 |
+
</div>
|
| 42 |
+
</div>
|
| 43 |
+
</section>
|
| 44 |
+
</article>
|
| 45 |
+
</article>
|
| 46 |
+
<article class="flex flex-col justify-center gap-2 items-end actions-{{word}}">
|
| 47 |
+
<section class="flex justify-end items-center gap-2 btns-container">
|
| 48 |
+
<button type="button" onclick="checkSendRating('{{word}}')"
|
| 49 |
+
class="ct-btn-check-{{word}} cts-btn-general-compress py-2 px-4 cts-btn-secondary btn-push">
|
| 50 |
+
¿Guardar calificación?
|
| 51 |
+
</button>
|
| 52 |
+
<button type="button" onclick="sendRating('{{word}}')"
|
| 53 |
+
class="ct-btn-submit-{{word}} cts-btn-general-compress py-2 px-4 cts-btn-primary btn-push hidden">
|
| 54 |
+
Estoy seguro
|
| 55 |
+
</button>
|
| 56 |
+
<button type="button" onclick="cancelSendRating('{{word}}')"
|
| 57 |
+
class="ct-btn-cancel-{{word}} cts-btn-general-compress py-2 px-4 cts-btn-error btn-push hidden">
|
| 58 |
+
Cancelar
|
| 59 |
+
</button>
|
| 60 |
+
</section>
|
| 61 |
+
</article>
|
| 62 |
+
</form>
|
tecnicas/templates/tecnicas/components/form-scale-structure.html
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<form action="" method="post" class="form-rating-{{ word }} w-full">
|
| 2 |
+
{% csrf_token %}
|
| 3 |
+
<article class="overflow-x-scroll w-full">
|
| 4 |
+
<article class="bg-surface-card p-6 rounded-lg mb-3 w-fit">
|
| 5 |
+
<label for="id-scale-word-{{ word }}"
|
| 6 |
+
class="text-xl font-bold tracking-wide block mb-6 first-letter:uppercase">{{ word }}</label>
|
| 7 |
+
<span class="hidden id-word">{{ word.id }}</span>
|
| 8 |
+
|
| 9 |
+
<section>
|
| 10 |
+
<div class="w-full min-w-xs">
|
| 11 |
+
<div class="relative mx-6">
|
| 12 |
+
<input type="range" min="1" max="{{ scale.longitud }}" step="1" name="rating-word"
|
| 13 |
+
class="w-full range range-md text-blue-400 [--range-bg:orange] [--range-thumb:blue] [--range-fill:0] z-5">
|
| 14 |
+
<div class="absolute top-0 left-0 w-full h-full z-10 flex justify-between pointer-events-none">
|
| 15 |
+
{% for tag in tags %}
|
| 16 |
+
<div class="w-0.5 transform -translate-x-1/2 h-full bg-red-500">
|
| 17 |
+
</div>
|
| 18 |
+
{% endfor %}
|
| 19 |
+
</div>
|
| 20 |
+
</div>
|
| 21 |
+
|
| 22 |
+
<div class="flex justify-between mt-4 text-xs gap-1">
|
| 23 |
+
{% for tag in tags %}
|
| 24 |
+
<div class="flex items-center justify-center text-center w-[70px]">
|
| 25 |
+
<span class="text-xs font-medium text-gray-700 break-words first-letter:capitalize">
|
| 26 |
+
{{ tag.id_etiqueta }}
|
| 27 |
+
</span>
|
| 28 |
+
</div>
|
| 29 |
+
{% endfor %}
|
| 30 |
+
</div>
|
| 31 |
+
</div>
|
| 32 |
+
</section>
|
| 33 |
+
</article>
|
| 34 |
+
</article>
|
| 35 |
+
|
| 36 |
+
<article class="flex flex-col justify-center gap-2 items-end actions-{{ word }}">
|
| 37 |
+
<section class="flex justify-end items-center gap-2 btns-container">
|
| 38 |
+
<button type="button" onclick="checkSendRating('{{ word }}')"
|
| 39 |
+
class="ct-btn-check-{{ word }} cts-btn-general-compress py-2 px-4 cts-btn-secondary btn-push">
|
| 40 |
+
¿Guardar calificación?
|
| 41 |
+
</button>
|
| 42 |
+
<button type="button" onclick="sendRating('{{ word }}')"
|
| 43 |
+
class="ct-btn-submit-{{ word }} cts-btn-general-compress py-2 px-4 cts-btn-primary btn-push hidden">
|
| 44 |
+
Estoy seguro
|
| 45 |
+
</button>
|
| 46 |
+
<button type="button" onclick="cancelSendRating('{{ word }}')"
|
| 47 |
+
class="ct-btn-cancel-{{ word }} cts-btn-general-compress py-2 px-4 cts-btn-error btn-push hidden">
|
| 48 |
+
Cancelar
|
| 49 |
+
</button>
|
| 50 |
+
</section>
|
| 51 |
+
</article>
|
| 52 |
+
</form>
|
tecnicas/templates/tecnicas/forms_tester/convencional.html
CHANGED
|
@@ -37,7 +37,8 @@
|
|
| 37 |
<article class="cts-wrap-content text-black">
|
| 38 |
<header class="text-center flex-row w-full items-stretch flex justify-around flex-wrap gap-2">
|
| 39 |
<h1 class="rounded font-bold text-2xl bg-surface-ligt p-4 flex-1">
|
| 40 |
-
Sesión usando <br>técnica
|
|
|
|
| 41 |
</h1>
|
| 42 |
<button class="cts-btn-general cts-btn-error btn-push" onclick="exit_sesion('form-actions')">
|
| 43 |
Salir de la sesión
|
|
@@ -45,12 +46,17 @@
|
|
| 45 |
</header>
|
| 46 |
|
| 47 |
<article class="hidden">
|
| 48 |
-
<form action="{% url 'cata_system:catador_init_session' code_sesion=session.codigo_sesion %}" method="post"
|
|
|
|
| 49 |
{% csrf_token %}
|
| 50 |
<input type="hidden" name="action" class="action-input">
|
| 51 |
</form>
|
| 52 |
</article>
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
{% if error %}
|
| 55 |
<hr>
|
| 56 |
<article class="bg-red-600 p-4 text-white rounded-xl ct-notification-error">
|
|
@@ -95,132 +101,17 @@
|
|
| 95 |
|
| 96 |
<article
|
| 97 |
class="scales-container [&>*:not(:last-child)]:mb-5 min-lg:grid min-lg:items-start grid-cols-2 gap-3 justify-center items-center">
|
| 98 |
-
{%
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
<section class="block">
|
| 110 |
-
<div class="relative mx-6">
|
| 111 |
-
<input type="range" type="range" min="0" max="1000" value="500" name="rating-word"
|
| 112 |
-
class="range range-md text-blue-400 [--range-bg:orange] [--range-thumb:blue] [--range-fill:0]"
|
| 113 |
-
style="width: {{scale.longitud}}cm;">
|
| 114 |
-
|
| 115 |
-
<div
|
| 116 |
-
class="absolute top-0 left-0 w-0.5 transform -translate-x-1/2 h-full bg-red-500 z-10">
|
| 117 |
-
</div>
|
| 118 |
-
|
| 119 |
-
<div
|
| 120 |
-
class="absolute top-1/5 left-1/2 w-0.5 transform -translate-x-1/2 h-4/5 bg-red-500 z-10">
|
| 121 |
-
</div>
|
| 122 |
-
|
| 123 |
-
<div
|
| 124 |
-
class="absolute top-0 right-0 w-0.5 transform -translate-x-1/2 h-full bg-red-500 z-10">
|
| 125 |
-
</div>
|
| 126 |
-
</div>
|
| 127 |
-
|
| 128 |
-
<div class="flex justify-between mt-4">
|
| 129 |
-
<div class="flex flex-col items-start text-left w-[100px]">
|
| 130 |
-
<span class="text-xs font-medium text-gray-700 break-words first-letter:capitalize">
|
| 131 |
-
{{ tags.0.id_etiqueta }}
|
| 132 |
-
</span>
|
| 133 |
-
</div>
|
| 134 |
-
<div class="flex flex-col items-start text-center w-[100px]">
|
| 135 |
-
<span class="text-xs font-medium text-gray-700 break-words first-letter:capitalize">
|
| 136 |
-
{{ tags.1.id_etiqueta }}
|
| 137 |
-
</span>
|
| 138 |
-
</div>
|
| 139 |
-
<div class="flex flex-col items-start text-right w-[100px]">
|
| 140 |
-
<span class="text-xs font-medium text-gray-700 break-words first-letter:capitalize">
|
| 141 |
-
{{ tags.2.id_etiqueta }}
|
| 142 |
-
</span>
|
| 143 |
-
</div>
|
| 144 |
-
</div>
|
| 145 |
-
</section>
|
| 146 |
-
</article>
|
| 147 |
-
</article>
|
| 148 |
-
<article class="flex flex-col justify-center gap-2 items-end actions-{{word}}">
|
| 149 |
-
<section class="flex justify-end items-center gap-2 btns-container">
|
| 150 |
-
<button type="button" onclick="checkSendRating('{{word}}')"
|
| 151 |
-
class="ct-btn-check-{{word}} cts-btn-general-compress py-2 px-4 cts-btn-secondary btn-push">
|
| 152 |
-
¿Guardar calificación?
|
| 153 |
-
</button>
|
| 154 |
-
<button type="button" onclick="sendRating('{{word}}')"
|
| 155 |
-
class="ct-btn-submit-{{word}} cts-btn-general-compress py-2 px-4 cts-btn-primary btn-push hidden">
|
| 156 |
-
Estoy seguro
|
| 157 |
-
</button>
|
| 158 |
-
<button type="button" onclick="cancelSendRating('{{word}}')"
|
| 159 |
-
class="ct-btn-cancel-{{word}} cts-btn-general-compress py-2 px-4 cts-btn-error btn-push hidden">
|
| 160 |
-
Cancelar
|
| 161 |
-
</button>
|
| 162 |
-
</section>
|
| 163 |
-
</article>
|
| 164 |
-
</form>
|
| 165 |
-
{% endfor %}
|
| 166 |
-
{% elif type_scale == "estructurada" %}
|
| 167 |
-
{% for word in words %}
|
| 168 |
-
<form action="" method="post" class="form-rating-{{ word }} w-full">
|
| 169 |
-
{% csrf_token %}
|
| 170 |
-
<article class="overflow-x-scroll w-full">
|
| 171 |
-
<article class="bg-surface-card p-6 rounded-lg mb-3 w-fit">
|
| 172 |
-
<label for="id-scale-word-{{ word }}"
|
| 173 |
-
class="text-xl font-bold tracking-wide block mb-6 first-letter:uppercase">{{ word }}</label>
|
| 174 |
-
<span class="hidden id-word">{{ word.id }}</span>
|
| 175 |
-
|
| 176 |
-
<section>
|
| 177 |
-
<div class="w-full min-w-xs">
|
| 178 |
-
<div class="relative mx-6">
|
| 179 |
-
<input type="range" min="1" max="{{scale.longitud}}" step="1" name="rating-word"
|
| 180 |
-
class="w-full range range-md text-blue-400 [--range-bg:orange] [--range-thumb:blue] [--range-fill:0] z-5">
|
| 181 |
-
<div
|
| 182 |
-
class="absolute top-0 left-0 w-full h-full z-10 flex justify-between pointer-events-none">
|
| 183 |
-
{% for tag in tags %}
|
| 184 |
-
<div class="w-0.5 transform -translate-x-1/2 h-full bg-red-500">
|
| 185 |
-
</div>
|
| 186 |
-
{% endfor %}
|
| 187 |
-
</div>
|
| 188 |
-
</div>
|
| 189 |
-
|
| 190 |
-
<div class="flex justify-between mt-4 text-xs gap-1">
|
| 191 |
-
{% for tag in tags %}
|
| 192 |
-
<div class="flex items-center justify-center text-center w-[70px]">
|
| 193 |
-
<span
|
| 194 |
-
class="text-xs font-medium text-gray-700 break-words first-letter:capitalize">
|
| 195 |
-
{{ tag.id_etiqueta }}
|
| 196 |
-
</span>
|
| 197 |
-
</div>
|
| 198 |
-
{% endfor %}
|
| 199 |
-
</div>
|
| 200 |
-
</div>
|
| 201 |
-
</section>
|
| 202 |
-
</article>
|
| 203 |
-
</article>
|
| 204 |
-
|
| 205 |
-
<article class="flex flex-col justify-center gap-2 items-end actions-{{ word }}">
|
| 206 |
-
<section class="flex justify-end items-center gap-2 btns-container">
|
| 207 |
-
<button type="button" onclick="checkSendRating('{{ word }}')"
|
| 208 |
-
class="ct-btn-check-{{ word }} cts-btn-general-compress py-2 px-4 cts-btn-secondary btn-push">
|
| 209 |
-
¿Guardar calificación?
|
| 210 |
-
</button>
|
| 211 |
-
<button type="button" onclick="sendRating('{{ word }}')"
|
| 212 |
-
class="ct-btn-submit-{{ word }} cts-btn-general-compress py-2 px-4 cts-btn-primary btn-push hidden">
|
| 213 |
-
Estoy seguro
|
| 214 |
-
</button>
|
| 215 |
-
<button type="button" onclick="cancelSendRating('{{ word }}')"
|
| 216 |
-
class="ct-btn-cancel-{{ word }} cts-btn-general-compress py-2 px-4 cts-btn-error btn-push hidden">
|
| 217 |
-
Cancelar
|
| 218 |
-
</button>
|
| 219 |
-
</section>
|
| 220 |
-
</article>
|
| 221 |
-
</form>
|
| 222 |
-
{% endfor %}
|
| 223 |
-
{% endif %}
|
| 224 |
</article>
|
| 225 |
</article>
|
| 226 |
</article>
|
|
|
|
| 37 |
<article class="cts-wrap-content text-black">
|
| 38 |
<header class="text-center flex-row w-full items-stretch flex justify-around flex-wrap gap-2">
|
| 39 |
<h1 class="rounded font-bold text-2xl bg-surface-ligt p-4 flex-1">
|
| 40 |
+
Sesión usando <br>técnica
|
| 41 |
+
<span class="uppercase">{{ session.tecnica.tipo_tecnica }}</span>
|
| 42 |
</h1>
|
| 43 |
<button class="cts-btn-general cts-btn-error btn-push" onclick="exit_sesion('form-actions')">
|
| 44 |
Salir de la sesión
|
|
|
|
| 46 |
</header>
|
| 47 |
|
| 48 |
<article class="hidden">
|
| 49 |
+
<form action="{% url 'cata_system:catador_init_session' code_sesion=session.codigo_sesion %}" method="post"
|
| 50 |
+
class="form-actions">
|
| 51 |
{% csrf_token %}
|
| 52 |
<input type="hidden" name="action" class="action-input">
|
| 53 |
</form>
|
| 54 |
</article>
|
| 55 |
|
| 56 |
+
<section class="hidden">
|
| 57 |
+
<input type="hidden" value="{{ session.tecnica.id }}" name="id-tecnica" class="ct-input-id-tech">
|
| 58 |
+
</section>
|
| 59 |
+
|
| 60 |
{% if error %}
|
| 61 |
<hr>
|
| 62 |
<article class="bg-red-600 p-4 text-white rounded-xl ct-notification-error">
|
|
|
|
| 101 |
|
| 102 |
<article
|
| 103 |
class="scales-container [&>*:not(:last-child)]:mb-5 min-lg:grid min-lg:items-start grid-cols-2 gap-3 justify-center items-center">
|
| 104 |
+
{% with path_con="../components/form-scale-continue.html" path_str="../components/form-scale-structure.html" %}
|
| 105 |
+
{% if type_scale == "continua" %}
|
| 106 |
+
{% for word in words %}
|
| 107 |
+
{% include path_con with word=word tags=tags scale=scale id_tecnica=session.tecnica.id %}
|
| 108 |
+
{% endfor %}
|
| 109 |
+
{% elif type_scale == "estructurada" %}
|
| 110 |
+
{% for word in words %}
|
| 111 |
+
{% include path_str with word=word tags=tags scale=scale %}
|
| 112 |
+
{% endfor %}
|
| 113 |
+
{% endif %}
|
| 114 |
+
{% endwith %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
</article>
|
| 116 |
</article>
|
| 117 |
</article>
|
tecnicas/templates/tecnicas/forms_tester/init_session.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
| 5 |
|
| 6 |
{% block content %}
|
| 7 |
<article class="cts-container-main">
|
| 8 |
-
<article class="cts-wrap-content text-black">
|
| 9 |
<header class="text-center flex-row w-full flex justify-around items-center flex-wrap gap-10">
|
| 10 |
<h1 class="rounded-xl font-bold text-2xl bg-surface-ligt p-4 flex-1">
|
| 11 |
Panel principal de Catadores
|
|
|
|
| 5 |
|
| 6 |
{% block content %}
|
| 7 |
<article class="cts-container-main">
|
| 8 |
+
<article class="cts-wrap-content text-black max-w-4xl">
|
| 9 |
<header class="text-center flex-row w-full flex justify-around items-center flex-wrap gap-10">
|
| 10 |
<h1 class="rounded-xl font-bold text-2xl bg-surface-ligt p-4 flex-1">
|
| 11 |
Panel principal de Catadores
|
tecnicas/templates/tecnicas/manage_sesions/detalles-sesion.html
CHANGED
|
@@ -181,6 +181,14 @@
|
|
| 181 |
</p>
|
| 182 |
<article class="flex flex-wrap gap-10 max-sm:gap-2">
|
| 183 |
{% if not sesion.activo %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
<button
|
| 185 |
class="ct-btn-start-repition flex-1 uppercase text-lg max-sm:text-base tracking-wider p-4 border-b-2 active:border-b-0 active:border-t-2 active:border-green-500 border-green-800 transition-all rounded-xl bg-green-600 text-white font-bold disabled:bg-amber-600 flex flex-col justify-center items-center gap-2"
|
| 186 |
onclick="startRepetition()">
|
|
@@ -189,6 +197,7 @@
|
|
| 189 |
<img src="{% static 'img/giro.svg' %}" alt="flechas girando" class="invert">
|
| 190 |
</figure>
|
| 191 |
</button>
|
|
|
|
| 192 |
{% else %}
|
| 193 |
<a href="{% url 'cata_system:monitor_sesion' session_code=sesion.codigo_sesion %}" class="flex-1 w-fit">
|
| 194 |
<button
|
|
@@ -243,9 +252,11 @@
|
|
| 243 |
|
| 244 |
{% if existen_calificaciones %}
|
| 245 |
<article class="bg-surface-card p-4 max-sm:px-2 text-black rounded">
|
|
|
|
| 246 |
{% for repeticion, catadores in calificaciones.items %}
|
| 247 |
-
{% include
|
| 248 |
{% endfor %}
|
|
|
|
| 249 |
</article>
|
| 250 |
{% else %}
|
| 251 |
{% include "../components/error-message.html" with message='Sin calificaciones que mostrar aún' %}
|
|
|
|
| 181 |
</p>
|
| 182 |
<article class="flex flex-wrap gap-10 max-sm:gap-2">
|
| 183 |
{% if not sesion.activo %}
|
| 184 |
+
{% if fin_repeticiones %}
|
| 185 |
+
<div
|
| 186 |
+
class="text-2xl font-semibold flex-1 cts-btn-secondary p-4 flex justify-center items-center rounded-lg select-none text-center">
|
| 187 |
+
<p class=" text-black">
|
| 188 |
+
Máximo número de repeticiones alcanzado
|
| 189 |
+
</p>
|
| 190 |
+
</div>
|
| 191 |
+
{% else %}
|
| 192 |
<button
|
| 193 |
class="ct-btn-start-repition flex-1 uppercase text-lg max-sm:text-base tracking-wider p-4 border-b-2 active:border-b-0 active:border-t-2 active:border-green-500 border-green-800 transition-all rounded-xl bg-green-600 text-white font-bold disabled:bg-amber-600 flex flex-col justify-center items-center gap-2"
|
| 194 |
onclick="startRepetition()">
|
|
|
|
| 197 |
<img src="{% static 'img/giro.svg' %}" alt="flechas girando" class="invert">
|
| 198 |
</figure>
|
| 199 |
</button>
|
| 200 |
+
{% endif %}
|
| 201 |
{% else %}
|
| 202 |
<a href="{% url 'cata_system:monitor_sesion' session_code=sesion.codigo_sesion %}" class="flex-1 w-fit">
|
| 203 |
<button
|
|
|
|
| 252 |
|
| 253 |
{% if existen_calificaciones %}
|
| 254 |
<article class="bg-surface-card p-4 max-sm:px-2 text-black rounded">
|
| 255 |
+
{% with url_component="../components/table-convencional.html" %}
|
| 256 |
{% for repeticion, catadores in calificaciones.items %}
|
| 257 |
+
{% include url_component with repeticion=repeticion catadores=catadores palabras=palabras %}
|
| 258 |
{% endfor %}
|
| 259 |
+
{% endwith %}
|
| 260 |
</article>
|
| 261 |
{% else %}
|
| 262 |
{% include "../components/error-message.html" with message='Sin calificaciones que mostrar aún' %}
|
tecnicas/utils/general_controllers.py
CHANGED
|
@@ -17,7 +17,7 @@ def getId(value: object | int) -> int | None:
|
|
| 17 |
def noValidTechnique(params: dict, query_params: dict, name_view: str):
|
| 18 |
if query_params:
|
| 19 |
query_string = urlencode(query_params)
|
| 20 |
-
url_redireccion = f"{reverse(
|
| 21 |
else:
|
| 22 |
-
url_redireccion = f"{reverse(
|
| 23 |
return redirect(url_redireccion)
|
|
|
|
| 17 |
def noValidTechnique(params: dict, query_params: dict, name_view: str):
|
| 18 |
if query_params:
|
| 19 |
query_string = urlencode(query_params)
|
| 20 |
+
url_redireccion = f"{reverse(name_view, kwargs=params)}?{query_string}"
|
| 21 |
else:
|
| 22 |
+
url_redireccion = f"{reverse(name_view, kwargs=params)}"
|
| 23 |
return redirect(url_redireccion)
|
tecnicas/views/apis/rating_word.py
CHANGED
|
@@ -28,8 +28,8 @@
|
|
| 28 |
* Calquier otro metodo que se maneje mandar un error
|
| 29 |
'''
|
| 30 |
from django.http import HttpRequest, JsonResponse
|
| 31 |
-
from
|
| 32 |
-
from
|
| 33 |
import json
|
| 34 |
|
| 35 |
|
|
@@ -41,10 +41,11 @@ def reatingWord(req: HttpRequest):
|
|
| 41 |
received_rating = json.loads(req.POST.get("rating-word"))
|
| 42 |
received_id_word = json.loads(req.POST.get("id-word"))
|
| 43 |
received_id_product = json.loads(req.POST.get("id-product"))
|
|
|
|
| 44 |
|
| 45 |
view_controller = ApiRatingController(
|
| 46 |
rating_controller=CalificacionController(
|
| 47 |
-
technique=
|
| 48 |
product=received_id_product,
|
| 49 |
tester=req.user.user_catador
|
| 50 |
),
|
|
@@ -55,7 +56,7 @@ def reatingWord(req: HttpRequest):
|
|
| 55 |
)
|
| 56 |
)
|
| 57 |
|
| 58 |
-
response_data = view_controller.
|
| 59 |
|
| 60 |
return JsonResponse(response_data)
|
| 61 |
else:
|
|
|
|
| 28 |
* Calquier otro metodo que se maneje mandar un error
|
| 29 |
'''
|
| 30 |
from django.http import HttpRequest, JsonResponse
|
| 31 |
+
from tecnicas.controllers import ApiRatingController, CalificacionController, DatoController
|
| 32 |
+
from tecnicas.utils import general_error
|
| 33 |
import json
|
| 34 |
|
| 35 |
|
|
|
|
| 41 |
received_rating = json.loads(req.POST.get("rating-word"))
|
| 42 |
received_id_word = json.loads(req.POST.get("id-word"))
|
| 43 |
received_id_product = json.loads(req.POST.get("id-product"))
|
| 44 |
+
id_technique = json.loads(req.POST.get("id-technique"))
|
| 45 |
|
| 46 |
view_controller = ApiRatingController(
|
| 47 |
rating_controller=CalificacionController(
|
| 48 |
+
technique=id_technique,
|
| 49 |
product=received_id_product,
|
| 50 |
tester=req.user.user_catador
|
| 51 |
),
|
|
|
|
| 56 |
)
|
| 57 |
)
|
| 58 |
|
| 59 |
+
response_data = view_controller.controllPostScales()
|
| 60 |
|
| 61 |
return JsonResponse(response_data)
|
| 62 |
else:
|
tecnicas/views/sessions_management/session_details.py
CHANGED
|
@@ -42,7 +42,7 @@ def sessionDetails(req: HttpRequest, session_code: str):
|
|
| 42 |
|
| 43 |
if req.POST["action"] == "start_session":
|
| 44 |
response = controller_view.startRepetition(
|
| 45 |
-
presenter=req.user.user_presentador)
|
| 46 |
elif req.POST.get("action") == "delete_session":
|
| 47 |
controller_view.deleteSesorialSession()
|
| 48 |
response = redirect(
|
|
|
|
| 42 |
|
| 43 |
if req.POST["action"] == "start_session":
|
| 44 |
response = controller_view.startRepetition(
|
| 45 |
+
presenter=req.user.user_presentador, request=req)
|
| 46 |
elif req.POST.get("action") == "delete_session":
|
| 47 |
controller_view.deleteSesorialSession()
|
| 48 |
response = redirect(
|
tecnicas/views/tester_forms/convencional_scales.py
CHANGED
|
@@ -55,78 +55,26 @@
|
|
| 55 |
- Cata segmento en el que se divide debe tener la etiqueda correspondiente por debajo
|
| 56 |
'''
|
| 57 |
from django.http import HttpRequest
|
| 58 |
-
from
|
| 59 |
-
from
|
| 60 |
-
from ...controllers import SesionController, PosicionController, CalificacionController, ParticipacionController, PalabrasController, EscalaController, DatoController
|
| 61 |
|
| 62 |
|
| 63 |
def convencionalScales(req: HttpRequest, code_sesion: str):
|
| 64 |
-
if not "id_order" in req.session:
|
| 65 |
-
return redirect(reverse("cata_system:catador_main"))
|
| 66 |
-
|
| 67 |
session = SesionController.getSessionByCode(code_sesion)
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
context = {
|
| 71 |
-
"session": session
|
| 72 |
-
}
|
| 73 |
-
|
| 74 |
-
req.session["id_technique"] = session.tecnica.id
|
| 75 |
|
| 76 |
if req.method == "GET":
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
next_position = CalificacionController.checkProducsWithoutRating(
|
| 85 |
-
positions=sorted_positions,
|
| 86 |
-
user_cata=req.user.username,
|
| 87 |
-
id_technique=session.tecnica.id,
|
| 88 |
-
repetition=session.tecnica.repeticion,
|
| 89 |
-
technique=technique,
|
| 90 |
-
num_words=len(words)
|
| 91 |
-
)
|
| 92 |
-
|
| 93 |
-
if isinstance(next_position, dict):
|
| 94 |
-
updated_participation = ParticipacionController.finishSession(
|
| 95 |
-
req.session["id_participation"])
|
| 96 |
-
return redirect(reverse("cata_system:catador_main"))
|
| 97 |
-
|
| 98 |
-
if isinstance(next_position, list):
|
| 99 |
-
next_position = next_position[0]
|
| 100 |
-
|
| 101 |
-
context["product"] = next_position.id_producto
|
| 102 |
-
|
| 103 |
-
ratings_product = CalificacionController.getRatings(
|
| 104 |
-
technique=technique,
|
| 105 |
-
product=next_position.id_producto,
|
| 106 |
-
repetition=technique.repeticion,
|
| 107 |
-
user_tester=req.user.username
|
| 108 |
-
)
|
| 109 |
-
|
| 110 |
-
if isinstance(ratings_product, dict):
|
| 111 |
-
context["error"] = ratings_product["error"]
|
| 112 |
-
return render(req, "tecnicas/forms_tester/convencional.html", context)
|
| 113 |
-
elif not ratings_product:
|
| 114 |
-
context["words"] = words
|
| 115 |
else:
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
words_to_use = PalabrasController.getWordsWithoutData(
|
| 122 |
-
recoreded_data=recoreded_data, words=words)
|
| 123 |
-
context["words"] = words_to_use
|
| 124 |
-
|
| 125 |
-
scale = EscalaController.getScaleByTechnique(technique=technique)
|
| 126 |
-
context["scale"] = scale
|
| 127 |
-
context["type_scale"] = scale.id_tipo_escala.nombre_escala
|
| 128 |
-
|
| 129 |
-
use_tags = EscalaController.getRelatedTagsInScale(scale=scale)
|
| 130 |
-
context["tags"] = use_tags
|
| 131 |
|
| 132 |
-
return
|
|
|
|
| 55 |
- Cata segmento en el que se divide debe tener la etiqueda correspondiente por debajo
|
| 56 |
'''
|
| 57 |
from django.http import HttpRequest
|
| 58 |
+
from tecnicas.controllers import SesionController, ConvencionalScalesController
|
| 59 |
+
from tecnicas.utils import noValidTechnique
|
|
|
|
| 60 |
|
| 61 |
|
| 62 |
def convencionalScales(req: HttpRequest, code_sesion: str):
|
|
|
|
|
|
|
|
|
|
| 63 |
session = SesionController.getSessionByCode(code_sesion)
|
| 64 |
+
type_technique = session.tecnica.tipo_tecnica.nombre_tecnica
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
if req.method == "GET":
|
| 67 |
+
view_controller = ConvencionalScalesController(
|
| 68 |
+
sensorial_session=session, user_tester=req.user.user_catador)
|
| 69 |
+
if type_technique == "escalas":
|
| 70 |
+
respose = view_controller.controllGetEscalas(request=req)
|
| 71 |
+
elif type_technique == "rata":
|
| 72 |
+
respose = view_controller.controllGetRATA(request=req)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
else:
|
| 74 |
+
respose = noValidTechnique(
|
| 75 |
+
name_view='cata_system:catador_init_session',
|
| 76 |
+
params={"code_sesion": session.codigo_sesion},
|
| 77 |
+
query_params={"error": "No es posible poder usar esta técnica"}
|
| 78 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
|
| 80 |
+
return respose
|
tecnicas/views/tester_forms/init_tester_form.py
CHANGED
|
@@ -7,11 +7,6 @@ from tecnicas.models import SesionSensorial
|
|
| 7 |
|
| 8 |
def initTesterForm(req: HttpRequest, code_sesion: str):
|
| 9 |
session = SesionSensorial.objects.get(codigo_sesion=code_sesion)
|
| 10 |
-
|
| 11 |
-
context = {
|
| 12 |
-
"session": session
|
| 13 |
-
}
|
| 14 |
-
|
| 15 |
type_technique = session.tecnica.tipo_tecnica.nombre_tecnica
|
| 16 |
template_url = "tecnicas/forms_tester/init_session.html"
|
| 17 |
|
|
@@ -25,6 +20,7 @@ def initTesterForm(req: HttpRequest, code_sesion: str):
|
|
| 25 |
response = view_controller.controllGetRATA(request=req)
|
| 26 |
else:
|
| 27 |
context = {
|
|
|
|
| 28 |
"error": "La técnica usada en esta sesión o ha sido implementada para ingresar a ella"
|
| 29 |
}
|
| 30 |
response = render(
|
|
@@ -36,6 +32,7 @@ def initTesterForm(req: HttpRequest, code_sesion: str):
|
|
| 36 |
response = view_controller.controllPostEscalas(request=req)
|
| 37 |
else:
|
| 38 |
context = {
|
|
|
|
| 39 |
"error": "Esta opción aun no esta disponible para la técnica usada por la sesión"
|
| 40 |
}
|
| 41 |
response = render(
|
|
|
|
| 7 |
|
| 8 |
def initTesterForm(req: HttpRequest, code_sesion: str):
|
| 9 |
session = SesionSensorial.objects.get(codigo_sesion=code_sesion)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
type_technique = session.tecnica.tipo_tecnica.nombre_tecnica
|
| 11 |
template_url = "tecnicas/forms_tester/init_session.html"
|
| 12 |
|
|
|
|
| 20 |
response = view_controller.controllGetRATA(request=req)
|
| 21 |
else:
|
| 22 |
context = {
|
| 23 |
+
"session": session,
|
| 24 |
"error": "La técnica usada en esta sesión o ha sido implementada para ingresar a ella"
|
| 25 |
}
|
| 26 |
response = render(
|
|
|
|
| 32 |
response = view_controller.controllPostEscalas(request=req)
|
| 33 |
else:
|
| 34 |
context = {
|
| 35 |
+
"session": session,
|
| 36 |
"error": "Esta opción aun no esta disponible para la técnica usada por la sesión"
|
| 37 |
}
|
| 38 |
response = render(
|