Files
data-entry-app/backend/app/schemas/throughput.py
T

129 lines
4.3 KiB
Python
Raw Normal View History

2026-05-31 20:19:44 +12:00
from __future__ import annotations
from datetime import date, datetime
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field, field_validator
QuantityType = Literal["bags", "kg"]
class ThroughputProductBase(BaseModel):
model_config = ConfigDict(extra="forbid")
item_id: str | None = Field(default=None, max_length=64)
name: str = Field(min_length=1, max_length=255)
default_bag_size: float | None = Field(default=None, ge=0)
is_bulka_default: bool = False
active: bool = True
is_stock_item: bool = True
notes: str | None = Field(default=None, max_length=2000)
class ThroughputProductCreate(ThroughputProductBase):
pass
class ThroughputProductUpdate(BaseModel):
model_config = ConfigDict(extra="forbid")
item_id: str | None = Field(default=None, max_length=64)
name: str | None = Field(default=None, min_length=1, max_length=255)
default_bag_size: float | None = Field(default=None, ge=0)
is_bulka_default: bool | None = None
active: bool | None = None
is_stock_item: bool | None = None
notes: str | None = Field(default=None, max_length=2000)
class ThroughputProductRead(ThroughputProductBase):
id: int
tenant_id: str
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)
class ThroughputEntryBase(BaseModel):
model_config = ConfigDict(extra="forbid")
production_date: date
product_id: int | None = None
product_name_snapshot: str | None = Field(default=None, max_length=255)
bag_size: float | None = Field(default=None, ge=0)
scales_checked: bool = True
label_correct: bool = True
bag_sealed: bool = True
pallet_good_condition: bool = True
sample_box_no: str | None = Field(default=None, max_length=64)
test_weight_1: float | None = Field(default=None, ge=0)
test_weight_2: float | None = Field(default=None, ge=0)
test_weight_3: float | None = Field(default=None, ge=0)
test_weight_4: float | None = Field(default=None, ge=0)
test_weight_5: float | None = Field(default=None, ge=0)
quantity: float = Field(ge=0)
quantity_type: QuantityType = "bags"
staff_name: str | None = Field(default=None, max_length=255)
notes: str | None = Field(default=None, max_length=2000)
@field_validator("staff_name")
@classmethod
def _normalize_staff(cls, value: str | None) -> str | None:
if value is None:
return None
stripped = value.strip()
return stripped or None
class ThroughputEntryCreate(ThroughputEntryBase):
pass
class ThroughputEntryUpdate(BaseModel):
model_config = ConfigDict(extra="forbid")
production_date: date | None = None
product_id: int | None = None
product_name_snapshot: str | None = Field(default=None, max_length=255)
bag_size: float | None = Field(default=None, ge=0)
scales_checked: bool | None = None
label_correct: bool | None = None
bag_sealed: bool | None = None
pallet_good_condition: bool | None = None
sample_box_no: str | None = Field(default=None, max_length=64)
test_weight_1: float | None = Field(default=None, ge=0)
test_weight_2: float | None = Field(default=None, ge=0)
test_weight_3: float | None = Field(default=None, ge=0)
test_weight_4: float | None = Field(default=None, ge=0)
test_weight_5: float | None = Field(default=None, ge=0)
quantity: float | None = Field(default=None, ge=0)
quantity_type: QuantityType | None = None
staff_name: str | None = Field(default=None, max_length=255)
notes: str | None = Field(default=None, max_length=2000)
class ThroughputEntryRead(BaseModel):
id: int
tenant_id: str
production_date: date
product_id: int | None
product_name_snapshot: str
bag_size: float | None
scales_checked: bool
label_correct: bool
bag_sealed: bool
pallet_good_condition: bool
sample_box_no: str | None
test_weight_1: float | None
test_weight_2: float | None
test_weight_3: float | None
test_weight_4: float | None
test_weight_5: float | None
quantity: float
quantity_type: QuantityType
calculated_kg: float
staff_name: str | None
notes: str | None
qa_passed: bool
created_by: str | None
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)