70 lines
4.4 KiB
Python
70 lines
4.4 KiB
Python
from flask import Blueprint, render_template
|
|
from flask_login import login_required
|
|
|
|
from app_new.core.models.college import Site, Building, Zone, Room, RoomProfile, RoomSchedule
|
|
from app_new.core.models.equipment import Equipment
|
|
from app_new.core.models.maintenance import LotTask
|
|
from app_new.core.models.user import User
|
|
from app_new.core.models.planning import WorkSchedule
|
|
from app_new.contracts.models import Contract
|
|
|
|
configuration_bp = Blueprint("configuration", __name__, template_folder="templates")
|
|
|
|
|
|
def _status(ok, label, url, detail=None, optional=False, attention=False):
|
|
if optional and not ok:
|
|
state = "Facultatif"
|
|
elif attention:
|
|
state = "Attention"
|
|
elif ok:
|
|
state = "Configuré"
|
|
else:
|
|
state = "À configurer"
|
|
return {"label": label, "state": state, "ok": ok, "url": url, "detail": detail or ""}
|
|
|
|
|
|
@configuration_bp.route("/")
|
|
@login_required
|
|
def index():
|
|
from flask import url_for
|
|
sites = Site.query.count()
|
|
buildings = Building.query.count()
|
|
zones = Zone.query.count()
|
|
rooms = Room.query.count()
|
|
profiles = RoomProfile.query.count()
|
|
unprofiled = Room.query.filter(Room.room_type_id.is_(None)).count()
|
|
equipment_without_lot = Equipment.query.filter(Equipment.is_deleted.is_(False), Equipment.lot_id.is_(None)).count()
|
|
technicians = User.query.filter_by(is_active=True).all()
|
|
scheduled_users = {row[0] for row in WorkSchedule.query.filter_by(is_active=True).with_entities(WorkSchedule.user_id).all()}
|
|
tasks_without_duration = LotTask.query.filter(LotTask.is_active.is_(True), (LotTask.duree_minutes.is_(None) | (LotTask.duree_minutes <= 0))).count()
|
|
contract_table = Contract.__table__.c
|
|
contracts_without_due = Contract.query.filter(contract_table.status == "actif", contract_table.end_date.is_(None)).count()
|
|
room_schedules = RoomSchedule.query.count()
|
|
sections = [
|
|
("ESSENTIEL", [
|
|
_status(User.query.filter_by(is_active=True).count() > 0, "Administrateur / utilisateurs", url_for("admin.users")),
|
|
_status(sites > 0, "Établissement / site", url_for("buildings.index"), f"{sites} site(s)"),
|
|
_status(buildings > 0, "Bâtiments", url_for("buildings.index"), f"{buildings} bâtiment(s)"),
|
|
_status(zones > 0, "Zones", url_for("zones.index"), f"{zones} zone(s)"),
|
|
_status(rooms > 0, "Locaux / emplacements", url_for("rooms.index"), f"{rooms} local(aux)"),
|
|
_status(len(scheduled_users) >= len(technicians) and bool(technicians), "Horaires techniciens", url_for("planning.work_schedules"), f"{len(technicians) - len(scheduled_users)} sans horaires" if technicians else "Aucun technicien actif", attention=bool(technicians) and len(scheduled_users) < len(technicians)),
|
|
]),
|
|
("MAINTENANCE", [
|
|
_status(profiles > 0, "Profils de locaux", url_for("room_profiles.index"), f"{profiles} profil(s)"),
|
|
_status(False, "Équipements sans lot (facultatif)", url_for("equipments.index"), f"{equipment_without_lot} équipement(s) sans lot — le lot peut être ajouté plus tard", optional=True),
|
|
_status(tasks_without_duration == 0, "Durées préventives", url_for("lots.index"), f"{tasks_without_duration} à renseigner", attention=tasks_without_duration > 0),
|
|
_status(room_schedules > 0, "Planning des salles", url_for("planning.room_schedules"), f"{room_schedules} créneau(x)"),
|
|
]),
|
|
("PATRIMOINE", [
|
|
_status(unprofiled == 0, "Locaux avec profil structurel", url_for("rooms.index"), f"{unprofiled} sans type", attention=unprofiled > 0),
|
|
_status(True, "Logements de fonction", url_for("housing.index"), "Facultatif", optional=True),
|
|
]),
|
|
("ENTREPRISES", [_status(contracts_without_due == 0, "Contrats avec échéance", url_for("companies.index"), f"{contracts_without_due} sans échéance", attention=contracts_without_due > 0)]),
|
|
("COMPTEURS", [_status(False, "Compteurs", url_for("meters.index"), "Non configuré", optional=True)]),
|
|
("CARTOGRAPHIE TECHNIQUE", [_status(False, "Relations techniques", url_for("equipments.index"), "Facultatif", optional=True)]),
|
|
("INTÉGRATIONS", [
|
|
_status(False, "Pronote", url_for("pronote.index"), "Non configuré", optional=True),
|
|
_status(False, "ENT / Outlook / Yeastar / IA", url_for("admin.settings"), "Facultatif", optional=True),
|
|
]),
|
|
]
|
|
return render_template("configuration/index.html", sections=sections)
|