feat: refactorizar espacios fisicos desacoplando Edificio, Piso y Aula con selectores en cascada y filtros

This commit is contained in:
Carlos Tello
2026-09-03 05:18:01 -03:00
parent 5e0b905e55
commit 6ccc9e8c87
11 changed files with 1093 additions and 522 deletions
+32 -19
View File
@@ -40,8 +40,8 @@ def today_schedule():
~Classroom.building.ilike('%Virtual%')
)
if floor_filter and floor_filter.isdigit():
query = query.filter(Classroom.floor == int(floor_filter))
if floor_filter:
query = query.filter(Classroom.floor == str(floor_filter).strip())
if shift_filter:
query = query.filter(Reservation.shift.ilike(f'%{shift_filter}%'))
@@ -140,9 +140,11 @@ def view_reservation(id):
def calendar_view():
"""Show calendar view with classroom, subject, career, shift, floor and virtual filtering"""
from app.models.career import Career
from app.models.building import Building
classrooms = Classroom.query.filter_by(is_active=True).order_by(Classroom.building.asc(), Classroom.code.asc()).all()
subjects = Subject.query.filter_by(is_active=True).order_by(Subject.name.asc()).all()
careers = Career.query.order_by(Career.name.asc()).all()
buildings = Building.query.filter_by(is_active=True).order_by(Building.name.asc()).all()
floors = db.session.query(Classroom.floor).filter(Classroom.is_active==True, Classroom.floor.isnot(None)).distinct().order_by(Classroom.floor.asc()).all()
available_floors = [f[0] for f in floors]
@@ -154,6 +156,7 @@ def calendar_view():
classrooms=classrooms,
subjects=subjects,
careers=careers,
buildings=buildings,
available_floors=available_floors
)
@@ -400,23 +403,23 @@ def add_reservation():
"""Add new reservation"""
from app.models.classroom import Classroom
from app.models.subject import Commission
from app.models.building import Building
form = ReservationForm()
# Get active classrooms for the dropdown
classrooms = Classroom.query.filter_by(is_active=True).all()
# Get active commissions for the dropdown
# Get active buildings and classrooms
buildings = Building.query.filter_by(is_active=True).order_by(Building.name.asc()).all()
classrooms = Classroom.query.filter_by(is_active=True).order_by(Classroom.building_id.asc(), Classroom.floor.asc(), Classroom.code.asc()).all()
commissions = Commission.query.filter_by(active=True).all()
# Populate form choices
form.classroom_id.choices = [(c.id, f'{c.building} - {c.code} (Cap: {c.capacity_display})') for c in classrooms]
form.classroom_id.choices = [(c.id, f'{c.building_name} - {c.code} (Cap: {c.capacity_display})') for c in classrooms]
form.commission_id.choices = [(c.id, f'{c.get_full_code()} - {c.subject.name if c.subject else "No Subject"} (Students: {c.max_students})') for c in commissions]
if request.method == 'POST':
if form.validate_on_submit():
try:
# Check for existing reservations at the same time
# Check for existing reservations at the same time
from app.models.reservation import ReservationStatus
existing_reservation = Reservation.query.filter_by(
classroom_id=form.classroom_id.data,
@@ -428,7 +431,7 @@ def add_reservation():
if existing_reservation:
flash('This classroom is already booked for the selected time slot.', 'danger')
return render_template('schedule/add.html', form=form, title='New Reservation', classroom_list=classrooms, commission_list=commissions)
return render_template('schedule/add.html', form=form, title='New Reservation', classroom_list=classrooms, commission_list=commissions, buildings=buildings)
# Create new reservation
reservation = Reservation(
@@ -451,10 +454,9 @@ def add_reservation():
except Exception as e:
db.session.rollback()
current_app.logger.error(f"Error creating reservation: {str(e)}")
flash(f'Error creating reservation: {str(e)}', 'danger')
return render_template('schedule/add.html', form=form, title='New Reservation', classroom_list=classrooms, commission_list=commissions)
return render_template('schedule/add.html', form=form, title='New Reservation', classroom_list=classrooms, commission_list=commissions, buildings=buildings)
@schedule_bp.route('/list')
@login_required
@@ -498,8 +500,8 @@ def list_reservations():
~Classroom.building.ilike('%Virtual%')
)
if floor_filter and floor_filter.isdigit():
query = query.filter(Classroom.floor == int(floor_filter))
if floor_filter:
query = query.filter(Classroom.floor == str(floor_filter).strip())
if shift_filter:
query = query.filter(Reservation.shift.ilike(f'%{shift_filter}%'))
@@ -666,7 +668,6 @@ def calendar_data():
search = request.args.get('search', '').strip()
if start and end:
from datetime import datetime
# Clean up ISO timezone strings for PostgreSQL naive timestamp comparison
start_clean = start.replace('Z', '+00:00')
end_clean = end.replace('Z', '+00:00')
@@ -695,6 +696,16 @@ def calendar_data():
if career_id and career_id.isdigit():
query = query.filter(Subject.career_id == int(career_id))
building = request.args.get('building', '').strip()
if building:
from app.models.building import Building
query = query.filter(
or_(
Classroom.building.ilike(f'%{building}%'),
Classroom.building_entity.has(Building.name.ilike(f'%{building}%'))
)
)
if shift:
query = query.filter(Reservation.shift.ilike(f'%{shift}%'))
@@ -704,8 +715,8 @@ def calendar_data():
~Classroom.building.ilike('%Virtual%')
)
if floor and floor.isdigit():
query = query.filter(Classroom.floor == int(floor))
if floor:
query = query.filter(Classroom.floor == str(floor).strip())
if search:
query = query.filter(
@@ -725,8 +736,9 @@ def calendar_data():
subject_code = subject.code if subject else (reservation.commission.code if reservation.commission else '')
subject_name = subject.name if subject else (reservation.purpose or 'Clase')
classroom_name = reservation.classroom.code if reservation.classroom else 'Sin Aula'
classroom_floor = reservation.classroom.floor if reservation.classroom else None
is_virtual = bool(reservation.classroom and ('VIRTUAL' in (reservation.classroom.code or '').upper() or 'VIRTUAL' in (reservation.classroom.building or '').upper()))
classroom_floor = reservation.classroom.floor_display if reservation.classroom else None
classroom_building = reservation.classroom.building_name if reservation.classroom else ''
is_virtual = bool(reservation.classroom and reservation.classroom.is_virtual)
career_name = subject.career_obj.name if (subject and subject.career_obj) else (subject.department if subject else '')
status_val = str(reservation.status.value if hasattr(reservation.status, 'value') else reservation.status)
@@ -741,9 +753,10 @@ def calendar_data():
'subject_code': subject_code,
'subject_name': subject_name,
'classroom': classroom_name,
'building': reservation.classroom.building if reservation.classroom else '',
'building': classroom_building,
'floor': classroom_floor,
'is_virtual': is_virtual,
'location_display': reservation.classroom.location_display if reservation.classroom else '',
'career': career_name,
'commission': reservation.commission.code if reservation.commission else '',
'shift': reservation.shift or '',