200 lines
7.8 KiB
Python
200 lines
7.8 KiB
Python
"""Routes salles - GMAO Collège"""
|
||
from datetime import date, datetime, timedelta
|
||
from flask import Blueprint, render_template, redirect, url_for, request, flash
|
||
from flask_login import login_required
|
||
|
||
from app_new.extensions import db
|
||
from app_new.core.models.college import Room, Zone, Building, RoomType, RoomSchedule
|
||
from app_new.core.models.equipment import Equipment
|
||
|
||
rooms_bp = Blueprint('rooms', __name__, template_folder='templates')
|
||
|
||
|
||
def _room_form_context(room=None):
|
||
"""Return all reference data used by the room form.
|
||
|
||
The building list is deliberately loaded independently from the zone
|
||
list. Previously the GET route only supplied ``zones`` which left the
|
||
required building select empty and made every room creation impossible.
|
||
"""
|
||
return {
|
||
'room': room,
|
||
'buildings': Building.query.order_by(Building.name).all(),
|
||
'zones': Zone.query.join(Building).order_by(Building.name, Zone.name).all(),
|
||
'room_types': RoomType.query.order_by(RoomType.name).all(),
|
||
}
|
||
|
||
|
||
@rooms_bp.route('/')
|
||
@login_required
|
||
def index():
|
||
"""Liste des salles."""
|
||
zones_filter = request.args.getlist('zone') or None
|
||
room_type_id = request.args.get('room_type', type=int)
|
||
|
||
query = Room.query.join(Zone).join(Building)
|
||
if zones_filter:
|
||
query = query.filter(Zone.id.in_(zones_filter))
|
||
if room_type_id:
|
||
query = query.filter_by(room_type_id=room_type_id)
|
||
rooms = query.order_by(Building.name, Zone.name, Room.name).all()
|
||
zones = Zone.query.join(Building).order_by(Building.name, Zone.name).all()
|
||
room_types = RoomType.query.order_by(RoomType.name).all()
|
||
return render_template('equipments/rooms.html',
|
||
rooms=rooms, zones=zones, room_types=room_types,
|
||
selected_zones=[int(z) for z in zones_filter] if zones_filter else [])
|
||
|
||
|
||
@rooms_bp.route('/<int:id>')
|
||
@login_required
|
||
def detail(id):
|
||
"""Détail d'une salle."""
|
||
room = Room.query.get_or_404(id)
|
||
today = date.today()
|
||
week_start = today - timedelta(days=today.weekday())
|
||
courses = RoomSchedule.query.filter_by(
|
||
room_id=room.id,
|
||
week_start=week_start,
|
||
day_of_week=today.weekday(),
|
||
).order_by(RoomSchedule.start_time).all()
|
||
current_time = datetime.now().time()
|
||
current_course = next(
|
||
(course for course in courses
|
||
if course.start_time <= current_time <= course.end_time),
|
||
None,
|
||
)
|
||
next_course = next(
|
||
(course for course in courses if course.start_time > current_time),
|
||
None,
|
||
)
|
||
if current_course:
|
||
room_status = {
|
||
'status': 'occupee',
|
||
'message': 'Salle actuellement occupée',
|
||
'course': current_course,
|
||
'next_occupied': None,
|
||
}
|
||
elif courses:
|
||
room_status = {
|
||
'status': 'libre',
|
||
'message': 'Salle libre actuellement',
|
||
'course': None,
|
||
'next_occupied': next_course.start_time.strftime('%H:%M') if next_course else None,
|
||
}
|
||
else:
|
||
room_status = {
|
||
'status': 'inconnu',
|
||
'message': "Aucun emploi du temps importé pour cette salle aujourd'hui.",
|
||
'course': None,
|
||
'next_occupied': None,
|
||
}
|
||
|
||
equipments = Equipment.query.filter(
|
||
Equipment.room_id == room.id,
|
||
Equipment.is_deleted.is_(False),
|
||
).order_by(Equipment.name, Equipment.individual_number).all()
|
||
return render_template('equipments/room_detail.html',
|
||
room=room, equipments=equipments,
|
||
courses=courses, room_status=room_status)
|
||
|
||
|
||
@rooms_bp.route('/new', methods=['GET', 'POST'])
|
||
@login_required
|
||
def create():
|
||
"""Créer une salle."""
|
||
if request.method == 'POST':
|
||
name = (request.form.get('name') or '').strip()
|
||
building_id = request.form.get('building_id', type=int)
|
||
zone_id = request.form.get('zone_id', type=int)
|
||
building = db.session.get(Building, building_id) if building_id else None
|
||
zone = db.session.get(Zone, zone_id) if zone_id else None
|
||
errors = []
|
||
if not name:
|
||
errors.append('Le nom de la salle est obligatoire.')
|
||
if not building:
|
||
errors.append('Sélectionnez un bâtiment valide.')
|
||
if zone and building and zone.building_id != building.id:
|
||
errors.append('La zone sélectionnée n’appartient pas au bâtiment choisi.')
|
||
if errors:
|
||
for error in errors:
|
||
flash(error, 'danger')
|
||
context = _room_form_context()
|
||
context['form_data'] = request.form
|
||
return render_template('equipments/room_form.html', **context), 400
|
||
room = Room(
|
||
name=name,
|
||
code=request.form.get('code') or None,
|
||
zone_id=zone_id,
|
||
building_id=building.id,
|
||
room_type_id=request.form.get('room_type_id', type=int),
|
||
floor=request.form.get('floor', 0, type=int)
|
||
)
|
||
db.session.add(room)
|
||
try:
|
||
db.session.commit()
|
||
except Exception:
|
||
db.session.rollback()
|
||
flash('Impossible d’enregistrer cette salle. Vérifiez les valeurs saisies.', 'danger')
|
||
context = _room_form_context()
|
||
context['form_data'] = request.form
|
||
return render_template('equipments/room_form.html', **context), 400
|
||
flash(f"Salle '{room.name}' créée.", 'success')
|
||
return redirect(url_for('rooms.index'))
|
||
|
||
context = _room_form_context()
|
||
context['form_data'] = {}
|
||
context['title'] = 'Nouvelle salle'
|
||
return render_template('equipments/room_form.html', **context)
|
||
|
||
|
||
@rooms_bp.route('/<int:id>/edit', methods=['GET', 'POST'])
|
||
@login_required
|
||
def edit(id):
|
||
"""Modifier une salle."""
|
||
room = Room.query.get_or_404(id)
|
||
|
||
if request.method == 'POST':
|
||
name = (request.form.get('name') or '').strip()
|
||
building_id = request.form.get('building_id', type=int)
|
||
zone_id = request.form.get('zone_id', type=int)
|
||
building = db.session.get(Building, building_id) if building_id else None
|
||
zone = db.session.get(Zone, zone_id) if zone_id else None
|
||
if not name or not building or (zone and zone.building_id != building.id):
|
||
flash('Le nom, le bâtiment et une zone cohérente sont obligatoires.', 'danger')
|
||
context = _room_form_context(room)
|
||
context['form_data'] = request.form
|
||
context['title'] = 'Modifier la salle'
|
||
return render_template('equipments/room_form.html', **context), 400
|
||
room.name = name
|
||
room.code = request.form.get('code') or None
|
||
room.zone_id = zone_id
|
||
room.building_id = building.id
|
||
room.room_type_id = request.form.get('room_type_id', type=int)
|
||
room.floor = request.form.get('floor', 0, type=int)
|
||
try:
|
||
db.session.commit()
|
||
except Exception:
|
||
db.session.rollback()
|
||
flash('Impossible d’enregistrer cette salle. Vérifiez les valeurs saisies.', 'danger')
|
||
context = _room_form_context(room)
|
||
context['form_data'] = request.form
|
||
context['title'] = 'Modifier la salle'
|
||
return render_template('equipments/room_form.html', **context), 400
|
||
flash(f"Salle '{room.name}' mise à jour.", 'success')
|
||
return redirect(url_for('rooms.index'))
|
||
|
||
context = _room_form_context(room)
|
||
context['form_data'] = {}
|
||
context['title'] = 'Modifier la salle'
|
||
return render_template('equipments/room_form.html', **context)
|
||
|
||
|
||
@rooms_bp.route('/<int:id>/delete', methods=['POST'])
|
||
@login_required
|
||
def delete(id):
|
||
"""Supprimer une salle."""
|
||
room = Room.query.get_or_404(id)
|
||
db.session.delete(room)
|
||
db.session.commit()
|
||
flash(f"Salle '{room.name}' supprimée.", 'success')
|
||
return redirect(url_for('rooms.index'))
|