Lagerorte per 10-Zeichen-Code statt fortlaufender ID; iOS-Einlagern ohne Kamerazwang
Lagerort-IDs sind jetzt ein zufaelliger 10-Zeichen-Code (wie die Einzelstueck-UIDs) statt einer fortlaufenden Zahl - so kollidiert die Stammdaten-Sicherung zwischen zwei Instanzen praktisch nie mehr, und der Code ist zugleich der Inhalt des QR /l/<code>. Alle Fremdschluessel (lots, movements, items, Mindestbestaende, parent_id) ziehen mit; die Umstellung laeuft einmalig und transaktional beim Serverstart (_migrate_locations_to_code) und rollt bei Fehlern komplett zurueck. Vor dem Deploy ein DB-Backup machen. iOS-Einlagern oeffnet nicht mehr sofort die Kamera, sondern ein Formular mit Artikelsuche; die Kamera kommt erst per Button. Im Formular laesst sich der Lagerort zusaetzlich per /l/-QR scannen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -111,13 +111,13 @@ class UserUpdate(BaseModel):
|
||||
# ---- Groups ----
|
||||
class LocationMinStockIn(BaseModel):
|
||||
"""Ein Mindestbestand-Eintrag je Lagerort (Menge in Artikeleinheiten)."""
|
||||
location_id: int
|
||||
location_id: str
|
||||
min_stock: float = Field(ge=0)
|
||||
|
||||
|
||||
class LocationMinStockOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
location_id: int
|
||||
location_id: str
|
||||
location_name: str | None = None
|
||||
min_stock: float
|
||||
|
||||
@@ -239,19 +239,19 @@ class FieldDefinitionOut(BaseModel):
|
||||
# ---- Locations ----
|
||||
class LocationOut(BaseModel):
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
id: int
|
||||
id: str
|
||||
name: str
|
||||
parent_id: int | None = None
|
||||
parent_id: str | None = None
|
||||
|
||||
|
||||
class LocationCreate(BaseModel):
|
||||
name: str = Field(min_length=1, max_length=120)
|
||||
parent_id: int | None = None
|
||||
parent_id: str | None = None
|
||||
|
||||
|
||||
class LocationUpdate(BaseModel):
|
||||
name: str | None = Field(default=None, min_length=1, max_length=120)
|
||||
parent_id: int | None = None
|
||||
parent_id: str | None = None
|
||||
|
||||
|
||||
# ---- Gebinde (Packung, Glas, …) ----
|
||||
@@ -409,7 +409,7 @@ class CheckInRequest(BaseModel):
|
||||
best_before: date | None = None
|
||||
# "month" legt das MHD auf den Monatsletzten (siehe services/dates.py).
|
||||
best_before_precision: DatePrecision = DatePrecision.day
|
||||
location_id: int | None = None
|
||||
location_id: str | None = None
|
||||
note: str | None = None
|
||||
|
||||
|
||||
@@ -430,7 +430,7 @@ class LotOut(BaseModel):
|
||||
quantity: float
|
||||
best_before: date | None
|
||||
best_before_precision: DatePrecision = DatePrecision.day
|
||||
location_id: int | None
|
||||
location_id: str | None
|
||||
created_at: datetime
|
||||
|
||||
|
||||
@@ -439,7 +439,7 @@ class LotUpdate(BaseModel):
|
||||
quantity: float | None = Field(default=None, gt=0)
|
||||
best_before: date | None = None
|
||||
best_before_precision: DatePrecision | None = None
|
||||
location_id: int | None = None
|
||||
location_id: str | None = None
|
||||
|
||||
|
||||
class CheckInResponse(BaseModel):
|
||||
@@ -452,7 +452,7 @@ class CheckInLine(BaseModel):
|
||||
quantity: float = Field(gt=0)
|
||||
best_before: date | None = None
|
||||
best_before_precision: DatePrecision = DatePrecision.day
|
||||
location_id: int | None = None
|
||||
location_id: str | None = None
|
||||
|
||||
|
||||
class BatchCheckInRequest(BaseModel):
|
||||
@@ -479,8 +479,8 @@ class RelocateRequest(BaseModel):
|
||||
product_id: int | None = None
|
||||
barcode: str | None = None
|
||||
quantity: float = Field(gt=0)
|
||||
from_location_id: int | None = None
|
||||
to_location_id: int | None = None
|
||||
from_location_id: str | None = None
|
||||
to_location_id: str | None = None
|
||||
note: str | None = None
|
||||
|
||||
|
||||
@@ -489,7 +489,7 @@ class RemoveRequest(BaseModel):
|
||||
product_id: int | None = None
|
||||
barcode: str | None = None
|
||||
quantity: float = Field(gt=0)
|
||||
location_id: int | None = None
|
||||
location_id: str | None = None
|
||||
reason: RemovalReason
|
||||
note: str | None = None
|
||||
|
||||
@@ -508,7 +508,7 @@ class RemovalStat(BaseModel):
|
||||
class RemovalHistoryItem(BaseModel):
|
||||
reason: RemovalReason
|
||||
quantity: float
|
||||
location_id: int | None = None
|
||||
location_id: str | None = None
|
||||
location_name: str | None = None
|
||||
note: str | None = None
|
||||
username: str | None = None
|
||||
@@ -524,7 +524,7 @@ class RemovalSummary(BaseModel):
|
||||
class ItemCreate(BaseModel):
|
||||
"""Ein oder mehrere Einzelstücke mit gemeinsamen Startwerten anlegen."""
|
||||
count: int = Field(default=1, ge=1, le=200)
|
||||
location_id: int | None = None
|
||||
location_id: str | None = None
|
||||
shop_id: int | None = None
|
||||
acquired_on: date | None = None
|
||||
warranty_until: date | None = None
|
||||
@@ -534,7 +534,7 @@ class ItemCreate(BaseModel):
|
||||
|
||||
|
||||
class ItemUpdate(BaseModel):
|
||||
location_id: int | None = None
|
||||
location_id: str | None = None
|
||||
shop_id: int | None = None
|
||||
acquired_on: date | None = None
|
||||
warranty_until: date | None = None
|
||||
@@ -578,7 +578,7 @@ class ItemOut(BaseModel):
|
||||
id: int
|
||||
uid: str
|
||||
product_id: int
|
||||
location_id: int | None = None
|
||||
location_id: str | None = None
|
||||
location_name: str | None = None
|
||||
shop_id: int | None = None
|
||||
shop_name: str | None = None
|
||||
@@ -652,7 +652,7 @@ class LocationNeedGroup(BaseModel):
|
||||
|
||||
class LocationNeeds(BaseModel):
|
||||
"""Alle Bedarfe (Produkte + Gruppen) eines Lagerorts."""
|
||||
location_id: int
|
||||
location_id: str
|
||||
location_name: str
|
||||
products: list[LocationNeedProduct] = []
|
||||
groups: list[LocationNeedGroup] = []
|
||||
|
||||
Reference in New Issue
Block a user