feat: Phase 2H — void/waste log
Backend:
- New model: WasteLog (waste_log table) — product, quantity (float), reason, reason_notes,
unit_cost_snapshot (copied at log time from product's effective cost), total_cost (stored),
logged_by, business_day_id
- Cost snapshot: same logic as Phase 2A — breakdown sum first, fallback to cost_simple, null if neither
- New router /api/waste/:
- GET / — list entries (?business_day_id= or ?from=&to=), ordered by logged_at desc
- POST / — log waste; snapshots cost; attaches to open business day automatically
- DELETE /{id} — manager only; only allowed within the same open business day
- GET /summary — totals by reason + by product for a period
- product_performance report: waste_qty + waste_cost added per product from the same period;
products with only waste (no sales) also included
- Migration: CREATE TABLE IF NOT EXISTS waste_log
Frontend:
- WastePage (/waste): fast log form (product picker, quantity, reason chips, notes);
today's entries list below (scoped to active business day); cost shown per entry;
delete button for today's entries; history section behind toggle with date-range picker
- ProductPerformance report: Απόβλητα column showing waste_qty + cost in amber
- Sidebar: Trash2 icon for Αποβλήτα (after Καρτέλες)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
37
local_backend/schemas/waste.py
Normal file
37
local_backend/schemas/waste.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
|
||||
VALID_REASONS = {"kitchen_error", "dropped", "expired", "other"}
|
||||
|
||||
REASON_LABELS = {
|
||||
"kitchen_error": "Λάθος κουζίνας",
|
||||
"dropped": "Έπεσε",
|
||||
"expired": "Έληξε",
|
||||
"other": "Άλλο",
|
||||
}
|
||||
|
||||
|
||||
class WasteLogCreate(BaseModel):
|
||||
product_id: int
|
||||
quantity: float
|
||||
reason: str
|
||||
reason_notes: Optional[str] = None
|
||||
|
||||
|
||||
class WasteLogOut(BaseModel):
|
||||
id: int
|
||||
product_id: int
|
||||
product_name: Optional[str] = None
|
||||
quantity: float
|
||||
unit_cost_snapshot: Optional[float] = None
|
||||
total_cost: Optional[float] = None
|
||||
reason: str
|
||||
reason_label: Optional[str] = None
|
||||
reason_notes: Optional[str] = None
|
||||
logged_by_id: int
|
||||
logged_by_name: Optional[str] = None
|
||||
business_day_id: Optional[int] = None
|
||||
logged_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
Reference in New Issue
Block a user