feat: optimizacion zocalos aulas, metricas ocupacion dia/semana/mes, modificacion de reservas y permisos RBAC en gestion
This commit is contained in:
@@ -139,6 +139,92 @@ def view_reservation(id):
|
||||
flash(f'Error loading reservation details: {str(e)}', 'error')
|
||||
return redirect(url_for('schedule.today_schedule'))
|
||||
|
||||
@schedule_bp.route('/reservation/<int:id>/edit', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_reservation(id):
|
||||
"""Edit existing reservation"""
|
||||
from app.models.classroom import Classroom
|
||||
from app.models.subject import Commission
|
||||
from app.models.building import Building
|
||||
from flask_babel import gettext as _
|
||||
|
||||
reservation = Reservation.query.options(
|
||||
joinedload(Reservation.classroom),
|
||||
joinedload(Reservation.commission),
|
||||
joinedload(Reservation.user)
|
||||
).get_or_404(id)
|
||||
|
||||
if not current_user.can_edit_reservation(reservation):
|
||||
flash(_('No tienes los permisos necesarios para modificar esta reserva.'), 'error')
|
||||
return redirect(url_for('schedule.view_reservation', id=reservation.id))
|
||||
|
||||
form = ReservationForm(is_edit=True)
|
||||
|
||||
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()
|
||||
|
||||
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 == 'GET':
|
||||
form.classroom_id.data = reservation.classroom_id
|
||||
form.commission_id.data = reservation.commission_id
|
||||
form.start_time.data = reservation.start_time
|
||||
form.end_time.data = reservation.end_time
|
||||
form.purpose.data = reservation.purpose
|
||||
form.expected_attendees.data = reservation.expected_attendees
|
||||
form.notes.data = reservation.notes or ''
|
||||
form.virtual_link.data = reservation.virtual_link or ''
|
||||
|
||||
elif request.method == 'POST':
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
# Verificar colisión de horario si no es virtual
|
||||
target_room = Classroom.query.get(form.classroom_id.data)
|
||||
if target_room and not target_room.is_virtual:
|
||||
conflict = Reservation.query.filter(
|
||||
Reservation.id != reservation.id,
|
||||
Reservation.classroom_id == form.classroom_id.data,
|
||||
Reservation.status == ReservationStatus.CONFIRMED.value,
|
||||
Reservation.start_time < form.end_time.data,
|
||||
Reservation.end_time > form.start_time.data
|
||||
).first()
|
||||
|
||||
if conflict:
|
||||
flash(_('El aula seleccionada ya cuenta con una reserva confirmada en esa franja horaria.'), 'danger')
|
||||
return render_template('schedule/edit.html', form=form, reservation=reservation, classroom_list=classrooms, commission_list=commissions, buildings=buildings)
|
||||
|
||||
# Asignar cambios
|
||||
reservation.classroom_id = form.classroom_id.data
|
||||
reservation.commission_id = form.commission_id.data
|
||||
reservation.start_time = form.start_time.data
|
||||
reservation.end_time = form.end_time.data
|
||||
reservation.purpose = form.purpose.data
|
||||
reservation.expected_attendees = form.expected_attendees.data
|
||||
reservation.notes = form.notes.data
|
||||
reservation.virtual_link = form.virtual_link.data.strip() if form.virtual_link.data else None
|
||||
|
||||
# Turno
|
||||
h = reservation.start_time.hour
|
||||
if h < 13:
|
||||
reservation.shift = 'Mañana'
|
||||
elif h < 18:
|
||||
reservation.shift = 'Tarde'
|
||||
elif h < 21:
|
||||
reservation.shift = 'Vespertino'
|
||||
else:
|
||||
reservation.shift = 'Noche'
|
||||
|
||||
db.session.commit()
|
||||
flash(_('Reserva #%(id)d modificada exitosamente.', id=reservation.id), 'success')
|
||||
return redirect(url_for('schedule.view_reservation', id=reservation.id))
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
flash(f'Error al modificar reserva: {str(e)}', 'danger')
|
||||
|
||||
return render_template('schedule/edit.html', form=form, reservation=reservation, classroom_list=classrooms, commission_list=commissions, buildings=buildings)
|
||||
|
||||
@schedule_bp.route('/calendar')
|
||||
@login_required
|
||||
def calendar_view():
|
||||
@@ -518,6 +604,7 @@ def list_reservations():
|
||||
hide_virtual = request.args.get('hide_virtual', '0') in ['1', 'true', 'True']
|
||||
floor_filter = request.args.get('floor', '').strip()
|
||||
shift_filter = request.args.get('shift', '').strip()
|
||||
classroom_id = request.args.get('classroom_id', type=int)
|
||||
search = request.args.get('search', '').strip()
|
||||
|
||||
query = Reservation.query.options(
|
||||
@@ -526,6 +613,9 @@ def list_reservations():
|
||||
joinedload(Reservation.user)
|
||||
).join(Reservation.classroom).outerjoin(Reservation.commission).outerjoin(Commission.subject)
|
||||
|
||||
if classroom_id:
|
||||
query = query.filter(Reservation.classroom_id == classroom_id)
|
||||
|
||||
if status_filter and status_filter != 'all':
|
||||
query = query.filter(Reservation.status == status_filter.upper())
|
||||
|
||||
@@ -575,6 +665,7 @@ def list_reservations():
|
||||
|
||||
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]
|
||||
all_classrooms = Classroom.query.filter_by(is_active=True).order_by(Classroom.building_id.asc(), Classroom.floor.asc(), Classroom.code.asc()).all()
|
||||
|
||||
return render_template(
|
||||
'schedule/list.html',
|
||||
@@ -585,6 +676,8 @@ def list_reservations():
|
||||
hide_virtual=hide_virtual,
|
||||
floor_filter=floor_filter,
|
||||
shift_filter=shift_filter,
|
||||
classroom_id=classroom_id,
|
||||
all_classrooms=all_classrooms,
|
||||
search=search,
|
||||
available_floors=available_floors
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user