from __future__ import annotations from datetime import date, datetime from pydantic import BaseModel, ConfigDict, Field from .models import BaseUnit, Role # ---- Auth / Users ---- class Token(BaseModel): access_token: str token_type: str = "bearer" role: Role username: str class UserOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int username: str role: Role created_at: datetime class UserCreate(BaseModel): username: str = Field(min_length=1, max_length=64) password: str = Field(min_length=4, max_length=255) role: Role = Role.user class UserUpdate(BaseModel): password: str | None = Field(default=None, min_length=4, max_length=255) role: Role | None = None # ---- Groups ---- class GroupOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int name: str min_stock: float | None = None # angereichert: product_count: int = 0 stock: float = 0.0 class GroupCreate(BaseModel): name: str = Field(min_length=1, max_length=120) min_stock: float | None = Field(default=None, ge=0) class GroupUpdate(BaseModel): name: str | None = Field(default=None, min_length=1, max_length=120) min_stock: float | None = Field(default=None, ge=0) # ---- Locations ---- class LocationOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int name: str parent_id: int | None = None class LocationCreate(BaseModel): name: str = Field(min_length=1, max_length=120) parent_id: int | None = None # ---- Products ---- class ProductBase(BaseModel): barcode: str | None = None name: str = Field(min_length=1, max_length=255) brand: str | None = None image_url: str | None = None base_unit: BaseUnit = BaseUnit.piece package_size: float | None = Field(default=None, gt=0) group_id: int | None = None min_stock: float | None = Field(default=None, ge=0) class ProductCreate(ProductBase): pass class ProductUpdate(BaseModel): barcode: str | None = None name: str | None = Field(default=None, min_length=1, max_length=255) brand: str | None = None image_url: str | None = None base_unit: BaseUnit | None = None package_size: float | None = Field(default=None, gt=0) group_id: int | None = None min_stock: float | None = Field(default=None, ge=0) class ProductOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int barcode: str | None name: str brand: str | None image_url: str | None base_unit: BaseUnit package_size: float | None group_id: int | None min_stock: float | None source: str created_at: datetime # angereichert: stock: float = 0.0 class LookupResult(BaseModel): found: bool existing_product: ProductOut | None = None suggestion: dict | None = None # ---- Stock movements ---- class CheckInRequest(BaseModel): product_id: int | None = None barcode: str | None = None quantity: float = Field(gt=0) unit: str best_before: date | None = None location_id: int | None = None note: str | None = None class CheckOutRequest(BaseModel): product_id: int | None = None barcode: str | None = None quantity: float = Field(gt=0) unit: str note: str | None = None class LotOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int product_id: int quantity: float best_before: date | None location_id: int | None created_at: datetime class CheckInResponse(BaseModel): lot: LotOut product_stock: float class CheckInLine(BaseModel): """Eine Charge innerhalb eines Sammel-Einlagerns (Menge + eigenes MHD).""" quantity: float = Field(gt=0) best_before: date | None = None location_id: int | None = None class BatchCheckInRequest(BaseModel): product_id: int | None = None barcode: str | None = None unit: str lines: list[CheckInLine] = Field(min_length=1) note: str | None = None class BatchCheckInResponse(BaseModel): lots: list[LotOut] product_stock: float class CheckOutResponse(BaseModel): affected_lots: list[dict] product_stock: float # ---- Views ---- class ShoppingItem(BaseModel): product_id: int name: str base_unit: BaseUnit package_size: float | None = None stock: float min_stock: float deficit: float class ExpiringItem(BaseModel): lot_id: int product_id: int product_name: str quantity: float base_unit: BaseUnit best_before: date days_left: int class GroupShoppingItem(BaseModel): group_id: int name: str stock: float min_stock: float deficit: float product_count: int class MovementOut(BaseModel): id: int product_id: int product_name: str type: str quantity: float base_unit: BaseUnit unit_used: str username: str | None note: str | None created_at: datetime class SettingOut(BaseModel): key: str value: str