Arch/routes/project_routes.py

240 lines
7.3 KiB
Python
Raw Normal View History

2025-03-03 15:35:24 -03:00
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify
from flask_login import login_required, current_user
from flask_wtf import FlaskForm
from wtforms import StringField, SelectField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Length
from services.project_service import (
create_project,
update_project,
get_project,
delete_project,
get_all_projects,
get_project_children,
get_project_document_count,
filter_projects,
archive_project,
2025-03-03 15:35:24 -03:00
)
from services.schema_service import get_all_schemas
from utils.security import permission_required
# Definir Blueprint
projects_bp = Blueprint("projects", __name__, url_prefix="/projects")
2025-03-03 15:35:24 -03:00
# Formularios
class ProjectForm(FlaskForm):
"""Formulario de proyecto."""
descripcion = StringField(
"Descripción", validators=[DataRequired(), Length(1, 100)]
)
cliente = StringField("Cliente", validators=[DataRequired(), Length(1, 100)])
destinacion = StringField("Destinación", validators=[Length(0, 100)])
esquema = SelectField("Esquema", validators=[DataRequired()])
proyecto_padre = SelectField("Proyecto Padre", validators=[])
submit = SubmitField("Guardar")
2025-03-03 15:35:24 -03:00
class ProjectFilterForm(FlaskForm):
"""Formulario de filtrado de proyectos."""
cliente = StringField("Cliente")
estado = SelectField(
"Estado",
choices=[("", "Todos"), ("activo", "Activo"), ("inactivo", "Inactivo")],
)
ano_inicio = StringField("Año Inicio")
ano_fin = StringField("Año Fin")
descripcion = StringField("Descripción")
submit = SubmitField("Filtrar")
2025-03-03 15:35:24 -03:00
# Rutas
@projects_bp.route("/")
2025-03-03 15:35:24 -03:00
@login_required
def list():
"""Listar proyectos."""
filter_form = ProjectFilterForm(request.args)
2025-03-03 15:35:24 -03:00
# Obtener proyectos según filtros
if request.args:
projects = filter_projects(request.args)
else:
projects = get_all_projects()
return render_template(
"projects/list.html", projects=projects, filter_form=filter_form
)
@projects_bp.route("/create", methods=["GET", "POST"])
2025-03-03 15:35:24 -03:00
@login_required
@permission_required(1000) # Nivel mínimo para crear proyectos
def create():
"""Crear nuevo proyecto."""
form = ProjectForm()
2025-03-03 15:35:24 -03:00
# Cargar opciones para esquemas
schemas = get_all_schemas()
form.esquema.choices = [
(schema["id"], schema.get("name", "") or schema.get("descripcion", ""))
for schema in schemas
]
2025-03-03 15:35:24 -03:00
# Cargar opciones para proyectos padre
projects = [(p["codigo"], p["descripcion"]) for p in get_all_projects()]
form.proyecto_padre.choices = [("", "Ninguno")] + projects
2025-03-03 15:35:24 -03:00
if form.validate_on_submit():
# Preparar datos del proyecto
project_data = {
"descripcion": form.descripcion.data,
"cliente": form.cliente.data,
"destinacion": form.destinacion.data,
"esquema": form.esquema.data,
"proyecto_padre": (
form.proyecto_padre.data if form.proyecto_padre.data else None
),
2025-03-03 15:35:24 -03:00
}
2025-03-03 15:35:24 -03:00
# Crear proyecto
success, message, project_id = create_project(
project_data, current_user.username
)
2025-03-03 15:35:24 -03:00
if success:
flash(message, "success")
return redirect(url_for("projects.view", project_id=project_id))
2025-03-03 15:35:24 -03:00
else:
flash(message, "danger")
return render_template("projects/create.html", form=form, schemas=schemas)
2025-03-03 15:35:24 -03:00
@projects_bp.route("/<project_id>")
2025-03-03 15:35:24 -03:00
@login_required
def view(project_id):
"""Ver detalles de un proyecto."""
project = get_project(project_id)
2025-03-03 15:35:24 -03:00
if not project:
flash("Proyecto no encontrado.", "danger")
return redirect(url_for("projects.list"))
2025-03-03 15:35:24 -03:00
# Obtener información adicional
children = get_project_children(project_id)
document_count = get_project_document_count(project_id)
return render_template(
"projects/view.html",
project=project,
children=children,
document_count=document_count,
)
@projects_bp.route("/<project_id>/edit", methods=["GET", "POST"])
2025-03-03 15:35:24 -03:00
@login_required
@permission_required(5000) # Nivel mínimo para editar proyectos
def edit(project_id):
"""Editar un proyecto."""
project = get_project(project_id)
2025-03-03 15:35:24 -03:00
if not project:
flash("Proyecto no encontrado.", "danger")
return redirect(url_for("projects.list"))
2025-03-03 15:35:24 -03:00
form = ProjectForm()
2025-03-03 15:35:24 -03:00
# Cargar opciones para esquemas
schemas = get_all_schemas()
form.esquema.choices = [
(schema["id"], schema.get("name", "") or schema.get("descripcion", ""))
for schema in schemas
]
2025-03-03 15:35:24 -03:00
# Cargar opciones para proyectos padre (excluyendo este proyecto y sus hijos)
all_projects = get_all_projects()
children_codes = [child["codigo"] for child in get_project_children(project_id)]
available_projects = [
(p["codigo"], p["descripcion"])
for p in all_projects
if p["codigo"] != project["codigo"] and p["codigo"] not in children_codes
]
form.proyecto_padre.choices = [("", "Ninguno")] + available_projects
if request.method == "GET":
2025-03-03 15:35:24 -03:00
# Cargar datos actuales
form.descripcion.data = project["descripcion"]
form.cliente.data = project["cliente"]
form.destinacion.data = project.get("destinacion", "")
form.esquema.data = project["esquema"]
form.proyecto_padre.data = project.get("proyecto_padre", "")
2025-03-03 15:35:24 -03:00
if form.validate_on_submit():
# Preparar datos actualizados
project_data = {
"descripcion": form.descripcion.data,
"cliente": form.cliente.data,
"destinacion": form.destinacion.data,
"esquema": form.esquema.data,
"proyecto_padre": (
form.proyecto_padre.data if form.proyecto_padre.data else None
),
2025-03-03 15:35:24 -03:00
}
2025-03-03 15:35:24 -03:00
# Actualizar proyecto
success, message = update_project(
project_id, project_data, current_user.username
)
2025-03-03 15:35:24 -03:00
if success:
flash(message, "success")
return redirect(url_for("projects.view", project_id=project_id))
2025-03-03 15:35:24 -03:00
else:
flash(message, "danger")
return render_template(
"projects/edit.html", form=form, project=project, schemas=schemas
)
2025-03-03 15:35:24 -03:00
@projects_bp.route("/<project_id>/delete", methods=["POST"])
2025-03-03 15:35:24 -03:00
@login_required
@permission_required(9000) # Nivel alto para eliminar proyectos
def delete(project_id):
"""Eliminar un proyecto (marcar como inactivo)."""
success, message = delete_project(project_id)
if success:
flash(message, "success")
else:
flash(message, "danger")
return redirect(url_for("projects.list"))
@projects_bp.route("/<project_id>/archive", methods=["POST"])
@login_required
@permission_required(9000) # Nivel alto para archivar proyectos
def archive(project_id):
"""Archivar un proyecto."""
success, message = archive_project(project_id, current_user.username)
2025-03-03 15:35:24 -03:00
if success:
flash(message, "success")
2025-03-03 15:35:24 -03:00
else:
flash(message, "danger")
return redirect(url_for("projects.list"))
2025-03-03 15:35:24 -03:00
@projects_bp.route("/api/list")
2025-03-03 15:35:24 -03:00
@login_required
def api_list():
"""API para listar proyectos (para selects dinámicos)."""
projects = get_all_projects()
return jsonify([{"id": p["codigo"], "text": p["descripcion"]} for p in projects])