diff --git a/Plataform_Web/documentos/__init__.py b/Plataform_Web/documentos/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/documentos/admin.py b/Plataform_Web/documentos/admin.py deleted file mode 100644 index d14f08f..0000000 --- a/Plataform_Web/documentos/admin.py +++ /dev/null @@ -1,39 +0,0 @@ -from django.contrib import admin -from .models import Documento, Factura - -@admin.register(Documento) -class DocumentoAdmin(admin.ModelAdmin): - # Columnas principales - list_display = ('nombre', 'categoria', 'tipo', 'subido_por', 'fecha_subida') - - # Filtros por área técnica, tipo de documento y temporada del documento - list_filter = ('categoria', 'tipo', 'temporada') - - # Buscador de documentos por su nombre o descripción - search_fields = ('nombre', 'descripcion') - - # Para asignar a que temporada pertenece el documento - filter_horizontal = ('temporada',) - - # Automatización: para rellenar el creador del nuevo documento de manera automática - def save_model(self, request, obj, form, change): - if not obj.subido_por: - obj.subido_por = request.user - super().save_model(request, obj, form, change) - - -@admin.register(Factura) -class FacturaAdmin(admin.ModelAdmin): - # Herncia de Documento - list_display = ('nombre', 'empresa', 'importe', 'categoria', 'subido_por', 'fecha_subida') - - list_filter = ('categoria', 'temporada') - search_fields = ('nombre', 'empresa', 'descripcion') - - filter_horizontal = ('temporada',) - - # Mantenemos la misma automatización - def save_model(self, request, obj, form, change): - if not obj.subido_por: - obj.subido_por = request.user - super().save_model(request, obj, form, change) \ No newline at end of file diff --git a/Plataform_Web/documentos/apps.py b/Plataform_Web/documentos/apps.py deleted file mode 100644 index b42b59d..0000000 --- a/Plataform_Web/documentos/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class DocumentosConfig(AppConfig): - name = 'documentos' diff --git a/Plataform_Web/documentos/migrations/0001_initial.py b/Plataform_Web/documentos/migrations/0001_initial.py deleted file mode 100644 index 3598421..0000000 --- a/Plataform_Web/documentos/migrations/0001_initial.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 6.0.2 on 2026-02-17 11:36 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('temporadas', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Documento', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('titulo', models.CharField(max_length=100, verbose_name='Título del documento')), - ('archivo', models.FileField(upload_to='ingenieria_docs/')), - ('categoria', models.CharField(choices=[('aerodinamica', 'Aerodinámica'), ('chasis', 'Chasis'), ('suspension', 'Suspensión'), ('motor', 'Motor/Powertrain'), ('electronica', 'Electrónica'), ('general', 'General / Normativa')], max_length=20)), - ('tipo', models.CharField(choices=[('diseno', 'Diseño / CAD'), ('simulacion', 'Simulación'), ('informe', 'Informe Técnico'), ('factura', 'Factura / Presupuesto'), ('otro', 'Otro')], default='informe', max_length=20)), - ('descripcion', models.TextField(blank=True, null=True, verbose_name='Descripción o notas')), - ('fecha_subida', models.DateTimeField(auto_now_add=True)), - ('subido_por', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='documentos_subidos', to=settings.AUTH_USER_MODEL)), - ('temporada', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='temporadas.temporada')), - ], - options={ - 'verbose_name': 'Documento Técnico', - 'verbose_name_plural': 'Documentos de Ingeniería', - 'ordering': ['-fecha_subida'], - }, - ), - ] diff --git a/Plataform_Web/documentos/migrations/0002_factura_alter_documento_options_and_more.py b/Plataform_Web/documentos/migrations/0002_factura_alter_documento_options_and_more.py deleted file mode 100644 index d29ff00..0000000 --- a/Plataform_Web/documentos/migrations/0002_factura_alter_documento_options_and_more.py +++ /dev/null @@ -1,66 +0,0 @@ -# Generated by Django 6.0.2 on 2026-03-06 19:29 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('documentos', '0001_initial'), - ('temporadas', '0002_temporada_miembros'), - ] - - operations = [ - migrations.CreateModel( - name='Factura', - fields=[ - ('documento_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='documentos.documento')), - ('empresa', models.CharField(max_length=100, verbose_name='Nombre de la empresa')), - ('importe', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Importe (€)')), - ], - options={ - 'verbose_name': 'Factura', - 'verbose_name_plural': 'Facturas', - }, - bases=('documentos.documento',), - ), - migrations.AlterModelOptions( - name='documento', - options={'ordering': ['-fecha_subida'], 'verbose_name': 'Documento', 'verbose_name_plural': 'Documentos'}, - ), - migrations.RemoveField( - model_name='documento', - name='titulo', - ), - migrations.AddField( - model_name='documento', - name='nombre', - field=models.CharField(default='Documento antiguo', max_length=100, verbose_name='Nombre del documento'), - preserve_default=False, - ), - migrations.AlterField( - model_name='documento', - name='categoria', - field=models.CharField(choices=[('aerodinamica', 'Aerodinámica'), ('chasis', 'Chasis'), ('business', 'Business & Operations'), ('e_powertrain', 'E-Powertrain'), ('electronica', 'Electrónica'), ('sdf', 'SDF'), ('motor_transmision', 'Motor & Transmisión'), ('software', 'Software'), ('normativa', 'General / Normativa')], max_length=20), - ), - migrations.AlterField( - model_name='documento', - name='descripcion', - field=models.TextField(blank=True, null=True, verbose_name='Descripción del documento'), - ), - migrations.RemoveField( - model_name='documento', - name='temporada', - ), - migrations.AlterField( - model_name='documento', - name='tipo', - field=models.CharField(choices=[('fabricacion', 'Fabricación'), ('diseno', 'Diseño / CAD'), ('concepto', 'Concepto'), ('simulacion', 'Simulación'), ('dossier_patrocinado', 'Dossier Patrocinio'), ('informe', 'Informe'), ('tutorial', 'Tutorial'), ('otro', 'Otro')], default='informe', max_length=20), - ), - migrations.AddField( - model_name='documento', - name='temporada', - field=models.ManyToManyField(related_name='documentos_asociados', to='temporadas.temporada'), - ), - ] diff --git a/Plataform_Web/documentos/migrations/0003_factura_estado.py b/Plataform_Web/documentos/migrations/0003_factura_estado.py deleted file mode 100644 index 0d89bea..0000000 --- a/Plataform_Web/documentos/migrations/0003_factura_estado.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 6.0.2 on 2026-06-30 16:00 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('documentos', '0002_factura_alter_documento_options_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='factura', - name='estado', - field=models.CharField(choices=[('pendiente', 'Pendiente'), ('aceptada', 'Aceptada'), ('rechazada', 'Rechazada')], default='pendiente', max_length=20), - ), - ] diff --git a/Plataform_Web/documentos/migrations/__init__.py b/Plataform_Web/documentos/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/documentos/models.py b/Plataform_Web/documentos/models.py deleted file mode 100644 index 2703e84..0000000 --- a/Plataform_Web/documentos/models.py +++ /dev/null @@ -1,83 +0,0 @@ -from django.db import models -from users.models import CustomUser -from temporadas.models import Temporada -import os - -class Documento(models.Model): - # Opciones de categorías (puedes añadir más) - CATEGORIAS = ( - ('aerodinamica', 'Aerodinámica'), - ('chasis', 'Chasis'), - ('business', 'Business & Operations'), - ('e_powertrain', 'E-Powertrain'), - ('electronica', 'Electrónica'), - ('sdf', 'SDF'), - ('motor_transmision', 'Motor & Transmisión'), - ('software', 'Software'), - ('normativa', 'General / Normativa'), - ) - - TIPO_DOC = ( - ('fabricacion', 'Fabricación'), - ('diseno', 'Diseño / CAD'), - ('concepto', 'Concepto'), - ('simulacion', 'Simulación'), - ('dossier_patrocinado', 'Dossier Patrocinio'), - ('informe', 'Informe'), - ('tutorial', 'Tutorial'), - ('otro', 'Otro'), - ) - - # CAMPOS - nombre = models.CharField(max_length=100, verbose_name="Nombre del documento") - - # Aquí definimos dónde se guardan los archivos. - # upload_to='ingenieria/' creará esa carpeta automáticamente. - archivo = models.FileField(upload_to='ingenieria_docs/') - - categoria = models.CharField(max_length=20, choices=CATEGORIAS) - tipo = models.CharField(max_length=20, choices=TIPO_DOC, default='informe') - descripcion = models.TextField(blank=True, null=True, verbose_name="Descripción del documento") - fecha_subida = models.DateTimeField(auto_now_add=True) - - # RELACIONES - # Relacion Documento - Temporadas (Relación 1..* a 1..* ) - temporada = models.ManyToManyField(Temporada, related_name="documentos_asociados") - - # 2. Relación 1 a N con el Usuario (Miembros) - subido_por = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, related_name="documentos_subidos") - - class Meta: - verbose_name = "Documento" - verbose_name_plural = "Documentos" - ordering = ['-fecha_subida'] - - def __str__(self): - return f"{self.nombre} ({self.get_categoria_display()})" - - def delete(self, *args, **kwargs): - # Esto borra el archivo físico del disco duro cuando borras la entrada en la base de datos - if self.archivo: - if os.path.isfile(self.archivo.path): - os.remove(self.archivo.path) - super().delete(*args, **kwargs) - -ESTADO_FACTURA = [ - ('pendiente', 'Pendiente'), - ('aceptada', 'Aceptada'), - ('rechazada', 'Rechazada'), -] - -# Herencia de la clase Factura: Factura hereda de Documento -class Factura(Documento): - # Al heredar de Documento, ya tiene nombre, archivo, categoria, etc. - empresa = models.CharField(max_length=100, verbose_name="Nombre de la empresa") - importe = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Importe (€)") - estado = models.CharField(max_length=20, choices=ESTADO_FACTURA, default='pendiente') - - class Meta: - verbose_name = "Factura" - verbose_name_plural = "Facturas" - - def __str__(self): - return f"Factura {self.empresa} - {self.importe}€" \ No newline at end of file diff --git a/Plataform_Web/documentos/tests.py b/Plataform_Web/documentos/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/Plataform_Web/documentos/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/Plataform_Web/documentos/views.py b/Plataform_Web/documentos/views.py deleted file mode 100644 index 91ea44a..0000000 --- a/Plataform_Web/documentos/views.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.shortcuts import render - -# Create your views here. diff --git a/Plataform_Web/gades_manager/__init__.py b/Plataform_Web/gades_manager/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/gades_manager/asgi.py b/Plataform_Web/gades_manager/asgi.py deleted file mode 100644 index 153ca09..0000000 --- a/Plataform_Web/gades_manager/asgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -ASGI config for gades_manager project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/6.0/howto/deployment/asgi/ -""" - -import os - -from django.core.asgi import get_asgi_application - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gades_manager.settings') - -application = get_asgi_application() diff --git a/Plataform_Web/gades_manager/settings.py b/Plataform_Web/gades_manager/settings.py deleted file mode 100644 index a0536f4..0000000 --- a/Plataform_Web/gades_manager/settings.py +++ /dev/null @@ -1,141 +0,0 @@ -""" -Django settings for gades_manager project. - -Generated by 'django-admin startproject' using Django 6.0.2. - -For more information on this file, see -https://docs.djangoproject.com/en/6.0/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/6.0/ref/settings/ -""" - -from pathlib import Path -import os - -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-mwlyo^0ax9u9ts5(hw(e&vlgmr$nbla-3az0d%s(lymmp5^)$-' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - 'users', - 'temporadas', - 'documentos', - 'gestion', - 'pruebas', - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'gades_manager.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [BASE_DIR / 'templates'], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -WSGI_APPLICATION = 'gades_manager.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/6.0/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'formula_gades_bd', # El nombre exacto que pusiste en Workbench - 'USER': 'root', - 'PASSWORD': 'admin1234', # ¡La que apuntaste en el papel! - 'HOST': 'localhost', # Significa "este ordenador" - 'PORT': '3306', - } -} - - -# Password validation -# https://docs.djangoproject.com/en/6.0/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/6.0/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/6.0/howto/static-files/ - -STATIC_URL = '/static/' - -STATICFILES_DIRS = [ - BASE_DIR / "static", -] - -AUTH_USER_MODEL = 'users.CustomUser' - -MEDIA_URL = '/media/' # La URL pública (ej: tudominio.com/media/archivo.pdf) -MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # La carpeta física en tu ordenador - -LOGIN_URL = 'login' -LOGIN_REDIRECT_URL = 'inicio' -LOGOUT_REDIRECT_URL = 'login' diff --git a/Plataform_Web/gades_manager/urls.py b/Plataform_Web/gades_manager/urls.py deleted file mode 100644 index 6d53cf2..0000000 --- a/Plataform_Web/gades_manager/urls.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -URL configuration for gades_manager project. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/6.0/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" - -from django.contrib import admin -from django.urls import path -from django.contrib.auth import views as auth_views -from gestion import views -from users import views as users_views -from temporadas import views as temporadas_views -from pruebas import views as pruebas_views - -urlpatterns = [ - path('admin/', admin.site.urls), - path('', views.inicio, name='inicio'), - path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'), - path('logout/', auth_views.LogoutView.as_view(next_page='login'), name='logout'), - path('mi-perfil/', users_views.mi_perfil, name='mi_perfil'), - path('miembros/', users_views.listado_miembros, name='listado_miembros'), - path('gestion/usuarios/', users_views.gestion_usuarios, name='gestion_usuarios'), - path('gestion/usuarios//editar/', users_views.editar_usuario, name='editar_usuario'), - path('gestion/usuarios//eliminar/', users_views.eliminar_usuario, name='eliminar_usuario'), - path('gestion/temporadas/', temporadas_views.gestion_temporadas, name='gestion_temporadas'), - path('gestion/temporadas/crear/', temporadas_views.crear_temporada, name='crear_temporada'), - path('gestion/temporadas//editar/', temporadas_views.editar_temporada, name='editar_temporada'), - path('gestion/temporadas//eliminar/', temporadas_views.eliminar_temporada, name='eliminar_temporada'), - path('gestion/contabilidad/', views.contabilidad, name='contabilidad'), - path('gestion/contabilidad/gasto/anadir/', views.anadir_gasto, name='anadir_gasto'), - path('gestion/contabilidad/ingreso/anadir/', views.anadir_ingreso, name='anadir_ingreso'), - path('gestion/contabilidad/factura//aceptar/', views.aceptar_factura, name='aceptar_factura'), - path('gestion/contabilidad/factura//rechazar/', views.rechazar_factura, name='rechazar_factura'), - path('patrocinios/', views.patrocinios, name='patrocinios'), - path('patrocinios/proponer/', views.proponer_patrocinio, name='proponer_patrocinio'), - path('patrocinios//editar/', views.editar_patrocinio, name='editar_patrocinio'), - path('patrocinios//estado/', views.cambiar_estado_patrocinio, name='cambiar_estado_patrocinio'), - path('pruebas/', pruebas_views.listado_pruebas, name='listado_pruebas'), - path('pruebas/nueva/', pruebas_views.crear_prueba, name='crear_prueba'), - path('pruebas//', pruebas_views.detalle_prueba, name='detalle_prueba'), - path('pruebas//editar/', pruebas_views.editar_prueba, name='editar_prueba'), - path('pruebas//eliminar/', pruebas_views.eliminar_prueba, name='eliminar_prueba'), - path('pruebas//csv/subir/', pruebas_views.subir_csv, name='subir_csv'), -] \ No newline at end of file diff --git a/Plataform_Web/gades_manager/wsgi.py b/Plataform_Web/gades_manager/wsgi.py deleted file mode 100644 index ef3583b..0000000 --- a/Plataform_Web/gades_manager/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for gades_manager project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/6.0/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gades_manager.settings') - -application = get_wsgi_application() diff --git a/Plataform_Web/gestion/__init__.py b/Plataform_Web/gestion/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/gestion/admin.py b/Plataform_Web/gestion/admin.py deleted file mode 100644 index 0d47392..0000000 --- a/Plataform_Web/gestion/admin.py +++ /dev/null @@ -1,46 +0,0 @@ -from django.contrib import admin -from .models import Patrocinio, Pieza, Gasto, Ingreso - -# INLINES -class PiezaInline(admin.TabularInline): - model = Pieza - extra = 1 - -# PANEL PARA ADMINISTRACIÓN -@admin.register(Patrocinio) -class PatrocinioAdmin(admin.ModelAdmin): - list_display = ('empresa', 'estado', 'tipo_patrocinio', 'importe_economico', 'temporada', 'contacto_equipo') - - # Para editar el estado y pasar de En contacto a Aceptado o Denagado desde la lista, sin tener que hacerlo manual - list_editable = ('estado',) - - list_filter = ('estado', 'tipo_patrocinio', 'temporada') - search_fields = ('empresa', 'persona_contacto', 'email_contacto') - - # Metemos las piezas en el patrocinio, por si hiciera falta - inlines = [PiezaInline] - -@admin.register(Pieza) -class PiezaAdmin(admin.ModelAdmin): - list_display = ('nombre', 'cantidad', 'patrocinio') - search_fields = ('nombre', 'patrocinio__empresa') - -# CONTABILIDAD (Gastos e Ingresos) -@admin.register(Gasto) -class GastoAdmin(admin.ModelAdmin): - # Heredamos los campos de Contabilidad - list_display = ('concepto', 'importe', 'categoria', 'fecha', 'temporada') - list_filter = ('categoria', 'temporada') - search_fields = ('concepto', 'observaciones') - - # Barra de navegación por fecha de gasto - date_hierarchy = 'fecha' - -@admin.register(Ingreso) -class IngresoAdmin(admin.ModelAdmin): - list_display = ('concepto', 'importe', 'categoria', 'fecha', 'temporada') - list_filter = ('categoria', 'temporada') - search_fields = ('concepto', 'observaciones') - - # Barra de navegación por fecha de ingreso - date_hierarchy = 'fecha' \ No newline at end of file diff --git a/Plataform_Web/gestion/apps.py b/Plataform_Web/gestion/apps.py deleted file mode 100644 index 48586ea..0000000 --- a/Plataform_Web/gestion/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class GestionConfig(AppConfig): - name = 'gestion' diff --git a/Plataform_Web/gestion/forms.py b/Plataform_Web/gestion/forms.py deleted file mode 100644 index aecfd67..0000000 --- a/Plataform_Web/gestion/forms.py +++ /dev/null @@ -1,46 +0,0 @@ -from django import forms -from .models import Gasto, Ingreso, Patrocinio - - -class GastoForm(forms.ModelForm): - class Meta: - model = Gasto - fields = ['concepto', 'importe', 'categoria', 'observaciones'] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - for field in self.fields.values(): - field.widget.attrs['class'] = 'form-control' - - -class IngresoForm(forms.ModelForm): - class Meta: - model = Ingreso - fields = ['concepto', 'importe', 'categoria', 'observaciones'] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - for field in self.fields.values(): - field.widget.attrs['class'] = 'form-control' - - -class PatrocinioForm(forms.ModelForm): - class Meta: - model = Patrocinio - fields = ['empresa', 'email_contacto', 'persona_contacto', 'tipo_patrocinio'] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - for field in self.fields.values(): - field.widget.attrs['class'] = 'form-control' - - -class PatrocinioEditForm(forms.ModelForm): - class Meta: - model = Patrocinio - fields = ['empresa', 'email_contacto', 'persona_contacto', 'tipo_patrocinio', 'estado', 'importe_economico'] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - for field in self.fields.values(): - field.widget.attrs['class'] = 'form-control' diff --git a/Plataform_Web/gestion/migrations/0001_initial.py b/Plataform_Web/gestion/migrations/0001_initial.py deleted file mode 100644 index 7c34fb8..0000000 --- a/Plataform_Web/gestion/migrations/0001_initial.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 6.0.2 on 2026-02-19 10:14 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('temporadas', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Factura', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nombre', models.CharField(max_length=100, verbose_name='Concepto de la factura')), - ('empresa', models.CharField(max_length=100, verbose_name='Empresa / Proveedor')), - ('categoria', models.CharField(choices=[('aerodinamica', 'Aerodinámica'), ('chasis', 'Chasis'), ('business', 'Business & Operations'), ('epowertrain', 'E-Powertrain'), ('electronica', 'Electrónica'), ('sdf', 'SDF'), ('motor_transmision', 'Motor & Transmisión'), ('software', 'Software'), ('general', 'General')], max_length=30)), - ('descripcion', models.TextField(blank=True, null=True, verbose_name='Breve descripción')), - ('archivo', models.FileField(upload_to='facturas/', verbose_name='Foto o PDF de la factura')), - ('subido_por', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Usuario que la sube')), - ('temporada', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='temporadas.temporada')), - ], - ), - migrations.CreateModel( - name='Patrocinador', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('empresa', models.CharField(max_length=100, verbose_name='Nombre de la Empresa')), - ('email_contacto', models.EmailField(max_length=254, verbose_name='Correo de contacto')), - ('tipo_empresa', models.CharField(max_length=30, verbose_name='Tipo de la Empresa')), - ('tipo_patrocinio', models.CharField(choices=[('economico', 'Económico'), ('piezas/materiales', 'Piezas/Materiales'), ('mixto', 'Mixto (Dinero y Piezas)')], max_length=30)), - ('detalle_piezas', models.TextField(blank=True, help_text='Detallar qué se ofrece si es en especies', null=True)), - ('estado', models.CharField(choices=[('en contacto', 'En contacto'), ('aceptado', 'Aceptado / Activo'), ('denegado', 'Denegado')], default='contacto', max_length=20)), - ('contacto_equipo', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Miembro al cargo')), - ('temporada', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='temporadas.temporada')), - ], - ), - ] diff --git a/Plataform_Web/gestion/migrations/0002_remove_patrocinador_contacto_equipo_and_more.py b/Plataform_Web/gestion/migrations/0002_remove_patrocinador_contacto_equipo_and_more.py deleted file mode 100644 index 84fb76c..0000000 --- a/Plataform_Web/gestion/migrations/0002_remove_patrocinador_contacto_equipo_and_more.py +++ /dev/null @@ -1,92 +0,0 @@ -# Generated by Django 6.0.2 on 2026-03-06 19:29 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('gestion', '0001_initial'), - ('temporadas', '0002_temporada_miembros'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.RemoveField( - model_name='patrocinador', - name='contacto_equipo', - ), - migrations.RemoveField( - model_name='patrocinador', - name='temporada', - ), - migrations.CreateModel( - name='Gasto', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('concepto', models.CharField(max_length=150)), - ('importe', models.DecimalField(decimal_places=2, max_digits=10)), - ('fecha', models.DateField()), - ('observaciones', models.TextField(blank=True, null=True)), - ('categoria', models.CharField(choices=[('aerodinamica', 'Aerodinámica'), ('chasis', 'Chasis'), ('business', 'Business & Operations'), ('e_powertrain', 'E-Powertrain'), ('electronica', 'Electrónica'), ('sdf', 'SDF'), ('motor_transmision', 'Motor & Transmisión'), ('software', 'Software'), ('general', 'General')], max_length=30, verbose_name='Área del gasto')), - ('doc_justificativo', models.FileField(blank=True, null=True, upload_to='contabilidad/gastos/', verbose_name='Ticket o Factura (PDF/IMG)')), - ('temporada', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='%(class)s_registrados', to='temporadas.temporada')), - ], - options={ - 'verbose_name': 'Gasto', - 'verbose_name_plural': 'Gastos', - }, - ), - migrations.CreateModel( - name='Ingreso', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('concepto', models.CharField(max_length=150)), - ('importe', models.DecimalField(decimal_places=2, max_digits=10)), - ('fecha', models.DateField()), - ('observaciones', models.TextField(blank=True, null=True)), - ('categoria', models.CharField(choices=[('patrocinador', 'Patrocinador'), ('donación', 'Donación'), ('premio', 'Premio'), ('recaudación', 'Recaudación'), ('Cuotas', 'Cuotas'), ('Ventas', 'ventas')], max_length=30, verbose_name='Categoria del Ingreso')), - ('temporada', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='%(class)s_registrados', to='temporadas.temporada')), - ], - options={ - 'verbose_name': 'Ingreso', - 'verbose_name_plural': 'Ingresos', - }, - ), - migrations.CreateModel( - name='Patrocinio', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('empresa', models.CharField(max_length=100, verbose_name='Nombre de la Empresa')), - ('persona_contacto', models.CharField(blank=True, max_length=100, null=True, verbose_name='Persona de contacto')), - ('email_contacto', models.EmailField(max_length=254, verbose_name='Correo de contacto')), - ('tipo_patrocinio', models.CharField(choices=[('economico', 'Económico'), ('piezas/materiales', 'Piezas/Materiales'), ('mixto', 'Mixto (Dinero y Piezas)')], max_length=30)), - ('estado', models.CharField(choices=[('en_contacto', 'En contacto'), ('aceptado', 'Aceptado / Activo'), ('denegado', 'Denegado')], default='en_contacto', max_length=20)), - ('importe_economico', models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='Importe (€)')), - ('fecha_contacto', models.DateField(auto_now_add=True)), - ('contacto_equipo', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='patrocinios_gestionados', to=settings.AUTH_USER_MODEL, verbose_name='Persona al cargo del Patrocinio')), - ('temporada', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='patrocinios', to='temporadas.temporada', verbose_name='Temporada del patrocinio')), - ], - options={ - 'verbose_name': 'Patrocinio', - 'verbose_name_plural': 'Patrocinios', - }, - ), - migrations.CreateModel( - name='Pieza', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nombre', models.CharField(max_length=100, verbose_name='Nombre de la pieza/material')), - ('cantidad', models.PositiveIntegerField(default=1)), - ('patrocinio', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='piezas', to='gestion.patrocinio')), - ], - ), - migrations.DeleteModel( - name='Factura', - ), - migrations.DeleteModel( - name='Patrocinador', - ), - ] diff --git a/Plataform_Web/gestion/migrations/__init__.py b/Plataform_Web/gestion/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/gestion/models.py b/Plataform_Web/gestion/models.py deleted file mode 100644 index 5155e65..0000000 --- a/Plataform_Web/gestion/models.py +++ /dev/null @@ -1,106 +0,0 @@ -from django.db import models -from django.conf import settings -from temporadas.models import Temporada - - -class Patrocinio(models.Model): - - TIPO_PATROCINIO = ( - ('economico', 'Económico'), - ('piezas/materiales', 'Piezas/Materiales'), - ('mixto', 'Mixto (Dinero y Piezas)'), - ) - - ESTADOS = ( - ('en_contacto', 'En contacto'), - ('aceptado', 'Aceptado / Activo'), - ('denegado', 'Denegado'), - ) - - empresa = models.CharField(max_length=100, verbose_name="Nombre de la Empresa") - persona_contacto = models.CharField(max_length=100, blank=True, null=True, verbose_name="Persona de contacto") - email_contacto = models.EmailField(verbose_name="Correo de contacto") - tipo_patrocinio = models.CharField(max_length=30, choices=TIPO_PATROCINIO) - estado = models.CharField(max_length=20, choices=ESTADOS, default='en_contacto') - - # Si el patrocinio es únicamente material, se quedará en 0. Si es económico o mixto, se rellena - importe_economico = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name="Importe (€)") - - fecha_contacto = models.DateField(auto_now_add=True) - # Relaciones - temporada = models.ForeignKey(Temporada, on_delete=models.CASCADE, related_name="patrocinios", verbose_name="Temporada del patrocinio") - contacto_equipo = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, related_name="patrocinios_gestionados", verbose_name="Persona al cargo del Patrocinio") - - class Meta: - verbose_name = "Patrocinio" - verbose_name_plural = "Patrocinios" - - def __str__(self): - return f"{self.empresa} ({self.get_estado_display()})" - -class Pieza(models.Model): - nombre = models.CharField(max_length=100, verbose_name="Nombre de la pieza/material") - cantidad = models.PositiveIntegerField(default=1) - - # COMPOSICIÓN ESTRICTA: Si se borra el Patrocinio, se borran las Piezas irremediablemente (CASCADE) - patrocinio = models.ForeignKey(Patrocinio, on_delete=models.CASCADE, related_name="piezas") - - def __str__(self): - return f"{self.cantidad}x {self.nombre} (De: {self.patrocinio.empresa})" - -class Contabilidad(models.Model): - concepto = models.CharField(max_length=150) - importe = models.DecimalField(max_digits=10, decimal_places=2) - fecha = models.DateField() - observaciones = models.TextField(blank=True, null=True) - - # Relación con Temporada. PROTECT evita que borres una temporada si tiene contabilidad asociada (por temas legales) - temporada = models.ForeignKey(Temporada, on_delete=models.PROTECT, related_name="%(class)s_registrados") - - class Meta: - abstract = True #marcamos la clase como abstracta - ordering = ['-fecha'] - - -class Gasto(Contabilidad): - - CATEGORIAS_GASTOS = ( - ('aerodinamica', 'Aerodinámica'), - ('chasis', 'Chasis'), - ('business', 'Business & Operations'), - ('e_powertrain', 'E-Powertrain'), - ('electronica', 'Electrónica'), - ('sdf', 'SDF'), - ('motor_transmision', 'Motor & Transmisión'), - ('software', 'Software'), - ('general', 'General'), - ) - # Hereda concepto, importe, fecha, observaciones y temporada automáticamente - categoria = models.CharField(max_length=30, choices=CATEGORIAS_GASTOS, verbose_name="Área del gasto") - doc_justificativo = models.FileField(upload_to='contabilidad/gastos/', blank=True, null=True, verbose_name="Ticket o Factura (PDF/IMG)") - - class Meta: - verbose_name = "Gasto" - verbose_name_plural = "Gastos" - - def __str__(self): - return f"[-{self.importe}€] {self.concepto} ({self.temporada})" - -class Ingreso(Contabilidad): - CATEGORIAS_INGRESO = ( - ('patrocinador', 'Patrocinador'), - ('donación', 'Donación'), - ('premio', 'Premio'), - ('recaudación', 'Recaudación'), - ('Cuotas', 'Cuotas'), - ('Ventas', 'ventas'), - ) - - # Hereda concepto, importe, fecha, observaciones y temporada automáticamente - categoria = models.CharField(max_length=30, choices=CATEGORIAS_INGRESO, verbose_name="Categoria del Ingreso") - class Meta: - verbose_name = "Ingreso" - verbose_name_plural = "Ingresos" - - def __str__(self): - return f"[+{self.importe}€] {self.concepto} ({self.temporada})" diff --git a/Plataform_Web/gestion/tests.py b/Plataform_Web/gestion/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/Plataform_Web/gestion/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/Plataform_Web/gestion/views.py b/Plataform_Web/gestion/views.py deleted file mode 100644 index 8da0530..0000000 --- a/Plataform_Web/gestion/views.py +++ /dev/null @@ -1,202 +0,0 @@ -from django.shortcuts import render, redirect, get_object_or_404 -from django.contrib import messages -from django.contrib.auth.decorators import login_required -from django.views.decorators.http import require_POST -from django.db.models import Sum -from datetime import date - -from temporadas.models import Temporada -from documentos.models import Factura -from users.decorators import require_rol -from .models import Gasto, Ingreso, Patrocinio -from .forms import GastoForm, IngresoForm, PatrocinioForm, PatrocinioEditForm - -# Categorías válidas en Gasto (Documento usa 'normativa' en su lugar de 'general') -_CATEGORIAS_GASTO_VALIDAS = {c[0] for c in Gasto.CATEGORIAS_GASTOS} - - -@login_required -def inicio(request): - temporada_activa = Temporada.objects.filter(actual=True).first() - return render(request, 'index.html', {'temporada_actual': temporada_activa}) - - -@require_rol('directiva') -def contabilidad(request): - temporada_actual = Temporada.objects.filter(actual=True).first() - - gastos = [] - ingresos = [] - facturas_pendientes = [] - total_gastos = 0 - total_ingresos = 0 - presupuesto_inicial = 0 - presupuesto_actual = 0 - - if temporada_actual: - gastos = Gasto.objects.filter(temporada=temporada_actual) - ingresos = Ingreso.objects.filter(temporada=temporada_actual) - facturas_pendientes = Factura.objects.filter( - temporada=temporada_actual, estado='pendiente' - ) - - total_gastos = gastos.aggregate(total=Sum('importe'))['total'] or 0 - total_ingresos = ingresos.aggregate(total=Sum('importe'))['total'] or 0 - presupuesto_inicial = temporada_actual.presupuesto - presupuesto_actual = presupuesto_inicial - total_gastos + total_ingresos - - return render(request, 'contabilidad.html', { - 'temporada_actual': temporada_actual, - 'gastos': gastos, - 'ingresos': ingresos, - 'facturas_pendientes': facturas_pendientes, - 'total_gastos': total_gastos, - 'total_ingresos': total_ingresos, - 'presupuesto_inicial': presupuesto_inicial, - 'presupuesto_actual': presupuesto_actual, - 'gasto_form': GastoForm(), - 'ingreso_form': IngresoForm(), - }) - - -@require_rol('directiva') -@require_POST -def anadir_gasto(request): - temporada_actual = Temporada.objects.filter(actual=True).first() - if not temporada_actual: - messages.error(request, 'No hay temporada activa.') - return redirect('contabilidad') - - form = GastoForm(request.POST) - if form.is_valid(): - gasto = form.save(commit=False) - gasto.fecha = date.today() - gasto.temporada = temporada_actual - gasto.save() - messages.success(request, 'Gasto añadido correctamente.') - else: - messages.error(request, 'Error al añadir el gasto. Revisa los datos.') - return redirect('contabilidad') - - -@require_rol('directiva') -@require_POST -def anadir_ingreso(request): - temporada_actual = Temporada.objects.filter(actual=True).first() - if not temporada_actual: - messages.error(request, 'No hay temporada activa.') - return redirect('contabilidad') - - form = IngresoForm(request.POST) - if form.is_valid(): - ingreso = form.save(commit=False) - ingreso.fecha = date.today() - ingreso.temporada = temporada_actual - ingreso.save() - messages.success(request, 'Ingreso añadido correctamente.') - else: - messages.error(request, 'Error al añadir el ingreso. Revisa los datos.') - return redirect('contabilidad') - - -@require_rol('directiva') -@require_POST -def aceptar_factura(request, pk): - factura = get_object_or_404(Factura, pk=pk) - temporada_actual = Temporada.objects.filter(actual=True).first() - if not temporada_actual: - messages.error(request, 'No hay temporada activa.') - return redirect('contabilidad') - - categoria = factura.categoria if factura.categoria in _CATEGORIAS_GASTO_VALIDAS else 'general' - Gasto.objects.create( - concepto=factura.nombre, - importe=factura.importe, - fecha=date.today(), - categoria=categoria, - temporada=temporada_actual, - observaciones=f'Factura de {factura.empresa}', - doc_justificativo=factura.archivo, - ) - factura.estado = 'aceptada' - factura.save() - messages.success(request, f'Factura de {factura.empresa} aceptada y registrada como gasto.') - return redirect('contabilidad') - - -@require_rol('directiva') -@require_POST -def rechazar_factura(request, pk): - factura = get_object_or_404(Factura, pk=pk) - factura.estado = 'rechazada' - factura.save() - messages.success(request, f'Factura de {factura.empresa} rechazada.') - return redirect('contabilidad') - - -@login_required -def patrocinios(request): - temporada_actual = Temporada.objects.filter(actual=True).first() - pendientes = [] - aceptados = [] - denegados = [] - if temporada_actual: - qs = Patrocinio.objects.filter(temporada=temporada_actual).select_related('contacto_equipo') - pendientes = qs.filter(estado='en_contacto') - aceptados = qs.filter(estado='aceptado') - denegados = qs.filter(estado='denegado') - return render(request, 'patrocinios.html', { - 'temporada_actual': temporada_actual, - 'pendientes': pendientes, - 'aceptados': aceptados, - 'denegados': denegados, - 'form': PatrocinioForm(), - }) - - -@login_required -@require_POST -def proponer_patrocinio(request): - temporada_actual = Temporada.objects.filter(actual=True).first() - if not temporada_actual: - messages.error(request, 'No hay temporada activa. No se puede proponer un patrocinio.') - return redirect('patrocinios') - - form = PatrocinioForm(request.POST) - if form.is_valid(): - empresa = form.cleaned_data['empresa'].strip() - if Patrocinio.objects.filter(empresa__iexact=empresa, temporada=temporada_actual).exists(): - messages.error(request, f'Ya existe un patrocinio con "{empresa}" en la temporada actual.') - else: - patrocinio = form.save(commit=False) - patrocinio.estado = 'en_contacto' - patrocinio.temporada = temporada_actual - patrocinio.contacto_equipo = request.user - patrocinio.save() - messages.success(request, f'Patrocinio de "{empresa}" propuesto correctamente.') - else: - messages.error(request, 'Error en el formulario. Revisa los datos.') - return redirect('patrocinios') - - -@require_rol('directiva') -def editar_patrocinio(request, pk): - patrocinio = get_object_or_404(Patrocinio, pk=pk) - form = PatrocinioEditForm(request.POST or None, instance=patrocinio) - if request.method == 'POST' and form.is_valid(): - form.save() - messages.success(request, 'Patrocinio actualizado correctamente.') - return redirect('patrocinios') - return render(request, 'editar_patrocinio.html', {'form': form, 'patrocinio': patrocinio}) - - -@require_rol('directiva') -@require_POST -def cambiar_estado_patrocinio(request, pk): - patrocinio = get_object_or_404(Patrocinio, pk=pk) - nuevo_estado = request.POST.get('estado') - if nuevo_estado in ('aceptado', 'denegado', 'en_contacto'): - patrocinio.estado = nuevo_estado - patrocinio.save() - messages.success(request, f'Estado de "{patrocinio.empresa}" actualizado.') - return redirect('patrocinios') diff --git a/Plataform_Web/manage.py b/Plataform_Web/manage.py deleted file mode 100644 index d8daff8..0000000 --- a/Plataform_Web/manage.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -"""Django's command-line utility for administrative tasks.""" -import os -import sys - - -def main(): - """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'gades_manager.settings') - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - - -if __name__ == '__main__': - main() diff --git a/Plataform_Web/media/ingenieria_docs/PruebaTest1.png b/Plataform_Web/media/ingenieria_docs/PruebaTest1.png deleted file mode 100644 index 0c824e6..0000000 Binary files a/Plataform_Web/media/ingenieria_docs/PruebaTest1.png and /dev/null differ diff --git a/Plataform_Web/pruebas/__init__.py b/Plataform_Web/pruebas/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/pruebas/admin.py b/Plataform_Web/pruebas/admin.py deleted file mode 100644 index c2bb061..0000000 --- a/Plataform_Web/pruebas/admin.py +++ /dev/null @@ -1,50 +0,0 @@ -from django.contrib import admin -from .models import Prueba, Telemetria, Variable - -# INLINES -# Usamos inlines que nos sirve para cuando se este creando un registro de Telemetría, podremos añadir sus Variables en la misma pantalla sin tener que ir a otro menú -class VariableInline(admin.TabularInline): - model = Variable - extra = 1 - -class TelemetriaInline(admin.TabularInline): - model = Telemetria - extra = 0 - -# PANELES DE ADMINISTRACIÓN -@admin.register(Prueba) -class PruebaAdmin(admin.ModelAdmin): - list_display = ('nombre', 'categoria', 'fecha_inicio', 'temporada', 'realizado_por') - - # Filtros para encontrar los test dado una temporada y una área técnica - list_filter = ('categoria', 'temporada') - - # Buscador de texto - search_fields = ('nombre', 'descripcion', 'resultados') - - # Una barra de navegación en la parte superior, para poder hacer clic en un año y en un mes y mostrar todos los datos de ese me - date_hierarchy = 'fecha_inicio' - - # Mostramos los archivos de telemetría directamente dentro del test - inlines = [TelemetriaInline] - - -@admin.register(Telemetria) -class TelemetriaAdmin(admin.ModelAdmin): - list_display = ('nombre', 'prueba', 'fecha_subida') - - # Filtra test de telemetría basandose en la temporada o área tecnica de su test correspondiente - list_filter = ('prueba__temporada', 'prueba__categoria') - - # Buscador del nombre de la telemetría o por el nombre de la prueba - search_fields = ('nombre', 'prueba__nombre') - - # Mostramos las variables de su telemetría - inlines = [VariableInline] - - -@admin.register(Variable) -class VariableAdmin(admin.ModelAdmin): - # Aunque se pueden crear desde el Inline, dejamos su tabla propia por si fuese necesario, por prevenir - list_display = ('nombre', 'unidad_medida', 'telemetria') - search_fields = ('nombre', 'telemetria__nombre') \ No newline at end of file diff --git a/Plataform_Web/pruebas/apps.py b/Plataform_Web/pruebas/apps.py deleted file mode 100644 index 8cbb027..0000000 --- a/Plataform_Web/pruebas/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class PruebasConfig(AppConfig): - name = 'pruebas' diff --git a/Plataform_Web/pruebas/forms.py b/Plataform_Web/pruebas/forms.py deleted file mode 100644 index 60029e9..0000000 --- a/Plataform_Web/pruebas/forms.py +++ /dev/null @@ -1,22 +0,0 @@ -from django import forms -from .models import Prueba, Telemetria - - -class PruebaForm(forms.ModelForm): - class Meta: - model = Prueba - fields = ['nombre', 'descripcion', 'fecha_inicio', 'fecha_fin', 'categoria', 'resultados', 'temporada'] - widgets = { - 'fecha_inicio': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}), - 'fecha_fin': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}), - } - - -class TelemetriaForm(forms.ModelForm): - class Meta: - model = Telemetria - fields = ['nombre', 'archivo_csv'] - widgets = { - 'nombre': forms.TextInput(attrs={'class': 'form-control form-control-sm'}), - 'archivo_csv': forms.ClearableFileInput(attrs={'class': 'form-control form-control-sm'}), - } diff --git a/Plataform_Web/pruebas/migrations/0001_initial.py b/Plataform_Web/pruebas/migrations/0001_initial.py deleted file mode 100644 index d531753..0000000 --- a/Plataform_Web/pruebas/migrations/0001_initial.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 6.0.2 on 2026-02-19 10:14 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('temporadas', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='TestGeneral', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nombre', models.CharField(max_length=150, verbose_name='Nombre del Test')), - ('descripcion', models.TextField(verbose_name='Objetivo / Descripción del test')), - ('fecha_inicio', models.DateField()), - ('fecha_fin', models.DateField()), - ('categoria', models.CharField(choices=[('aerodinamica', 'Aerodinámica'), ('chasis', 'Chasis'), ('business', 'Business & Operations'), ('epowertrain', 'E-Powertrain'), ('electronica', 'Electrónica'), ('sdf', 'SDF'), ('motor_transmision', 'Motor & Transmisión'), ('general', 'General')], default='general', max_length=30)), - ('resultados', models.TextField(blank=True, null=True, verbose_name='Conclusiones y Resultados')), - ('temporada', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='temporadas.temporada')), - ], - options={ - 'verbose_name': 'Test General', - 'verbose_name_plural': 'Tests Generales', - 'ordering': ['-fecha_inicio'], - }, - ), - ] diff --git a/Plataform_Web/pruebas/migrations/0002_prueba_telemetria_variable_delete_testgeneral.py b/Plataform_Web/pruebas/migrations/0002_prueba_telemetria_variable_delete_testgeneral.py deleted file mode 100644 index 8bc4e3b..0000000 --- a/Plataform_Web/pruebas/migrations/0002_prueba_telemetria_variable_delete_testgeneral.py +++ /dev/null @@ -1,67 +0,0 @@ -# Generated by Django 6.0.2 on 2026-03-06 19:29 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('pruebas', '0001_initial'), - ('temporadas', '0002_temporada_miembros'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='Prueba', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nombre', models.CharField(max_length=150, verbose_name='Nombre del Test')), - ('descripcion', models.TextField(verbose_name='Objetivo / Descripción de la prueba')), - ('fecha_inicio', models.DateField()), - ('fecha_fin', models.DateField()), - ('categoria', models.CharField(choices=[('aerodinamica', 'Aerodinámica'), ('chasis', 'Chasis'), ('epowertrain', 'E-Powertrain'), ('electronica', 'Electrónica'), ('sdf', 'SDF'), ('motor_transmision', 'Motor & Transmisión'), ('software', 'Software'), ('general', 'General')], default='general', max_length=30)), - ('resultados', models.TextField(blank=True, null=True, verbose_name='Conclusiones y Resultados')), - ('realizado_por', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pruebas_realizadas', to=settings.AUTH_USER_MODEL, verbose_name='Realizado por')), - ('temporada', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pruebas', to='temporadas.temporada')), - ], - options={ - 'verbose_name': 'Prueba', - 'verbose_name_plural': 'Pruebas', - 'ordering': ['-fecha_inicio'], - }, - ), - migrations.CreateModel( - name='Telemetria', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nombre', models.CharField(max_length=100, verbose_name='Nombre del registro')), - ('archivo_csv', models.FileField(upload_to='telemetria/archivos_csv/', verbose_name='Archivo de Datos (CSV)')), - ('fecha_subida', models.DateTimeField(auto_now_add=True)), - ('prueba', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='archivos_telemetria', to='pruebas.prueba')), - ], - options={ - 'verbose_name': 'Registro de Telemetría', - 'verbose_name_plural': 'Registros de Telemetría', - }, - ), - migrations.CreateModel( - name='Variable', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nombre', models.CharField(max_length=50, verbose_name='Nombre ')), - ('unidad_medida', models.CharField(blank=True, max_length=20, null=True, verbose_name='Unidad de medida')), - ('descripcion', models.TextField(blank=True, null=True)), - ('telemetria', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='variables', to='pruebas.telemetria')), - ], - options={ - 'verbose_name': 'Variable de Telemetría', - 'verbose_name_plural': 'Variables de Telemetría', - }, - ), - migrations.DeleteModel( - name='TestGeneral', - ), - ] diff --git a/Plataform_Web/pruebas/migrations/__init__.py b/Plataform_Web/pruebas/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/pruebas/models.py b/Plataform_Web/pruebas/models.py deleted file mode 100644 index 257563e..0000000 --- a/Plataform_Web/pruebas/models.py +++ /dev/null @@ -1,78 +0,0 @@ -from django.db import models -from django.conf import settings -from temporadas.models import Temporada -import os - -class Prueba(models.Model): - CATEGORIAS_TEST = ( - ('aerodinamica', 'Aerodinámica'), - ('chasis', 'Chasis'), - ('epowertrain', 'E-Powertrain'), - ('electronica', 'Electrónica'), - ('sdf', 'SDF'), - ('motor_transmision', 'Motor & Transmisión'), - ('software', 'Software'), - ('general', 'General'), - ) - - nombre = models.CharField(max_length=150, verbose_name="Nombre del Test") - descripcion = models.TextField(verbose_name="Objetivo / Descripción de la prueba") - - fecha_inicio = models.DateField() - fecha_fin = models.DateField() - - categoria = models.CharField(max_length=30, choices=CATEGORIAS_TEST, default='general') - resultados = models.TextField(blank=True, null=True, verbose_name="Conclusiones y Resultados") - - # Relaciones - # Relacion con Temporada - temporada = models.ForeignKey(Temporada, on_delete=models.CASCADE, related_name="pruebas") - #Relacion con Usuario - realizado_por = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, related_name="pruebas_realizadas", verbose_name="Realizado por") - - class Meta: - verbose_name = "Prueba" - verbose_name_plural = "Pruebas" - ordering = ['-fecha_inicio'] - - def __str__(self): - return f"{self.nombre} ({self.fecha_inicio})" - -class Telemetria(models.Model): - nombre = models.CharField(max_length=100, verbose_name="Nombre del registro") - archivo_csv = models.FileField(upload_to='telemetria/archivos_csv/', verbose_name="Archivo de Datos (CSV)") - fecha_subida = models.DateTimeField(auto_now_add=True) - - # La telemetría se obtiene durante una Prueba en pista - prueba = models.ForeignKey(Prueba, on_delete=models.CASCADE, related_name="archivos_telemetria") - - class Meta: - verbose_name = "Registro de Telemetría" - verbose_name_plural = "Registros de Telemetría" - - def __str__(self): - return f"Telemetría: {self.nombre} (De: {self.prueba.nombre})" - - def delete(self, *args, **kwargs): - # Borra el archivo físico del disco duro cuando borras la entrada en la base de datos - if self.archivo_csv: - if os.path.isfile(self.archivo_csv.path): - os.remove(self.archivo_csv.path) - super().delete(*args, **kwargs) - - -class Variable(models.Model): - nombre = models.CharField(max_length=50, verbose_name="Nombre ") - unidad_medida = models.CharField(max_length=20, verbose_name="Unidad de medida", blank=True, null=True) - descripcion = models.TextField(blank=True, null=True) - - # COMPOSICIÓN - telemetria = models.ForeignKey(Telemetria, on_delete=models.CASCADE, related_name="variables") - - class Meta: - verbose_name = "Variable de Telemetría" - verbose_name_plural = "Variables de Telemetría" - - def __str__(self): - unidad = f" [{self.unidad_medida}]" if self.unidad_medida else "" - return f"{self.nombre}{unidad} (De: {self.telemetria.nombre})" \ No newline at end of file diff --git a/Plataform_Web/pruebas/tests.py b/Plataform_Web/pruebas/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/Plataform_Web/pruebas/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/Plataform_Web/pruebas/views.py b/Plataform_Web/pruebas/views.py deleted file mode 100644 index 38fcb78..0000000 --- a/Plataform_Web/pruebas/views.py +++ /dev/null @@ -1,102 +0,0 @@ -from django.shortcuts import render, redirect, get_object_or_404 -from django.contrib import messages -from django.contrib.auth.decorators import login_required -from django.views.decorators.http import require_POST -from users.decorators import require_rol -from temporadas.models import Temporada -from .models import Prueba -from .forms import PruebaForm, TelemetriaForm - - -def puede_subir_csv(user): - return user.rol == 'directiva' or user.especialidad == 'software' - - -@login_required -def listado_pruebas(request): - temporada_actual = Temporada.objects.filter(actual=True).first() - temporada_id = request.GET.get('temporada') or (temporada_actual.pk if temporada_actual else None) - categoria = request.GET.get('categoria') - - pruebas = Prueba.objects.all() - if temporada_id: - pruebas = pruebas.filter(temporada_id=temporada_id) - if categoria: - pruebas = pruebas.filter(categoria=categoria) - - return render(request, 'listado_pruebas.html', { - 'pruebas': pruebas, - 'temporadas': Temporada.objects.all(), - 'categorias': Prueba.CATEGORIAS_TEST, - 'temporada_seleccionada': str(temporada_id) if temporada_id else '', - 'categoria_seleccionada': categoria or '', - }) - - -@login_required -def detalle_prueba(request, pk): - prueba = get_object_or_404(Prueba, pk=pk) - puede_editar = request.user.rol == 'directiva' or ( - request.user.rol == 'jefe_area' and prueba.realizado_por_id == request.user.id - ) - return render(request, 'detalle_prueba.html', { - 'prueba': prueba, - 'puede_editar': puede_editar, - 'puede_subir_csv': puede_subir_csv(request.user), - 'form_csv': TelemetriaForm(), - }) - - -@require_rol('directiva', 'jefe_area') -def crear_prueba(request): - form = PruebaForm(request.POST or None) - if request.method == 'POST' and form.is_valid(): - prueba = form.save(commit=False) - prueba.realizado_por = request.user - prueba.save() - messages.success(request, 'Test creado correctamente.') - return redirect('listado_pruebas') - return render(request, 'editar_prueba.html', {'form': form, 'prueba': None}) - - -@require_rol('directiva', 'jefe_area') -def editar_prueba(request, pk): - prueba = get_object_or_404(Prueba, pk=pk) - if request.user.rol == 'jefe_area' and prueba.realizado_por_id != request.user.id: - messages.error(request, 'Solo puedes editar los tests que tú has creado.') - return redirect('detalle_prueba', pk=prueba.pk) - - form = PruebaForm(request.POST or None, instance=prueba) - if request.method == 'POST' and form.is_valid(): - form.save() - messages.success(request, 'Test actualizado correctamente.') - return redirect('detalle_prueba', pk=prueba.pk) - return render(request, 'editar_prueba.html', {'form': form, 'prueba': prueba}) - - -@require_rol('directiva') -@require_POST -def eliminar_prueba(request, pk): - prueba = get_object_or_404(Prueba, pk=pk) - prueba.delete() - messages.success(request, f'Test "{prueba.nombre}" eliminado.') - return redirect('listado_pruebas') - - -@login_required -@require_POST -def subir_csv(request, pk): - prueba = get_object_or_404(Prueba, pk=pk) - if not puede_subir_csv(request.user): - messages.error(request, 'No tienes permiso para subir archivos de telemetría.') - return redirect('detalle_prueba', pk=prueba.pk) - - form = TelemetriaForm(request.POST, request.FILES) - if form.is_valid(): - telemetria = form.save(commit=False) - telemetria.prueba = prueba - telemetria.save() - messages.success(request, 'Archivo de telemetría subido correctamente.') - else: - messages.error(request, 'No se pudo subir el archivo. Revisa el formulario.') - return redirect('detalle_prueba', pk=prueba.pk) diff --git a/Plataform_Web/static/dossiers/DossierEN_2025_2026.pdf b/Plataform_Web/static/dossiers/DossierEN_2025_2026.pdf deleted file mode 100644 index e77e215..0000000 Binary files a/Plataform_Web/static/dossiers/DossierEN_2025_2026.pdf and /dev/null differ diff --git a/Plataform_Web/static/dossiers/Dossier_2025_2026.pdf b/Plataform_Web/static/dossiers/Dossier_2025_2026.pdf deleted file mode 100644 index cc1b2f1..0000000 Binary files a/Plataform_Web/static/dossiers/Dossier_2025_2026.pdf and /dev/null differ diff --git a/Plataform_Web/static/images/logo_gades.png b/Plataform_Web/static/images/logo_gades.png deleted file mode 100644 index 36e0782..0000000 Binary files a/Plataform_Web/static/images/logo_gades.png and /dev/null differ diff --git a/Plataform_Web/static/images/monoplaza_gades.jpg b/Plataform_Web/static/images/monoplaza_gades.jpg deleted file mode 100644 index fe02155..0000000 Binary files a/Plataform_Web/static/images/monoplaza_gades.jpg and /dev/null differ diff --git a/Plataform_Web/templates/base.html b/Plataform_Web/templates/base.html deleted file mode 100644 index fd7817d..0000000 --- a/Plataform_Web/templates/base.html +++ /dev/null @@ -1,111 +0,0 @@ -{% load static %} - - - - - - {% block title %}Intranet | Formula Gades{% endblock title %} - - - - - - {% block extra_head %}{% endblock extra_head %} - - - - - - -
- {% block content %} - {% endblock content %} -
- -
-

© 2026 Formula Gades - Universidad de Cádiz. Todos los derechos reservados.

-
- - - - {% block extra_js %}{% endblock extra_js %} - - \ No newline at end of file diff --git a/Plataform_Web/templates/contabilidad.html b/Plataform_Web/templates/contabilidad.html deleted file mode 100644 index 9beeaf4..0000000 --- a/Plataform_Web/templates/contabilidad.html +++ /dev/null @@ -1,247 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Contabilidad | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-

Contabilidad

-

- {% if temporada_actual %}{{ temporada_actual.nombre }}{% else %}Sin temporada activa{% endif %} -

-
-
-
- -{% if messages %} -
-
- {% for message in messages %} -
{{ message }}
- {% endfor %} -
-
-{% endif %} - -{% if not temporada_actual %} -
-
-
No hay ninguna temporada activa. Activa una temporada desde Gestión de Temporadas.
-
-
-{% else %} - -{# ── Bloque 1: 4 tarjetas resumen ── #} -
-
-
-
-

Presupuesto Inicial

-

{{ presupuesto_inicial|floatformat:2 }} €

-
-
-
-
-
-
-

Total Ingresos

-

+{{ total_ingresos|floatformat:2 }} €

-
-
-
-
-
-
-

Total Gastos

-

-{{ total_gastos|floatformat:2 }} €

-
-
-
-
-
-
-

Presupuesto Actual

-

- {{ presupuesto_actual|floatformat:2 }} € -

-
-
-
-
- -{# ── Bloque 2: Gastos | Ingresos ── #} -
- - {# Columna Gastos #} -
-
-
-
-
Gastos
- -
-
- {% if gastos %} -
    - {% for gasto in gastos %} -
  • -
    -
    {{ gasto.concepto }}
    -
    {{ gasto.get_categoria_display }} · {{ gasto.fecha|date:"d/m/Y" }}
    -
    - -{{ gasto.importe|floatformat:2 }} € -
  • - {% endfor %} -
- {% else %} -

Sin gastos registrados.

- {% endif %} -
-
-
-
- - {# Columna Ingresos #} -
-
-
-
-
Ingresos
- -
-
- {% if ingresos %} -
    - {% for ingreso in ingresos %} -
  • -
    -
    {{ ingreso.concepto }}
    -
    {{ ingreso.get_categoria_display }} · {{ ingreso.fecha|date:"d/m/Y" }}
    -
    - +{{ ingreso.importe|floatformat:2 }} € -
  • - {% endfor %} -
- {% else %} -

Sin ingresos registrados.

- {% endif %} -
-
-
-
-
- -{# ── Bloque 3: Facturas pendientes ── #} -
-
-
-
-
Facturas Pendientes
-
- - - - - - - - - - - - {% for factura in facturas_pendientes %} - - - - - - - - {% empty %} - - - - {% endfor %} - -
NombreEmpresaImporteCategoríaAcciones
{{ factura.nombre }}{{ factura.empresa }}{{ factura.importe|floatformat:2 }} €{{ factura.get_categoria_display }} -
- {% csrf_token %} - -
-
- {% csrf_token %} - -
-
No hay facturas pendientes.
-
-
-
-
-
- -{% endif %}{# end if temporada_actual #} - -{# ── Modal Añadir Gasto ── #} - - -{# ── Modal Añadir Ingreso ── #} - - -{% endblock content %} diff --git a/Plataform_Web/templates/detalle_prueba.html b/Plataform_Web/templates/detalle_prueba.html deleted file mode 100644 index 1a8d889..0000000 --- a/Plataform_Web/templates/detalle_prueba.html +++ /dev/null @@ -1,112 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}{{ prueba.nombre }} | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-
-

{{ prueba.nombre }}

-

{{ prueba.get_categoria_display }} · Temporada {{ prueba.temporada.nombre }}

-
-
- {% if puede_editar %} - Editar - {% endif %} - {% if user.rol == 'directiva' %} - - {% endif %} -
-
-
-
- -
- - {% if messages %} -
- {% for message in messages %} -
{{ message }}
- {% endfor %} -
- {% endif %} - -
-
-
-
Objetivo / Descripción
-

{{ prueba.descripcion }}

- -
-
Fecha inicio: {{ prueba.fecha_inicio|date:"d/m/Y" }}
-
Fecha fin: {{ prueba.fecha_fin|date:"d/m/Y" }}
-
-

Realizado por: {{ prueba.realizado_por.first_name|default:"—" }}

- - {% if prueba.resultados %} -
Conclusiones y Resultados
-

{{ prueba.resultados }}

- {% endif %} -
-
-
- -
-
-
-
Archivos de telemetría
-
    - {% for telemetria in prueba.archivos_telemetria.all %} -
  • - {{ telemetria.nombre }} - {{ telemetria.fecha_subida|date:"d/m/Y" }} -
  • - {% empty %} -
  • No hay archivos subidos todavía.
  • - {% endfor %} -
- - {% if puede_subir_csv %} -
- {% csrf_token %} -
- - {{ form_csv.nombre }} -
-
- - {{ form_csv.archivo_csv }} -
- -
- {% endif %} -
-
-
-
- -{% if user.rol == 'directiva' %} - -{% endif %} -{% endblock content %} diff --git a/Plataform_Web/templates/editar_patrocinio.html b/Plataform_Web/templates/editar_patrocinio.html deleted file mode 100644 index 0b7d0bc..0000000 --- a/Plataform_Web/templates/editar_patrocinio.html +++ /dev/null @@ -1,44 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Editar Patrocinio | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-

Editar Patrocinio

-

{{ patrocinio.empresa }}

-
-
-
- -
-
-
-
-
Datos del Patrocinio
- -
- {% csrf_token %} - - {% for field in form %} -
- - {{ field }} - {% for error in field.errors %} -
{{ error }}
- {% endfor %} -
- {% endfor %} - -
- - Cancelar -
-
-
-
-
-
-{% endblock content %} diff --git a/Plataform_Web/templates/editar_prueba.html b/Plataform_Web/templates/editar_prueba.html deleted file mode 100644 index 1e7e012..0000000 --- a/Plataform_Web/templates/editar_prueba.html +++ /dev/null @@ -1,102 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}{% if prueba %}Editar Test{% else %}Nuevo Test{% endif %} | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-

{% if prueba %}Editar Test{% else %}Nuevo Test{% endif %}

-

{% if prueba %}{{ prueba.nombre }}{% else %}Rellena los datos del nuevo test.{% endif %}

-
-
-
- -
-
-
-
- -
- {% csrf_token %} - -
- - - {% for error in form.nombre.errors %} -
{{ error }}
- {% endfor %} -
- -
- - - {% for error in form.descripcion.errors %} -
{{ error }}
- {% endfor %} -
- -
-
- - {{ form.fecha_inicio }} - {% for error in form.fecha_inicio.errors %} -
{{ error }}
- {% endfor %} -
-
- - {{ form.fecha_fin }} - {% for error in form.fecha_fin.errors %} -
{{ error }}
- {% endfor %} -
-
- -
-
- - -
-
- - - {% for error in form.temporada.errors %} -
{{ error }}
- {% endfor %} -
-
- -
- - - {% for error in form.resultados.errors %} -
{{ error }}
- {% endfor %} -
- -
- - Cancelar -
-
- -
-
-
-
-{% endblock content %} diff --git a/Plataform_Web/templates/editar_temporada.html b/Plataform_Web/templates/editar_temporada.html deleted file mode 100644 index cd7d320..0000000 --- a/Plataform_Web/templates/editar_temporada.html +++ /dev/null @@ -1,96 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}{% if temporada %}Editar Temporada{% else %}Nueva Temporada{% endif %} | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-

{% if temporada %}Editar Temporada{% else %}Nueva Temporada{% endif %}

-

{% if temporada %}{{ temporada.nombre }}{% else %}Rellena los datos de la nueva temporada.{% endif %}

-
-
-
- -
-
-
-
- -
- {% csrf_token %} - -
- - - {% for error in form.nombre.errors %} -
{{ error }}
- {% endfor %} -
- -
-
- - {{ form.fecha_inicio }} - {% for error in form.fecha_inicio.errors %} -
{{ error }}
- {% endfor %} -
-
- - {{ form.fecha_fin }} - {% for error in form.fecha_fin.errors %} -
{{ error }}
- {% endfor %} -
-
- -
- - - {% for error in form.presupuesto.errors %} -
{{ error }}
- {% endfor %} -
- -
- - -
Solo puede haber una temporada activa. Al marcar esta se desactivarán las demás automáticamente.
-
- -
- -
- {% for checkbox in form.miembros %} -
- {{ checkbox.tag }} - -
- {% empty %} - No hay usuarios en el sistema. - {% endfor %} -
-
- -
- - Cancelar -
-
- -
-
-
-
-{% endblock content %} diff --git a/Plataform_Web/templates/editar_usuario.html b/Plataform_Web/templates/editar_usuario.html deleted file mode 100644 index 9e107d8..0000000 --- a/Plataform_Web/templates/editar_usuario.html +++ /dev/null @@ -1,70 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Editar Usuario | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-

Editar Usuario

-

{{ usuario.username }}

-
-
-
- -
-
-
-
-
Datos del Usuario
- -
- {% csrf_token %} - -
- - {{ form.username }} - {% for error in form.username.errors %} -
{{ error }}
- {% endfor %} -
- -
-
- - {{ form.first_name }} -
-
- - {{ form.last_name }} -
-
- -
- - {{ form.email }} - {% for error in form.email.errors %} -
{{ error }}
- {% endfor %} -
- -
-
- - {{ form.rol }} -
-
- - {{ form.especialidad }} -
-
- - - Cancelar -
-
-
-
-
-{% endblock content %} diff --git a/Plataform_Web/templates/gestion_temporadas.html b/Plataform_Web/templates/gestion_temporadas.html deleted file mode 100644 index 404f3b9..0000000 --- a/Plataform_Web/templates/gestion_temporadas.html +++ /dev/null @@ -1,100 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Gestión de Temporadas | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-
-

Gestión de Temporadas

-

Crea, edita y elimina temporadas del equipo.

-
- + Nueva Temporada -
-
-
- -
- - {% if messages %} -
- {% for message in messages %} -
{{ message }}
- {% endfor %} -
- {% endif %} - -
-
-
- -
- - - - - - - - - - - - - - {% for temporada in temporadas %} - - - - - - - - - - - - {% empty %} - - - - {% endfor %} - -
NombreFecha inicioFecha finPresupuestoMiembrosEstadoAcciones
{{ temporada.nombre }}{{ temporada.fecha_inicio|date:"d/m/Y" }}{{ temporada.fecha_fin|date:"d/m/Y" }}{{ temporada.presupuesto|floatformat:2 }} €{{ temporada.miembros.count }} - {% if temporada.actual %} - Activa - {% else %} - Anterior - {% endif %} - - Editar - -
No hay temporadas creadas todavía.
-
- -
-
-
-
-{% endblock content %} diff --git a/Plataform_Web/templates/gestion_usuarios.html b/Plataform_Web/templates/gestion_usuarios.html deleted file mode 100644 index 312d10e..0000000 --- a/Plataform_Web/templates/gestion_usuarios.html +++ /dev/null @@ -1,125 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Gestión de Usuarios | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-

Gestión de Usuarios

-

Administra las cuentas del sistema: edita o elimina usuarios.

-
-
-
- -
- - {% if messages %} -
- {% for message in messages %} -
{{ message }}
- {% endfor %} -
- {% endif %} - -
-
-
- -
-
- - -
- -
- - -
- -
- - -
- -
- - {% if filtro_rol or filtro_especialidad or filtro_apellido %} - × - {% endif %} -
-
- -
- - - - - - - - - - - - - - {% for usuario in usuarios %} - - - - - - - - - - - - {% empty %} - - - - {% endfor %} - -
UsuarioNombreApellidosEmailÁrea TécnicaRolAcciones
{{ usuario.username }}{{ usuario.first_name }}{{ usuario.last_name }}{{ usuario.email }}{{ usuario.get_especialidad_display|default:"—" }}{{ usuario.get_rol_display }} - Editar - -
No se han encontrado usuarios con los filtros seleccionados.
-
- -
-
-
-
-{% endblock content %} diff --git a/Plataform_Web/templates/index.html b/Plataform_Web/templates/index.html deleted file mode 100644 index a3a931a..0000000 --- a/Plataform_Web/templates/index.html +++ /dev/null @@ -1,115 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Inicio | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-
-

Bienvenido, {{ user.first_name }} {{ user.last_name }}

-

Panel de control de la plataforma de gestión interna.

-
-
- - Temporada Activa: {% if temporada_actual %}{{ temporada_actual.nombre }}{% else %}Ninguna activa{% endif %} - -
-
-
-
- -
- -
-
- Monoplaza Formula Gades -
-
- -
-
- - {% if user.rol != 'directiva' %} - -
-
-
-
Mi Área Técnica
-

Acceso a documentación, planos y buzón de compras de tu departamento.

- Acceder a mi Área -
-
-
- -
-
-
-
Pruebas y Telemetría
-

Carga de archivos de registros CSV y procesamiento analítico de telemetría.

- Ver Telemetría -
-
-
- -
-
-
-
Miembros del Equipo
-

Directorio completo de integrantes, correos corporativos y roles.

- Ver Directorio -
-
-
- - {% else %} - -
-
-
-
Pruebas y Telemetría
-

Carga de archivos de registros CSV y procesamiento analítico de telemetría.

- Ver Telemetría -
-
-
- -
-
-
-
Miembros del Equipo
-

Directorio completo de integrantes, correos corporativos y roles.

- Ver Directorio -
-
-
- -
-
-
-
Contabilidad Global
-

Supervisión del presupuesto anual y control del buzón financiero de facturas.

- Gestionar Finanzas -
-
-
- -
-
-
-
Administración del Sistema
-

Módulo avanzado de configuración de permisos, usuarios y temporadas.

- Panel de Control -
-
-
- - {% endif %} - -
-
- -
-{% endblock content %} \ No newline at end of file diff --git a/Plataform_Web/templates/listado_miembros.html b/Plataform_Web/templates/listado_miembros.html deleted file mode 100644 index 5746c3a..0000000 --- a/Plataform_Web/templates/listado_miembros.html +++ /dev/null @@ -1,90 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Miembros | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-

Miembros del Equipo

-

Directorio completo de integrantes de Formula Gades.

-
-
-
- -
-
-
-
- -
-
- - -
- -
- - -
- -
- - -
- -
- - {% if filtro_rol or filtro_especialidad or filtro_apellido %} - × - {% endif %} -
-
- -
- - - - - - - - - - - - - {% for miembro in miembros %} - - - - - - - - - {% empty %} - - - - {% endfor %} - -
UsuarioNombreApellidosEmailÁrea TécnicaRol
{{ miembro.username }}{{ miembro.first_name }}{{ miembro.last_name }}{{ miembro.email }}{{ miembro.get_especialidad_display|default:"—" }}{{ miembro.get_rol_display }}
No se han encontrado miembros con los filtros seleccionados.
-
- -
-
-
-
-{% endblock content %} diff --git a/Plataform_Web/templates/listado_pruebas.html b/Plataform_Web/templates/listado_pruebas.html deleted file mode 100644 index 7741beb..0000000 --- a/Plataform_Web/templates/listado_pruebas.html +++ /dev/null @@ -1,91 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Pruebas | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-
-

Pruebas

-

Tests realizados durante la temporada.

-
- {% if user.rol == 'directiva' or user.rol == 'jefe_area' %} - + Nuevo Test - {% endif %} -
-
-
- -
- - {% if messages %} -
- {% for message in messages %} -
{{ message }}
- {% endfor %} -
- {% endif %} - -
-
-
- -
-
- - -
-
- - -
-
- -
-
- -
- - - - - - - - - - - - {% for prueba in pruebas %} - - - - - - - - {% empty %} - - - - {% endfor %} - -
NombreFecha inicioFecha finCategoríaRealizado por
{{ prueba.nombre }}{{ prueba.fecha_inicio|date:"d/m/Y" }}{{ prueba.fecha_fin|date:"d/m/Y" }}{{ prueba.get_categoria_display }}{{ prueba.realizado_por.first_name|default:"—" }}
No hay tests todavía.
-
- -
-
-
-
-{% endblock content %} diff --git a/Plataform_Web/templates/login.html b/Plataform_Web/templates/login.html deleted file mode 100644 index 11950dd..0000000 --- a/Plataform_Web/templates/login.html +++ /dev/null @@ -1,97 +0,0 @@ -{% load static %} - - - - - - Iniciar Sesión | Formula Gades - - - - - - - - - - - - diff --git a/Plataform_Web/templates/mi_perfil.html b/Plataform_Web/templates/mi_perfil.html deleted file mode 100644 index 2b73724..0000000 --- a/Plataform_Web/templates/mi_perfil.html +++ /dev/null @@ -1,121 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Mi Perfil | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-

Mi Perfil

-

Consulta y edita tus datos personales.

-
-
-
- -
- - {% if messages %} -
- {% for message in messages %} -
{{ message }}
- {% endfor %} -
- {% endif %} - -
-
-
-
Datos Personales
- -
-
- - -
-
- - -
-
- -
- {% csrf_token %} - -
- - {{ perfil_form.username }} - {% for error in perfil_form.username.errors %} -
{{ error }}
- {% endfor %} -
- -
-
- - {{ perfil_form.first_name }} -
-
- - {{ perfil_form.last_name }} -
-
- -
- - {{ perfil_form.email }} - {% for error in perfil_form.email.errors %} -
{{ error }}
- {% endfor %} -
- - -
-
-
-
- -
-
-
-
Cambiar Contraseña
- -
- {% csrf_token %} - -
- - - {% for error in password_form.old_password.errors %} -
{{ error }}
- {% endfor %} -
- -
- - - {% for error in password_form.new_password1.errors %} -
{{ error }}
- {% endfor %} -
- -
- - - {% for error in password_form.new_password2.errors %} -
{{ error }}
- {% endfor %} -
- - {% if password_form.non_field_errors %} -
{{ password_form.non_field_errors }}
- {% endif %} - - -
-
-
-
- -
-{% endblock content %} diff --git a/Plataform_Web/templates/patrocinios.html b/Plataform_Web/templates/patrocinios.html deleted file mode 100644 index 189321b..0000000 --- a/Plataform_Web/templates/patrocinios.html +++ /dev/null @@ -1,269 +0,0 @@ -{% extends 'base.html' %} -{% load static %} - -{% block title %}Patrocinios | Gades Manager{% endblock title %} - -{% block content %} -
-
-
-
-

Patrocinios

-

Dossiers y gestión de patrocinadores del equipo.

-
- -
-
-
- -{% if messages %} -
-
- {% for message in messages %} -
{{ message }}
- {% endfor %} -
-
-{% endif %} - -
- - {# ── Bloque 1: Dossiers PDF ── #} -
-
-
-
- - - - -
-
Dossier de Patrocinio
-

Versión en español · Temporada 2025/2026

- -
-
-
- -
-
-
-
- - - - -
-
Sponsorship Dossier
-

English version · Season 2025/2026

-
- Open - Download -
-
-
-
- - {# ── Bloque 2: Patrocinios agrupados ── #} -
- - {% if not temporada_actual %} -
No hay temporada activa. Activa una desde Gestión de Temporadas.
- {% else %} - - {# Pendientes #} -
-
- {{ pendientes.count }} -
Pendientes / En contacto
-
-
-
- - - - - - - - - - {% if user.rol == 'directiva' %}{% endif %} - - - - {% for p in pendientes %} - - - - - - - - {% if user.rol == 'directiva' %} - - {% endif %} - - {% empty %} - - {% endfor %} - -
EmpresaTipoPersona contactoEmailPropuesto porFechaAcciones
{{ p.empresa }}{{ p.get_tipo_patrocinio_display }}{{ p.persona_contacto|default:"—" }}{{ p.email_contacto }}{{ p.contacto_equipo.get_full_name|default:p.contacto_equipo }}{{ p.fecha_contacto|date:"d/m/Y" }} -
-
- {% csrf_token %} - - -
-
- {% csrf_token %} - - -
- Editar -
-
No hay patrocinios pendientes.
-
-
-
- - {# Aceptados #} -
-
- {{ aceptados.count }} -
Aceptados
-
-
-
- - - - - - - - - - {% if user.rol == 'directiva' %}{% endif %} - - - - {% for p in aceptados %} - - - - - - - - {% if user.rol == 'directiva' %} - - {% endif %} - - {% empty %} - - {% endfor %} - -
EmpresaTipoImportePersona contactoEmailFechaAcciones
{{ p.empresa }}{{ p.get_tipo_patrocinio_display }}{{ p.importe_economico|floatformat:2 }} €{{ p.persona_contacto|default:"—" }}{{ p.email_contacto }}{{ p.fecha_contacto|date:"d/m/Y" }} -
-
- {% csrf_token %} - - -
- Editar -
-
No hay patrocinios aceptados.
-
-
-
- - {# Rechazados — colapsado por defecto #} -
-
- {{ denegados.count }} -
Rechazados
- -
-
-
- - - - - - - - - {% if user.rol == 'directiva' %}{% endif %} - - - - {% for p in denegados %} - - - - - - - {% if user.rol == 'directiva' %} - - {% endif %} - - {% empty %} - - {% endfor %} - -
EmpresaTipoPersona contactoEmailFechaAcciones
{{ p.empresa }}{{ p.get_tipo_patrocinio_display }}{{ p.persona_contacto|default:"—" }}{{ p.email_contacto }}{{ p.fecha_contacto|date:"d/m/Y" }} -
-
- {% csrf_token %} - - -
- Editar -
-
No hay patrocinios rechazados.
-
-
-
- - {% endif %}{# end if temporada_actual #} -
-
- -{# ── Modal Proponer Patrocinio ── #} - - -{% endblock content %} diff --git a/Plataform_Web/temporadas/__init__.py b/Plataform_Web/temporadas/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/temporadas/admin.py b/Plataform_Web/temporadas/admin.py deleted file mode 100644 index 8420191..0000000 --- a/Plataform_Web/temporadas/admin.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.contrib import admin -from .models import Temporada - -@admin.register(Temporada) -class TemporadaAdmin(admin.ModelAdmin): - # Columnas principales. - list_display = ('nombre', 'fecha_inicio', 'fecha_fin', 'presupuesto', 'actual') - - # Permite marcar o desmarcar el check de "actual" directamente desde la tabla, sin entrar al detalle - list_editable = ('actual',) - - # Filtro para filtrar por temporadas históricas o actual - list_filter = ('actual',) - - # Buscador de temporadas por nombre - search_fields = ('nombre',) - - # Filtro para ver los miembros de una temporada - filter_horizontal = ('miembros',) \ No newline at end of file diff --git a/Plataform_Web/temporadas/apps.py b/Plataform_Web/temporadas/apps.py deleted file mode 100644 index 1a7e5b5..0000000 --- a/Plataform_Web/temporadas/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class TemporadasConfig(AppConfig): - name = 'temporadas' diff --git a/Plataform_Web/temporadas/forms.py b/Plataform_Web/temporadas/forms.py deleted file mode 100644 index 4788a5d..0000000 --- a/Plataform_Web/temporadas/forms.py +++ /dev/null @@ -1,13 +0,0 @@ -from django import forms -from .models import Temporada - - -class TemporadaForm(forms.ModelForm): - class Meta: - model = Temporada - fields = ['nombre', 'fecha_inicio', 'fecha_fin', 'presupuesto', 'actual', 'miembros'] - widgets = { - 'fecha_inicio': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}), - 'fecha_fin': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}), - 'miembros': forms.CheckboxSelectMultiple(), - } diff --git a/Plataform_Web/temporadas/migrations/0001_initial.py b/Plataform_Web/temporadas/migrations/0001_initial.py deleted file mode 100644 index ba154fb..0000000 --- a/Plataform_Web/temporadas/migrations/0001_initial.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 6.0.2 on 2026-02-17 11:28 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='Temporada', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nombre', models.CharField(max_length=50, unique=True)), - ('fecha_inicio', models.DateField()), - ('fecha_fin', models.DateField()), - ('presupuesto', models.DecimalField(decimal_places=2, default=0.0, max_digits=10)), - ('actual', models.BooleanField(default=False, verbose_name='¿Es la temporada actual?')), - ], - options={ - 'verbose_name': 'Temporada', - 'verbose_name_plural': 'Temporadas', - 'ordering': ['-fecha_inicio'], - }, - ), - ] diff --git a/Plataform_Web/temporadas/migrations/0002_temporada_miembros.py b/Plataform_Web/temporadas/migrations/0002_temporada_miembros.py deleted file mode 100644 index b32fb3d..0000000 --- a/Plataform_Web/temporadas/migrations/0002_temporada_miembros.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 6.0.2 on 2026-03-06 19:29 - -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('temporadas', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AddField( - model_name='temporada', - name='miembros', - field=models.ManyToManyField(blank=True, related_name='temporadas_participadas', to=settings.AUTH_USER_MODEL, verbose_name='Miembros del equipo'), - ), - ] diff --git a/Plataform_Web/temporadas/migrations/__init__.py b/Plataform_Web/temporadas/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/temporadas/models.py b/Plataform_Web/temporadas/models.py deleted file mode 100644 index 7d0e19c..0000000 --- a/Plataform_Web/temporadas/models.py +++ /dev/null @@ -1,39 +0,0 @@ -from django.db import models -from django.conf import settings - -class Temporada(models.Model): - # El nombre será algo como "Gades 2024-25" - nombre = models.CharField(max_length=50, unique=True) - - fecha_inicio = models.DateField() - fecha_fin = models.DateField() - - # Presupuesto total para ese año - presupuesto = models.DecimalField(max_digits=10, decimal_places=2, default=0.00) - - # Checkbox para marcar cuál es la temporada que estamos viviendo ahora - actual = models.BooleanField(default=False, verbose_name="¿Es la temporada actual?") - - # Relaciones - # Relacion N a N con miembros - miembros = models.ManyToManyField( - settings.AUTH_USER_MODEL, - related_name="temporadas_participadas", - blank=True, - verbose_name="Miembros del equipo" - ) - - class Meta: - verbose_name = "Temporada" - verbose_name_plural = "Temporadas" - ordering = ['-fecha_inicio'] # Ordena las más nuevas primero - - def __str__(self): - return self.nombre - - def save(self, *args, **kwargs): - # TRUCO PRO: Si marco esta temporada como "actual", desmarco todas las demás - # Así evitamos que haya dos temporadas activas a la vez. - if self.actual: - Temporada.objects.filter(actual=True).exclude(pk=self.pk).update(actual=False) - super().save(*args, **kwargs) \ No newline at end of file diff --git a/Plataform_Web/temporadas/tests.py b/Plataform_Web/temporadas/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/Plataform_Web/temporadas/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/Plataform_Web/temporadas/views.py b/Plataform_Web/temporadas/views.py deleted file mode 100644 index 1db3713..0000000 --- a/Plataform_Web/temporadas/views.py +++ /dev/null @@ -1,42 +0,0 @@ -from django.shortcuts import render, redirect, get_object_or_404 -from django.contrib import messages -from django.views.decorators.http import require_POST -from users.decorators import require_rol -from .models import Temporada -from .forms import TemporadaForm - - -@require_rol('directiva') -def gestion_temporadas(request): - temporadas = Temporada.objects.all() - return render(request, 'gestion_temporadas.html', {'temporadas': temporadas}) - - -@require_rol('directiva') -def crear_temporada(request): - form = TemporadaForm(request.POST or None) - if request.method == 'POST' and form.is_valid(): - form.save() - messages.success(request, 'Temporada creada correctamente.') - return redirect('gestion_temporadas') - return render(request, 'editar_temporada.html', {'form': form, 'temporada': None}) - - -@require_rol('directiva') -def editar_temporada(request, pk): - temporada = get_object_or_404(Temporada, pk=pk) - form = TemporadaForm(request.POST or None, instance=temporada) - if request.method == 'POST' and form.is_valid(): - form.save() - messages.success(request, 'Temporada actualizada correctamente.') - return redirect('gestion_temporadas') - return render(request, 'editar_temporada.html', {'form': form, 'temporada': temporada}) - - -@require_rol('directiva') -@require_POST -def eliminar_temporada(request, pk): - temporada = get_object_or_404(Temporada, pk=pk) - temporada.delete() - messages.success(request, f'Temporada "{temporada.nombre}" eliminada.') - return redirect('gestion_temporadas') diff --git a/Plataform_Web/users/__init__.py b/Plataform_Web/users/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/users/admin.py b/Plataform_Web/users/admin.py deleted file mode 100644 index 81671c8..0000000 --- a/Plataform_Web/users/admin.py +++ /dev/null @@ -1,27 +0,0 @@ -from django.contrib import admin -from django.contrib.auth.admin import UserAdmin -from .models import CustomUser - -@admin.register(CustomUser) -class CustomUserAdmin(UserAdmin): - list_display = ('username', 'first_name', 'last_name', 'rol', 'especialidad', 'is_staff') - - # Filtramos por rol y área técnica - list_filter = ('rol', 'especialidad', 'is_staff', 'is_active') - - # Buscador de usuarios - search_fields = ('username', 'first_name', 'last_name', 'email') - - # Para editar al usuario con los datos insertados - fieldsets = UserAdmin.fieldsets + ( - ('Información del Equipo Gades', { - 'fields': ('rol', 'especialidad'), - }), - ) - - # Para crear al usuario con los datos insertados - add_fieldsets = UserAdmin.add_fieldsets + ( - ('Información del Equipo Gades', { - 'fields': ('rol', 'especialidad'), - }), - ) \ No newline at end of file diff --git a/Plataform_Web/users/apps.py b/Plataform_Web/users/apps.py deleted file mode 100644 index 4ce1fab..0000000 --- a/Plataform_Web/users/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class UsersConfig(AppConfig): - name = 'users' diff --git a/Plataform_Web/users/decorators.py b/Plataform_Web/users/decorators.py deleted file mode 100644 index 28cd93a..0000000 --- a/Plataform_Web/users/decorators.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.contrib.auth.decorators import login_required, user_passes_test - - -def require_rol(*roles): - def decorator(view_func): - return login_required(user_passes_test(lambda u: u.rol in roles)(view_func)) - return decorator diff --git a/Plataform_Web/users/forms.py b/Plataform_Web/users/forms.py deleted file mode 100644 index 0d096c3..0000000 --- a/Plataform_Web/users/forms.py +++ /dev/null @@ -1,42 +0,0 @@ -from django import forms -from .models import CustomUser - - -class PerfilForm(forms.ModelForm): - class Meta: - model = CustomUser - fields = ['username', 'first_name', 'last_name', 'email'] - widgets = { - 'username': forms.TextInput(attrs={'class': 'form-control'}), - 'first_name': forms.TextInput(attrs={'class': 'form-control'}), - 'last_name': forms.TextInput(attrs={'class': 'form-control'}), - 'email': forms.EmailInput(attrs={'class': 'form-control'}), - } - labels = { - 'username': 'Usuario', - 'first_name': 'Nombre', - 'last_name': 'Apellidos', - 'email': 'Correo electrónico', - } - - -class EditarUsuarioForm(forms.ModelForm): - class Meta: - model = CustomUser - fields = ['username', 'first_name', 'last_name', 'email', 'rol', 'especialidad'] - widgets = { - 'username': forms.TextInput(attrs={'class': 'form-control'}), - 'first_name': forms.TextInput(attrs={'class': 'form-control'}), - 'last_name': forms.TextInput(attrs={'class': 'form-control'}), - 'email': forms.EmailInput(attrs={'class': 'form-control'}), - 'rol': forms.Select(attrs={'class': 'form-select'}), - 'especialidad': forms.Select(attrs={'class': 'form-select'}), - } - labels = { - 'username': 'Usuario', - 'first_name': 'Nombre', - 'last_name': 'Apellidos', - 'email': 'Correo electrónico', - 'rol': 'Rol en el equipo', - 'especialidad': 'Área técnica', - } diff --git a/Plataform_Web/users/migrations/0001_initial.py b/Plataform_Web/users/migrations/0001_initial.py deleted file mode 100644 index fedfc57..0000000 --- a/Plataform_Web/users/migrations/0001_initial.py +++ /dev/null @@ -1,46 +0,0 @@ -# Generated by Django 6.0.2 on 2026-02-17 10:36 - -import django.contrib.auth.models -import django.contrib.auth.validators -import django.utils.timezone -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('auth', '0012_alter_user_first_name_max_length'), - ] - - operations = [ - migrations.CreateModel( - name='CustomUser', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('password', models.CharField(max_length=128, verbose_name='password')), - ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), - ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), - ('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')), - ('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')), - ('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')), - ('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')), - ('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')), - ('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), - ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), - ('rol', models.CharField(choices=[('directiva', 'Directiva'), ('jefe_area', 'Jefe de Área'), ('empleado', 'Empleado')], default='empleado', max_length=20)), - ('especialidad', models.CharField(blank=True, choices=[('aerodinamica', 'Aerodinámica'), ('chasis', 'Chasis'), ('business', 'Business & Operations'), ('epowertrain', 'E-Powertrain'), ('electronica', 'Electrónica'), ('sdf', 'SDF'), ('motor_transmision', 'Motor & Transmisión'), ('software', 'Software')], max_length=30, null=True)), - ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), - ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), - ], - options={ - 'verbose_name': 'user', - 'verbose_name_plural': 'users', - 'abstract': False, - }, - managers=[ - ('objects', django.contrib.auth.models.UserManager()), - ], - ), - ] diff --git a/Plataform_Web/users/migrations/0002_alter_customuser_especialidad_alter_customuser_rol.py b/Plataform_Web/users/migrations/0002_alter_customuser_especialidad_alter_customuser_rol.py deleted file mode 100644 index 9c991e1..0000000 --- a/Plataform_Web/users/migrations/0002_alter_customuser_especialidad_alter_customuser_rol.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 6.0.2 on 2026-02-17 11:15 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='customuser', - name='especialidad', - field=models.CharField(blank=True, choices=[('aerodinamica', 'Aerodinámica'), ('chasis', 'Chasis'), ('business', 'Business & Operations'), ('epowertrain', 'E-Powertrain'), ('electronica', 'Electrónica'), ('sdf', 'SDF'), ('motor_transmision', 'Motor & Transmisión'), ('software', 'Software')], max_length=30, null=True, verbose_name='Área Técnica'), - ), - migrations.AlterField( - model_name='customuser', - name='rol', - field=models.CharField(choices=[('directiva', 'Directiva'), ('jefe_area', 'Jefe de Área'), ('empleado', 'Empleado')], default='empleado', max_length=20, verbose_name='Rol en el equipo'), - ), - ] diff --git a/Plataform_Web/users/migrations/0003_alter_customuser_especialidad_alter_customuser_rol.py b/Plataform_Web/users/migrations/0003_alter_customuser_especialidad_alter_customuser_rol.py deleted file mode 100644 index 68dc9a3..0000000 --- a/Plataform_Web/users/migrations/0003_alter_customuser_especialidad_alter_customuser_rol.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 6.0.2 on 2026-03-06 19:29 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0002_alter_customuser_especialidad_alter_customuser_rol'), - ] - - operations = [ - migrations.AlterField( - model_name='customuser', - name='especialidad', - field=models.CharField(blank=True, choices=[('aerodinamica', 'Aerodinámica'), ('chasis', 'Chasis'), ('business_operations', 'Business & Operations'), ('epowertrain', 'E-Powertrain'), ('electronica', 'Electrónica'), ('sdf', 'SDF'), ('motor_transmision', 'Motor & Transmisión'), ('software', 'Software')], max_length=30, null=True, verbose_name='Área Técnica'), - ), - migrations.AlterField( - model_name='customuser', - name='rol', - field=models.CharField(choices=[('directiva', 'Directiva'), ('jefe_area', 'Jefe de Área'), ('miembro', 'Miembro')], default='miembro', max_length=20, verbose_name='Rol en el equipo'), - ), - ] diff --git a/Plataform_Web/users/migrations/__init__.py b/Plataform_Web/users/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Plataform_Web/users/models.py b/Plataform_Web/users/models.py deleted file mode 100644 index 2661b57..0000000 --- a/Plataform_Web/users/models.py +++ /dev/null @@ -1,43 +0,0 @@ -from django.contrib.auth.models import AbstractUser -from django.db import models - -class CustomUser(AbstractUser): - # --- 1. OPCIONES (El Menú) --- - ROL_CHOICES = ( - ('directiva', 'Directiva'), - ('jefe_area', 'Jefe de Área'), - ('miembro', 'Miembro'), - ) - - ESPECIALIDAD_CHOICES = ( - ('aerodinamica', 'Aerodinámica'), - ('chasis', 'Chasis'), - ('business_operations', 'Business & Operations'), - ('epowertrain', 'E-Powertrain'), - ('electronica', 'Electrónica'), - ('sdf', 'SDF'), - ('motor_transmision', 'Motor & Transmisión'), - ('software', 'Software'), - ) - - # --- 2. CAMPOS (Las Columnas en la BD) --- - # Usamos la versión con 'verbose_name' porque queda mejor en la web - rol = models.CharField( - max_length=20, - choices=ROL_CHOICES, - default='miembro', - verbose_name="Rol en el equipo" - ) - - especialidad = models.CharField( - max_length=30, - choices=ESPECIALIDAD_CHOICES, - null=True, - blank=True, - verbose_name="Área Técnica" - ) - - # --- 3. MÉTODOS --- - def __str__(self): - # Muestra: "Nombre Apellido (usuario) - Rol" - return f"{self.first_name} {self.last_name} ({self.username}) - {self.get_rol_display()}" \ No newline at end of file diff --git a/Plataform_Web/users/tests.py b/Plataform_Web/users/tests.py deleted file mode 100644 index 7ce503c..0000000 --- a/Plataform_Web/users/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/Plataform_Web/users/views.py b/Plataform_Web/users/views.py deleted file mode 100644 index 4a7fc52..0000000 --- a/Plataform_Web/users/views.py +++ /dev/null @@ -1,119 +0,0 @@ -from django.shortcuts import render, redirect, get_object_or_404 -from django.contrib.auth.decorators import login_required -from django.contrib.auth.forms import PasswordChangeForm -from django.contrib.auth import update_session_auth_hash -from django.contrib import messages -from django.views.decorators.http import require_POST -from .decorators import require_rol -from .forms import PerfilForm, EditarUsuarioForm -from .models import CustomUser - - -@login_required -def index(request): - return render(request, 'index.html') - - -@login_required -def mi_perfil(request): - perfil_form = PerfilForm(instance=request.user) - password_form = PasswordChangeForm(user=request.user) - - if request.method == 'POST': - if 'guardar_perfil' in request.POST: - perfil_form = PerfilForm(request.POST, instance=request.user) - if perfil_form.is_valid(): - perfil_form.save() - messages.success(request, 'Tus datos se han actualizado correctamente.') - return redirect('mi_perfil') - - elif 'cambiar_password' in request.POST: - password_form = PasswordChangeForm(user=request.user, data=request.POST) - if password_form.is_valid(): - user = password_form.save() - update_session_auth_hash(request, user) - messages.success(request, 'Tu contraseña se ha cambiado correctamente.') - return redirect('mi_perfil') - - context = { - 'perfil_form': perfil_form, - 'password_form': password_form, - } - return render(request, 'mi_perfil.html', context) - - -@login_required -def listado_miembros(request): - miembros = CustomUser.objects.all().order_by('last_name', 'first_name') - - rol = request.GET.get('rol', '') - especialidad = request.GET.get('especialidad', '') - apellido = request.GET.get('apellido', '') - - if rol: - miembros = miembros.filter(rol=rol) - if especialidad: - miembros = miembros.filter(especialidad=especialidad) - if apellido: - miembros = miembros.filter(last_name__icontains=apellido) - - context = { - 'miembros': miembros, - 'rol_choices': CustomUser.ROL_CHOICES, - 'especialidad_choices': CustomUser.ESPECIALIDAD_CHOICES, - 'filtro_rol': rol, - 'filtro_especialidad': especialidad, - 'filtro_apellido': apellido, - } - return render(request, 'listado_miembros.html', context) - - -@require_rol('directiva') -def gestion_usuarios(request): - usuarios = CustomUser.objects.all().order_by('last_name', 'first_name') - - rol = request.GET.get('rol', '') - especialidad = request.GET.get('especialidad', '') - apellido = request.GET.get('apellido', '') - - if rol: - usuarios = usuarios.filter(rol=rol) - if especialidad: - usuarios = usuarios.filter(especialidad=especialidad) - if apellido: - usuarios = usuarios.filter(last_name__icontains=apellido) - - context = { - 'usuarios': usuarios, - 'rol_choices': CustomUser.ROL_CHOICES, - 'especialidad_choices': CustomUser.ESPECIALIDAD_CHOICES, - 'filtro_rol': rol, - 'filtro_especialidad': especialidad, - 'filtro_apellido': apellido, - } - return render(request, 'gestion_usuarios.html', context) - - -@require_rol('directiva') -def editar_usuario(request, pk): - usuario = get_object_or_404(CustomUser, pk=pk) - - if request.method == 'POST': - form = EditarUsuarioForm(request.POST, instance=usuario) - if form.is_valid(): - form.save() - messages.success(request, 'El usuario se ha actualizado correctamente.') - return redirect('gestion_usuarios') - else: - form = EditarUsuarioForm(instance=usuario) - - return render(request, 'editar_usuario.html', {'form': form, 'usuario': usuario}) - - -@require_rol('directiva') -@require_POST -def eliminar_usuario(request, pk): - usuario = get_object_or_404(CustomUser, pk=pk) - usuario.delete() - messages.success(request, 'El usuario se ha eliminado correctamente.') - return redirect('gestion_usuarios')