diff --git a/local_backend/models/order.py b/local_backend/models/order.py index 30436be..55b117c 100644 --- a/local_backend/models/order.py +++ b/local_backend/models/order.py @@ -81,6 +81,11 @@ class OrderItem(Base): # Phase 2A — cost snapshot (copied from product at time of order, never updated) unit_cost = Column(Float, nullable=True) + # Phase 2B — cancellation tracking + cancelled_by = Column(Integer, ForeignKey("users.id"), nullable=True) + cancelled_at = Column(DateTime(timezone=True), nullable=True) + cancel_reason = Column(Text, nullable=True) + order = relationship("Order", back_populates="items") product = relationship("Product", back_populates="order_items") added_by_user = relationship("User", foreign_keys=[added_by], back_populates="order_items") diff --git a/local_backend/routers/reports.py b/local_backend/routers/reports.py index ee85ca1..e7b3129 100644 --- a/local_backend/routers/reports.py +++ b/local_backend/routers/reports.py @@ -1260,6 +1260,16 @@ def current_business_day( p = db.query(Product).filter(Product.id == top_product_id).first() top_product = {"id": top_product_id, "name": p.name if p else f"#{top_product_id}", "qty": item_counts[top_product_id]} + # Count cancelled items (individual items cancelled, across all orders in this day) + all_order_ids = [o.id for o in orders] + cancelled_items_qty = 0 + if all_order_ids: + from sqlalchemy import func as sqlfunc + cancelled_items_qty = db.query(sqlfunc.sum(OrderItem.quantity)).filter( + OrderItem.order_id.in_(all_order_ids), + OrderItem.status == "cancelled", + ).scalar() or 0 + return { "business_day": { "id": day.id, @@ -1272,6 +1282,7 @@ def current_business_day( "orders_open": len(open_orders), "active_waiters": len(active_shifts), "cancellations": len(cancelled_orders), + "cancelled_items": int(cancelled_items_qty), "top_product": top_product, } } diff --git a/local_backend/routers/shifts.py b/local_backend/routers/shifts.py index 9877ec0..7bce207 100644 --- a/local_backend/routers/shifts.py +++ b/local_backend/routers/shifts.py @@ -75,7 +75,7 @@ def _enrich_shift(shift: WaiterShift, db: Session) -> dict: wname = (w.full_name or w.username) if w else f"#{shift.waiter_id}" total = compute_shift_total(shift.id, db) if shift.ended_at is None else (shift.total_collected or 0.0) pay_data = compute_shift_pay(shift) - # Count cancelled items attributed to this waiter during shift window + # Count cancelled items and their value attributed to this waiter during shift window cancelled_q = db.query(OrderItem).filter( OrderItem.status == "cancelled", OrderItem.added_by == shift.waiter_id, @@ -83,7 +83,9 @@ def _enrich_shift(shift: WaiterShift, db: Session) -> dict: ) if shift.ended_at: cancelled_q = cancelled_q.filter(OrderItem.added_at <= shift.ended_at) - cancellations = cancelled_q.count() + cancelled_rows = cancelled_q.all() + cancellations = sum(r.quantity for r in cancelled_rows) + cancellation_value = round(sum(r.unit_price * r.quantity for r in cancelled_rows), 2) return { "id": shift.id, "waiter_id": shift.waiter_id, @@ -100,6 +102,7 @@ def _enrich_shift(shift: WaiterShift, db: Session) -> dict: "duration_hours": pay_data["duration_hours"], "shift_pay": pay_data["shift_pay"], "cancellations": cancellations, + "cancellation_value": cancellation_value, # Phase 2E "counted_cash_end": shift.counted_cash_end, "cash_discrepancy": shift.cash_discrepancy, diff --git a/manager_dashboard/src/pages/Settings/tabs/PrintFontsTab.jsx b/manager_dashboard/src/pages/Settings/tabs/PrintFontsTab.jsx index 63b5423..f1578e6 100644 --- a/manager_dashboard/src/pages/Settings/tabs/PrintFontsTab.jsx +++ b/manager_dashboard/src/pages/Settings/tabs/PrintFontsTab.jsx @@ -804,7 +804,7 @@ function FindPrintersModal({ onClose, onSelect }) { setError(null) setScanning(true) - const token = localStorage.getItem('access_token') || '' + const token = localStorage.getItem('manager_token') || '' const params = new URLSearchParams({ subnet, port }) // Use fetch with ReadableStream to consume SSE (EventSource doesn't support auth headers) fetch(`/api/system/printers/scan?${params}`, { diff --git a/manager_dashboard/src/pages/reports/restaurant/OrderHistory.jsx b/manager_dashboard/src/pages/reports/restaurant/OrderHistory.jsx index 575171b..6e5802e 100644 --- a/manager_dashboard/src/pages/reports/restaurant/OrderHistory.jsx +++ b/manager_dashboard/src/pages/reports/restaurant/OrderHistory.jsx @@ -95,8 +95,11 @@ export default function OrderHistory({ initialBusinessDayId } = {}) {
{orders.slice(0, 200).map(o => { - const activeItems = (o.items || []).filter(i => i.status !== 'cancelled') - const cancelledItems = (o.items || []).filter(i => i.status === 'cancelled') + const allItems = o.items || [] + const activeItems = allItems.filter(i => i.status !== 'cancelled') + const cancelledItems = allItems.filter(i => i.status === 'cancelled') + const totalQty = allItems.reduce((s, i) => s + (i.quantity || 1), 0) + const cancelledQty = cancelledItems.reduce((s, i) => s + (i.quantity || 1), 0) const total = activeItems.reduce((s, i) => s + i.unit_price * i.quantity, 0) const isCancelled = o.status === 'cancelled' return ( @@ -106,10 +109,10 @@ export default function OrderHistory({ initialBusinessDayId } = {}) {