gmao/app_new/core/models/company.py
root 0b3fff43e5
Some checks are pending
CI - Tests et Syntax / lint-and-test (push) Waiting to run
Complète le suivi opérationnel de la GMAO
2026-08-14 23:26:22 +00:00

123 lines
5.1 KiB
Python

"""
Modèle Company - GMAO Collège
Gestion des entreprises et pièces
Compatible avec la base de données existante
"""
from datetime import datetime, timezone
from ...extensions import db
class Company(db.Model):
"""Entreprise externe."""
__tablename__ = "companies"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), nullable=False)
trade_name = db.Column(db.String(200), nullable=True)
siret = db.Column(db.String(14), nullable=True)
contact_name = db.Column(db.String(150), nullable=True)
contact_email = db.Column(db.String(200), nullable=True)
contact_phone = db.Column(db.String(20), nullable=True)
address = db.Column(db.Text, nullable=True)
specialty = db.Column(db.String(200), nullable=True)
rating = db.Column(db.Integer, nullable=True)
notes = db.Column(db.Text, nullable=True)
is_active = db.Column(db.Boolean, default=True)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
tech1_name = db.Column(db.String(150), nullable=True)
tech1_phone = db.Column(db.String(20), nullable=True)
tech1_email = db.Column(db.String(200), nullable=True)
tech2_name = db.Column(db.String(150), nullable=True)
tech2_phone = db.Column(db.String(20), nullable=True)
tech2_email = db.Column(db.String(200), nullable=True)
tech3_name = db.Column(db.String(150), nullable=True)
tech3_phone = db.Column(db.String(20), nullable=True)
tech3_email = db.Column(db.String(200), nullable=True)
def __repr__(self):
return f"<Company {self.name}>"
class Part(db.Model):
"""Pièce détachée."""
__tablename__ = "parts"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200), nullable=False)
reference = db.Column(db.String(100), nullable=True)
description = db.Column(db.Text, nullable=True)
category = db.Column(db.String(100), nullable=True)
unit = db.Column(db.String(20), nullable=True)
quantity = db.Column(db.Integer, default=0)
min_quantity = db.Column(db.Integer, default=0)
unit_price = db.Column(db.Float, nullable=True)
supplier = db.Column(db.String(200), nullable=True)
location = db.Column(db.String(200), 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 - utiliser back_populates pour éviter conflit
usages_list = db.relationship("InterventionPart", back_populates="part", lazy="dynamic")
stock_movements = db.relationship("PartStockMovement", back_populates="part", lazy="dynamic",
cascade="all, delete-orphan")
@property
def is_low_stock(self):
"""Vérifie si le stock est faible."""
return self.quantity <= self.min_quantity
def __repr__(self):
return f"<Part {self.name}>"
class PartStockMovement(db.Model):
"""Journal immuable des entrées, sorties et corrections de stock."""
__tablename__ = "part_stock_movements"
id = db.Column(db.Integer, primary_key=True)
part_id = db.Column(db.Integer, db.ForeignKey("parts.id", ondelete="CASCADE"), nullable=False, index=True)
user_id = db.Column(db.Integer, db.ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
movement_type = db.Column(db.String(20), nullable=False)
quantity_delta = db.Column(db.Integer, nullable=False)
quantity_before = db.Column(db.Integer, nullable=False)
quantity_after = db.Column(db.Integer, nullable=False)
reason = db.Column(db.String(255), nullable=False)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), nullable=False)
part = db.relationship("Part", back_populates="stock_movements")
user = db.relationship("User")
class Alert(db.Model):
"""Alerte système."""
__tablename__ = "alerts"
id = db.Column(db.Integer, primary_key=True)
alert_type = db.Column(db.String(50), nullable=False)
title = db.Column(db.String(255), nullable=False)
message = db.Column(db.Text, nullable=False)
priority = db.Column(db.String(20), default="normale")
is_read = db.Column(db.Boolean, default=False)
is_resolved = db.Column(db.Boolean, default=False)
related_id = db.Column(db.Integer, nullable=True)
related_type = db.Column(db.String(50), nullable=True)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
resolved_at = db.Column(db.DateTime, nullable=True)
resolved_by = db.Column(db.Integer, db.ForeignKey("users.id"), nullable=True)
def __repr__(self):
return f"<Alert {self.title}>"
class Service(db.Model):
"""Service du collège."""
__tablename__ = "services"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
description = db.Column(db.Text, nullable=True)
is_active = db.Column(db.Boolean, default=True)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
def __repr__(self):
return f"<Service {self.name}>"