Backend: Kaufpreis + Belege an Einzelstücken, PDF-Garantie-Vorschlag

- Item: price_cents + currency (Kaufpreis rappen-/centgenau). Migration ergaenzt.
- Neue Tabelle item_documents (mehrere Belege je Stueck, PDF oder Bild); Blob
  wird verzoegert geladen, damit Item-Listen leicht bleiben.
- Endpunkte: Upload (POST), Ansehen/Download (GET), Loeschen (DELETE) je Stueck.
  Dateiname beim Download gehaertet (keine Header-Injektion).
- services/warranty.py: schaetzt aus PDF-Text lokal ein Garantieende
  (Zeitraum + Kaufdatum, oder Datum nahe Garantie-Stichwort); pypdf ergaenzt.
  Der Upload liefert den Vorschlag zurueck. 10 neue Tests, Suite 136 gruen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-26 20:49:08 +02:00
parent 9a11e3cfc6
commit 61270e6d00
8 changed files with 402 additions and 3 deletions

View File

@@ -512,6 +512,8 @@ class ItemCreate(BaseModel):
acquired_on: date | None = None
warranty_until: date | None = None
note: str | None = Field(default=None, max_length=255)
price_cents: int | None = Field(default=None, ge=0)
currency: str | None = Field(default=None, max_length=3)
class ItemUpdate(BaseModel):
@@ -520,6 +522,8 @@ class ItemUpdate(BaseModel):
acquired_on: date | None = None
warranty_until: date | None = None
note: str | None = Field(default=None, max_length=255)
price_cents: int | None = Field(default=None, ge=0)
currency: str | None = Field(default=None, max_length=3)
class ItemRemove(BaseModel):
@@ -527,6 +531,20 @@ class ItemRemove(BaseModel):
note: str | None = Field(default=None, max_length=255)
class ItemDocumentOut(BaseModel):
"""Beleg-Metadaten (ohne Binärdaten)."""
model_config = ConfigDict(from_attributes=True)
id: int
filename: str
content_type: str
uploaded_at: datetime
class ItemDocumentUploadOut(ItemDocumentOut):
"""Antwort nach dem Upload mit dem aus dem PDF vorgeschlagenen Garantieende."""
suggested_warranty_until: date | None = None
class ItemOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
@@ -539,10 +557,13 @@ class ItemOut(BaseModel):
acquired_on: date | None = None
warranty_until: date | None = None
note: str | None = None
price_cents: int | None = None
currency: str | None = None
created_at: datetime
# Für QR-Auflösung/Anzeige mitgeliefert:
product_name: str | None = None
product_brand: str | None = None
documents: list[ItemDocumentOut] = []
# ---- Views ----