inventory/inventory/models/user.py
2025-09-22 14:08:24 -05:00

65 lines
2.9 KiB
Python

from typing import List, Optional, TYPE_CHECKING
from sqlalchemy import Boolean, Integer, ForeignKey, Unicode, case, func, literal
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import expression as sql
from crudkit.core.base import Base, CRUDMixin
if TYPE_CHECKING:
from .room import Room
class User(Base, CRUDMixin):
__tablename__ = 'users'
first_name: Mapped[Optional[str]] = mapped_column(Unicode(255), nullable=True, index=True)
last_name: Mapped[Optional[str]] = mapped_column(Unicode(255), nullable=True, index=True)
title: Mapped[Optional[str]] = mapped_column(Unicode(255), nullable=True)
active: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=False, default=True, server_default=sql.true())
staff: Mapped[Optional[bool]] = mapped_column(Boolean, nullable=False, default=False, server_default=sql.false())
image: Mapped[Optional['Image']] = relationship('Image', back_populates='user', passive_deletes=True)
image_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("images.id", ondelete="SET NULL"), nullable=True, index=True)
inventory: Mapped[List['Inventory']] = relationship('Inventory', back_populates='owner')
location: Mapped[Optional['Room']] = relationship('Room', back_populates='users')
location_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("rooms.id"), nullable=True, index=True)
supervisor: Mapped[Optional['User']] = relationship('User', back_populates='subordinates', remote_side='User.id')
supervisor_id: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("users.id"), nullable=True, index=True)
subordinates: Mapped[List['User']] = relationship('User', back_populates='supervisor')
work_logs: Mapped[Optional[List['WorkLog']]] = relationship('WorkLog', back_populates='contact')
is_deleted: Mapped[Boolean] = mapped_column(Boolean, nullable=False, default=False, server_default=sql.false())
def __repr__(self):
return f"<User(id={self.id}, first_name={repr(self.first_name)}, last_name={repr(self.last_name)})>"
@hybrid_property
def label(self):
out = f"{self.first_name} {self.last_name}"
if self.title:
out = out + f" ({self.title})"
return out
@label.expression
def label(cls):
first = func.coalesce(cls.first_name, "")
last = func.coalesce(cls.last_name, "")
title = func.coalesce(cls.title, "")
have_first = func.length(func.trim(first)) > 0
have_last = func.length(func.trim(last)) > 0
space = case((have_first & have_last, literal(" ")), else_=literal(""))
title_part = case(
(func.length(func.trim(title)) > 0, func.concat(" (", title, ")")),
else_=literal("")
)
return func.concat(first, space, last, title_part)