Files
home_stock/backend/app/models/location.py
2026-01-28 19:22:30 +01:00

98 lines
3.3 KiB
Python

"""Modèle SQLAlchemy pour les emplacements de stockage.
Les emplacements sont organisés de manière hiérarchique :
pièce → meuble → tiroir → boîte
Exemple : Garage → Étagère A → Tiroir 2 → Boîte visserie
"""
from datetime import datetime
from typing import TYPE_CHECKING
from sqlalchemy import DateTime, Enum, ForeignKey, Integer, String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func
from app.core.database import Base
if TYPE_CHECKING:
from app.models.item import Item
import enum
class LocationType(str, enum.Enum):
"""Type d'emplacement dans la hiérarchie."""
ROOM = "room" # Pièce (ex: Garage, Cuisine)
FURNITURE = "furniture" # Meuble (ex: Étagère, Armoire)
DRAWER = "drawer" # Tiroir
BOX = "box" # Boîte/Bac de rangement
class Location(Base):
"""Emplacement de stockage hiérarchique.
Attributes:
id: Identifiant unique auto-incrémenté
name: Nom de l'emplacement (ex: "Garage", "Étagère A")
type: Type d'emplacement (room/furniture/drawer/box)
parent_id: ID du parent (None si racine)
path: Chemin complet calculé (ex: "Garage > Étagère A > Tiroir 2")
description: Description optionnelle
created_at: Date/heure de création (auto)
updated_at: Date/heure de dernière modification (auto)
parent: Relation vers le parent
children: Relation vers les enfants
items: Relation vers les objets à cet emplacement
"""
__tablename__ = "locations"
# Colonnes
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
name: Mapped[str] = mapped_column(String(100), nullable=False, index=True)
type: Mapped[LocationType] = mapped_column(
Enum(LocationType, native_enum=False, length=20), nullable=False
)
parent_id: Mapped[int | None] = mapped_column(
Integer, ForeignKey("locations.id", ondelete="CASCADE"), nullable=True, index=True
)
path: Mapped[str] = mapped_column(String(500), nullable=False, index=True)
description: Mapped[str | None] = mapped_column(String(500), nullable=True)
# Timestamps
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), nullable=False
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True),
server_default=func.now(),
onupdate=func.now(),
nullable=False,
)
# Relations
parent: Mapped["Location | None"] = relationship(
"Location", remote_side=[id], back_populates="children"
)
children: Mapped[list["Location"]] = relationship(
"Location", back_populates="parent", cascade="all, delete-orphan"
)
items: Mapped[list["Item"]] = relationship(
"Item", back_populates="location", cascade="all, delete-orphan"
)
def __repr__(self) -> str:
"""Représentation string de l'emplacement."""
return f"<Location(id={self.id}, name='{self.name}', type={self.type.value})>"
def calculate_path(self) -> str:
"""Calcule le chemin complet de l'emplacement.
Returns:
Chemin complet (ex: "Garage > Étagère A > Tiroir 2")
"""
if self.parent is None:
return self.name
return f"{self.parent.calculate_path()} > {self.name}"