gmao/app_new/core/models/college.py
root a296b9e013
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run
Gère les logements de fonction et leurs pièces
2026-08-14 21:23:33 +00:00

186 lines
7.4 KiB
Python

"""
Modèle College et Building - GMAO Collège
Gestion des collèges et bâtiments
Compatible avec la base de données existante
"""
from datetime import datetime, timezone
from ...extensions import db
class College(db.Model):
"""Collège."""
__tablename__ = "colleges"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
address = db.Column(db.Text, nullable=True)
city = db.Column(db.String(100), nullable=True)
zip_code = db.Column(db.String(10), nullable=True)
phone = db.Column(db.String(20), nullable=True)
email = db.Column(db.String(100), nullable=True)
website = db.Column(db.String(255), nullable=True)
logo = db.Column(db.String(255), nullable=True)
is_active = db.Column(db.Boolean, default=True)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
# Relations - buildings n'a pas de college_id, pas de relation directe
def __repr__(self):
return f"<College {self.name}>"
class Site(db.Model):
"""Site physique : collège, logements de fonction, annexe, etc."""
__tablename__ = "sites"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), nullable=False, unique=True)
site_type = db.Column(db.String(40), nullable=False, default="college")
address = db.Column(db.Text, nullable=True)
is_active = db.Column(db.Boolean, nullable=False, default=True)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
buildings = db.relationship("Building", back_populates="site", lazy="dynamic")
class Building(db.Model):
"""Bâtiment du collège."""
__tablename__ = "buildings"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
description = db.Column(db.Text, nullable=True)
site_id = db.Column(db.Integer, db.ForeignKey("sites.id"), nullable=True, index=True)
# Relations - utiliser overlaps pour éviter warning SQLAlchemy
rooms = db.relationship("Room", overlaps="building", lazy="dynamic")
zones = db.relationship("Zone", back_populates="building", lazy="dynamic")
site = db.relationship("Site", back_populates="buildings")
@property
def room_count(self):
"""Nombre de salles dans le bâtiment."""
return self.rooms.count()
def __repr__(self):
return f"<Building {self.name}>"
class HousingUnit(db.Model):
"""Logement de fonction et historique courant de son occupation."""
__tablename__ = "housing_units"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(120), nullable=False)
code = db.Column(db.String(40), nullable=True, unique=True)
building_id = db.Column(db.Integer, db.ForeignKey("buildings.id"), nullable=False, index=True)
housing_type = db.Column(db.String(40), nullable=False, default="fonction")
occupancy_status = db.Column(db.String(30), nullable=False, default="vacant")
occupant_name = db.Column(db.String(150), nullable=True)
occupant_contact = db.Column(db.String(150), nullable=True)
occupancy_start = db.Column(db.Date, nullable=True)
occupancy_end = db.Column(db.Date, nullable=True)
notes = db.Column(db.Text, nullable=True)
is_active = db.Column(db.Boolean, nullable=False, default=True)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
building = db.relationship("Building", backref=db.backref("housing_units", lazy="dynamic"))
rooms = db.relationship("Room", back_populates="housing_unit", lazy="dynamic")
class Zone(db.Model):
"""Zone dans un bâtiment."""
__tablename__ = "zones"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
building_id = db.Column(db.Integer, db.ForeignKey("buildings.id"), nullable=False)
# Relations
building = db.relationship("Building", back_populates="zones")
rooms = db.relationship("Room", back_populates="zone")
@property
def full_name(self):
"""Nom complet avec bâtiment."""
if self.building:
return f"{self.building.name} - {self.name}"
return self.name
def __repr__(self):
return f"<Zone {self.name}>"
class Room(db.Model):
"""Salle du collège."""
__tablename__ = "rooms"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
code = db.Column(db.String(20), nullable=True)
zone_id = db.Column(db.Integer, db.ForeignKey("zones.id"), nullable=True)
floor = db.Column(db.Integer, default=0)
building_id = db.Column(db.Integer, db.ForeignKey("buildings.id"), nullable=False)
room_type_id = db.Column(db.Integer, db.ForeignKey("room_types.id"), nullable=True)
housing_unit_id = db.Column(db.Integer, db.ForeignKey("housing_units.id"), nullable=True, index=True)
# Libelle historique conserve pour les imports anterieurs a zone_id.
legacy_zone_name = db.Column("zone", db.String(100), nullable=True)
# Relations - utiliser overlaps pour éviter warning SQLAlchemy
building = db.relationship("Building", overlaps="rooms")
zone = db.relationship("Zone", back_populates="rooms")
room_type = db.relationship("RoomType", back_populates="rooms")
equipments = db.relationship("Equipment", back_populates="room")
housing_unit = db.relationship("HousingUnit", back_populates="rooms")
@property
def full_name(self):
"""Nom complet avec bâtiment."""
if self.building:
return f"{self.building.name} - {self.name}"
return self.name
def __repr__(self):
return f"<Room {self.name}>"
class RoomType(db.Model):
"""Type de salle."""
__tablename__ = "room_types"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
description = db.Column(db.Text, nullable=True)
is_teaching = db.Column(db.Boolean, default=False)
color = db.Column(db.String(20), nullable=True)
icon = db.Column(db.String(50), nullable=True)
# Relation vers les salles
rooms = db.relationship("Room", back_populates="room_type")
def __repr__(self):
return f"<RoomType {self.name}>"
class RoomSchedule(db.Model):
"""Emploi du temps d'une salle."""
__tablename__ = "room_schedules"
id = db.Column(db.Integer, primary_key=True)
room_id = db.Column(db.Integer, db.ForeignKey("rooms.id"), nullable=False)
week_start = db.Column(db.Date, nullable=False)
day_of_week = db.Column(db.Integer, nullable=False)
start_time = db.Column(db.Time, nullable=False)
end_time = db.Column(db.Time, nullable=False)
subject = db.Column(db.String(100), nullable=True)
teacher = db.Column(db.String(100), nullable=True)
class_name = db.Column(db.String(50), nullable=True)
course_name = db.Column(db.String(255), nullable=True)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
# Relations
room = db.relationship("Room", backref="schedules")
def __repr__(self):
return f"<RoomSchedule {self.room.name} - {self.day_of_week}>"