""" Modele Contract - GMAO College Suivi des contrats d'entreprise pour les equipements/lots. """ from datetime import datetime, timezone, date from ..extensions import db class Contract(db.Model): """Contrat d'entreprise pour un lot ou un equipement.""" __tablename__ = "contracts" id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(200), nullable=False) contract_number = db.Column(db.String(100), nullable=True) # Liaison : un contrat est lie a un lot et/ou un equipement lot_id = db.Column(db.Integer, db.ForeignKey("lots.id"), nullable=True) equipment_id = db.Column(db.Integer, db.ForeignKey("equipments.id"), nullable=True) company_id = db.Column(db.Integer, db.ForeignKey("companies.id"), nullable=True) # Dates signed_date = db.Column(db.Date, nullable=True) start_date = db.Column(db.Date, nullable=False) end_date = db.Column(db.Date, nullable=True) # NULL = duree indeterminee # Tacite reconduction tacit_renewal = db.Column(db.Boolean, default=True) renewal_period_days = db.Column(db.Integer, default=365) # reconduction par periode de X jours # Delai de preavis pour resilier (en jours avant la date de fin) notice_period_days = db.Column(db.Integer, nullable=True) notice_deadline = db.Column(db.Date, nullable=True) # date limite pour envoyer le preavis # Montant annual_amount = db.Column(db.Float, nullable=True) currency = db.Column(db.String(3), default="EUR") # Statut status = db.Column(db.String(20), default="actif") # actif, expire, resilie, en_attente notes = db.Column(db.Text, nullable=True) visit_interval_days = db.Column(db.Integer, nullable=True) last_visit_date = db.Column(db.Date, nullable=True) next_visit_date = db.Column(db.Date, nullable=True) # Documents contract_file = db.Column(db.String(500), nullable=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 lot = db.relationship("Lot", backref=db.backref("contracts", lazy="dynamic")) equipment = db.relationship("Equipment", backref=db.backref("contracts", lazy="dynamic")) company = db.relationship("Company", backref=db.backref("contracts", lazy="dynamic")) visits = db.relationship("ContractVisit", back_populates="contract", cascade="all, delete-orphan", order_by="ContractVisit.scheduled_date") @property def is_active(self): """True si le contrat est actif aujourd'hui.""" if self.status != "actif": return False today = date.today() if self.start_date and today < self.start_date: return False if self.end_date and today > self.end_date: return False return True @property def is_expiring_soon(self): """True si le contrat expire dans les 90 prochains jours.""" if not self.end_date: return False days_left = (self.end_date - date.today()).days return 0 <= days_left <= 90 @property def days_until_expiry(self): """Nombre de jours avant l'expiration (negatif = expire).""" if not self.end_date: return None return (self.end_date - date.today()).days @property def notice_deadline_calculated(self): """Calcule la date limite de preavis si pas definie manuellement.""" if self.notice_deadline: return self.notice_deadline if self.end_date and self.notice_period_days: from datetime import timedelta return self.end_date - timedelta(days=self.notice_period_days) return None @property def must_send_notice_now(self): """True si le preavis doit etre envoye maintenant (deadline proche).""" deadline = self.notice_deadline_calculated if not deadline: return False days_left = (deadline - date.today()).days return days_left <= 60 # alerte 60 jours avant @property def status_color(self): """Couleur du badge.""" if not self.is_active: return "danger" if self.status == "expire" else "secondary" if self.is_expiring_soon: return "warning" if self.must_send_notice_now: return "warning" return "success" def __repr__(self): return f"" class ContractVisit(db.Model): """Visite planifiée ou réalisée par le prestataire d'un contrat.""" __tablename__ = "contract_visits" __table_args__ = (db.UniqueConstraint("contract_id", "scheduled_date", name="uq_contract_visit_date"),) id = db.Column(db.Integer, primary_key=True) contract_id = db.Column(db.Integer, db.ForeignKey("contracts.id", ondelete="CASCADE"), nullable=False, index=True) scheduled_date = db.Column(db.Date, nullable=False, index=True) status = db.Column(db.String(20), nullable=False, default="planifiee") completed_at = db.Column(db.DateTime, nullable=True) report = db.Column(db.Text, nullable=True) created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), nullable=False) contract = db.relationship("Contract", back_populates="visits")