Foodops
All docs

Ordering · Updated 2026-08-22 · vef65221

Deliveries

Audio narration for this article is generated with the weekly docs refresh.

Plain-English summary

Deliveries is the queue for orders that go out to customers. On the counter app it is not a separate page — it is the POS order screen in delivery mode: the same session POS filtered to delivery orders, with its own status tabs (Open → Preparing → Ready → Enroute → Delivered), a delivery-sector filter, and a one-tap driver assignment modal. Riders use a separate Flutter mobile app to see their assigned orders, navigate, collect cash, and mark orders delivered; rider cash flows back to the register through a handover/acknowledge step. Delivery-specific data (sectors with per-sector charges, delivery addresses, driver assignment) attaches to the order at creation.

When you'd use this

  • Dispatching drivers — assign orders, track Enroute/Delivered status
  • Working the delivery queue during service — which orders are ready to go out
  • Filtering the queue by delivery sector to batch nearby orders onto one rider
  • Reconciling rider cash at end of shift (Delivery Cash tab on the session)

How to access

  • Sidebar: "Deliveries" — with an open session it navigates to /sessions/{sessionId}/pos?mode=delivery; with no session it goes to /counter?intent=delivery so you open a register first. [code: foodops.counter.app/src/components/layout/Sidebar.tsx:321-339 (mode=delivery at :325, no-session intent at :335) @main]
  • Mobile bottom nav: same ?mode=delivery navigation. [code: src/components/layout/MobileBottomNav.tsx:80 @main]
  • Note: there is no separate /deliveries page in the counter app — the real surface is POS delivery mode. [code: NavigationContext.tsx:37 (active-menu mapping only, no Route) @main]

Walkthrough

Working the delivery queue (cashier/dispatcher, counter app)

Reconstructed from POSPage source, re-audited at main HEAD df086e4 (2026-06-14).

  1. Open the sidebar Deliveries item (requires an open register session). The POS loads with header Deliveries and delivery-specific status tabs: Open / Preparing / Ready / Enroute / Delivered. [code: foodops.counter.app/src/pages/POSPage.tsx:4367(header label),4425-4434(delivery tab list) @main]
  2. (Optional) Filter by delivery sector — sectors are fetched per session and each carries a name + delivery charge (DisplayName => $"{Name} ({FormattedCharge})", e.g. "Hulhumalé (MVR 30.00)"). Selecting a sector reloads the order list scoped to it. [code: POSPage.tsx:651-665(per-session fetch),668-671(reload on sector change) @main; hubits-api-sales/Hubits.Sales.Api/Dto/Counter/Delivery/DeliverySectorDto.cs:10 @main]
  3. Create a delivery order with the Delivery button (shown only when orderButtonConfig.enableDelivery is true for the outlet) — this routes into the standard order-create flow with order type id = 3 (delivery); customer, delivery sector and delivery address attach via the order summary panel. [code: POSPage.tsx:4377,4398,4766(button gated on enableDelivery),1469/1765(orderTypeId: isDeliveryMode ? 3) @main; src/components/orders/OrderSummaryPanel.tsx:21-22(deliverySectorId?/deliveryAddressId?) @main]
  4. Assign a driver from the order card — the driver assignment modal lists drivers and assigns on a single tap ("Mirrors the Restaurant.App _DriversAssignment.cshtml UX: tap a card, it assigns immediately and closes"). [code: src/components/orders/DriverAssignmentModal.tsx:14-15(doc comment),41(getDrivers(orderId)),52(currentDriverId guard) @main]
  5. Mark the order Enroute (Out for Delivery, status id 6) — from the order card or automatically when the rider picks it up via the rider app. [code: src/components/orders/OrderCard.tsx:742]
  6. Delivered (status id 7) is the terminal state. The rider flow owns this transition — item-served events do NOT auto-advance delivery orders the way they advance dine-in (Served) and takeout (Picked). [code: POSPage.tsx:774-777 — "Delivery doesn't auto-advance on item-served; leave the operation status untouched so the rider flow stays in control" @main]

Rider workflow (Flutter driver app — DORMANT/LEGACY)

Warning: Launch posture: the standalone Flutter rider app is a dormant/legacy surface (manual build, no CI; foodops.delivery.api retired 2025-11-27). It still functions because it points at the live sales API, but it is not a primary launch surface. For the July-10 launch, delivery is operated from the counter delivery queue (above) + the sales API delivery service; rider assignment and cash reconciliation run there. See Rider App.

The driver app (foodops.delivery.mobile, Flutter) talks directly to the sales API (sales-api.hubits.io) and its /orderHub SignalR hub. [code: foodops.delivery.mobile/lib/Helper/Api/api_constant.dart:4(baseUrl=https://sales-api.hubits.io/api/),8(signalRHubUrl=.../orderHub),18(identity-api) @master]

  1. Rider logs in (identity API) and picks the organisation. [screens: lib/Screens/DeliveryScreen/LoginScreen, OrganizationScreen]
  2. Rider sees delivery orders (delivery-management/orders) and order details; assigned orders surface on the Assigned Orders screen. [code: api_constant.dart:28,39]
  3. Rider marks the order en route (POST api/delivery/orders/mark-enroute) and later delivered (mark-delivered). [code: foodops.delivery.mobile/lib/Helper/Api/api_constant.dart:55-56 @master; hubits-api-sales/Hubits.Sales.Api/Controllers/DeliveryOrdersController.cs:291(mark-enroute),349(mark-delivered) @main]
  4. For cash orders the rider records collection (POST delivery-management/orders/{id}/cash/collect), hands the cash over to the register (POST delivery-management/cash/handover), and can check cash on hand (GET delivery-management/cash/on-hand). [code: hubits-api-sales/Hubits.Sales.Api/Controllers/DeliveryManagementController.cs:182(collect),208(handover),234(on-hand) @main]
  5. The cashier acknowledges the handed-over cash in the session's Delivery Cash tab, which adds it to the session's Expected balance — see Cash Handling.

The driver app also contains a Waiter mode (dine-in order taking screens) alongside the delivery screens. [dirs: lib/Screens/WaiterScreen/{AddOrderScreen,DineInScreen,...}]

Key concepts

  • Delivery mode, not a delivery page — the queue is POSPage with ?mode=delivery; the tab whitelist, status mapping, and sector filter all key off isDeliveryMode. [code: POSPage.tsx:176(isDeliveryMode = modeParam === 'delivery'),1397-1399(tab whitelist),651-665(sector fetch) @main]
  • Status lifecycle (delivery) — New(1)/Accepted(2) → Preparing(3) → Ready(4) → OutForDelivery(6, shown as "Enroute") → Delivered(7). (Server enum is authoritative: New=1…Served=5, OutForDelivery=6, Delivered=7, Picked=8.) The rendered delivery-mode tabs are Open / Preparing / Ready / Enroute / Delivered (the last tab has internal key='Served' but label='Delivered', mapping to the server Delivered filter). The "Delivered" tab badge sums delivered+served+picked terminal buckets so badge count equals list count. [code: POSPage.tsx:705-714(client ids),4425-4434(rendered delivery tabs) @main; haafai.domain/haafai.domain/Haafai.Models/Constants/ModelConstants.cs:RestaurantOrderOperationStatus:51-60 @staging]
  • Delivery sectors — named zones with a per-sector delivery charge and currency, maintained in restaurant settings (api/settings/restaurant/delivery-sectors) and selectable on the order; also usable as a queue filter. [code: hubits-api-sales/Hubits.Sales.Api/Controllers/RestaurantSettingsController.cs:749-863; DeliverySectorDto.cs]
  • Driver assignment — drivers are fetched per order (driverApiService.getDrivers(orderId)) and assigned one-tap; the current driver is highlighted. [code: DriverAssignmentModal.tsx:41(getDrivers),52(current driver guard) @main; src/services/driver/driverApiService.ts:46(getDrivers signature) @main]
  • Rider cash loop — collect (rider) → handover (rider) → acknowledge (cashier, session Delivery Cash tab) → Expected balance. Unacknowledged rider cash shows up as an unexplained over at session close.
  • Two backends, one live — the rider app's original backend repo (foodops.delivery.api, the foodops.app.api project) is dormant (master HEAD 51a1f8c dated 2025-11-27); the same controller surface (Delivery, DeliveryManagement, CashOnHand, DeliveryOrders, DeliverySectors, OrderHub) now lives in hubits-api-sales, and the shipped app points at sales-api.hubits.io. [code: foodops.delivery.mobile/lib/Helper/Api/api_constant.dart:4 @master; hubits-api-sales/Hubits.Sales.Api/Controllers/{Delivery,DeliveryManagement,CashOnHand,DeliveryOrders,DeliverySectors}Controller.cs + Hubs/OrderHub.cs mapped at Program.cs:337 @main]

Common questions

Q: Where do I see all delivery orders? A: Sidebar → Deliveries. With an open session you land in POS delivery mode; the Open tab shows everything not yet out the door, Enroute shows orders with riders, Delivered is the terminal tab.

Q: How do I assign a rider to an order? A: Open the delivery order's card and choose the driver assignment action — the modal lists drivers; tapping one assigns immediately and closes. [code: DriverAssignmentModal.tsx]

Q: Can a delivery order exist without a sector? A: Yes — the sector is optional on the order (deliverySectorId?), and the queue's sector filter defaults to "All". [code: OrderSummaryPanel.tsx:21; POSPage.tsx:314]

Q: Who marks the order Delivered — the cashier or the rider? A: Either can, but the flow is designed for the rider: the rider app calls mark-delivered, and the POS deliberately leaves delivery orders alone on item-served events "so the rider flow stays in control". The cashier can also mark Delivered from the order card (the "Delivered" button on out-for-delivery cards). [code: POSPage.tsx:774-777; OrderCard.tsx:handleMarkAsDelivered:778-797 @main]

Q: What does the "Enroute" tab mean exactly? A: Orders in operation status OutForDelivery (id 6) that are not yet paid/closed. The tab key maps to the server's OutForDelivery filter. [code: POSPage.tsx:681-682(Enroute→OutForDelivery),2154 — restaurantOperationStatusId === 6 ... && !isOrderPaid(o) @main]

Q: How does the delivery charge get onto the order? A: From the selected delivery sector — each sector carries a configured charge; selecting a sector on the order passes the charge to the order totals. [code: OrderSummaryPanel.tsx:51; DeliverySectorDto.cs]

Q: Where are delivery sectors configured? A: Restaurant settings → outlet Services/delivery settings (admin app), backed by api/settings/restaurant/delivery-sectors CRUD. [code: RestaurantSettingsController.cs:749-863; foodops-admin-app DeliverySectorFormDialog.tsx]

Q: What happens with cash the rider collected? A: The rider records collection and hands cash over via the rider app; the cashier acknowledges the handover in Session Details → Delivery Cash, which counts it into the session's Expected cash. See Cash Handling.

Q: Do delivery orders appear on the Kitchen Display?

A: Yes — kitchen routing is order-type-agnostic; KOTs fire on confirmation like any other order. See Kitchen Display System.

Q: Is there an integration with third-party delivery platforms (UberEats-style)? A: Not found in current code as of 2026-06-14. The delivery stack is in-house riders only — sectors, own driver assignment, own rider app. (The user story US-INT-004 describes third-party fleet integration as an aspiration; no implementing code was found.) [code: VERIFIED-ABSENT — grep of foodops.counter.app@main src/ for ubereats|deliveroo|talabat|doordash|grubhub|aggregator returned no delivery-integration code]

Q: Customers ordering delivery online — same queue? A: Yes. Online orders placed with delivery mode flow into the counter via SignalR and appear in the same delivery queue. See Online Ordering Platform.

Q: Can I take payment before the rider leaves? A: Yes — delivery orders support the normal payment flow at the counter; cash-on-delivery instead flows through the rider cash loop (delivery/orders/payment endpoint serves the rider-side payment record). [code: DeliveryOrdersController.cs:154]

Edge cases and known issues

  • No open session → no queue — the Deliveries sidebar item needs a session; without one you are routed to /counter?intent=delivery to open a register first. [code: Sidebar.tsx:323-338 — if (currentSession) navigate(/sessions/{id}/pos?mode=delivery); else navigate('/counter?intent=delivery') @main]
  • Item-served does not advance delivery orders — unlike dine-in/takeout, a delivery order stays in its current status when the kitchen marks all items served; only the enroute/delivered transitions move it. Symptom: "kitchen finished but order still shows Preparing/Ready" is expected until dispatch. [code: POSPage.tsx:774-777 — the orderTypeLower === 'delivery' branch deliberately leaves operationStatus untouched while takeout advances to Picked(8) @main]
  • Legacy rider backendfoodops.delivery.api (project foodops.app.api) is dormant; do not verify rider behaviour against it. The live rider endpoints are in hubits-api-sales under api/delivery, api/delivery/orders, api/delivery-management. The repo is retained in source_repos only as the historical reference for the Flutter app's API contract.
  • Sector filter only in delivery mode — leaving delivery mode clears any selected sector filter; sector state does not leak into takeout/counter views. [code: POSPage.tsx:1386-1390 — if (!isDeliveryMode && selectedDeliverySectorId) setSelectedDeliverySectorId('') @main]
  • Old monolith Delivery views retired — the legacy haafai.app.foodops Haafai.Restaurant.App/Views/Delivery/** monolith surface is retired at the July-10 launch; the live delivery surface is the counter delivery mode + hubits-api-sales.

Related

  • Takeouts — sibling queue for pickup orders (?mode=takeout)

  • Order Types — dine-in vs takeout vs delivery enablement per outlet

  • Cash Handling — the rider-cash acknowledge flow on the session

  • Online Ordering Platform — the customer-facing source of many delivery orders

  • Outlets — enabling the Delivery service per outlet

  • 2026-06-14 — codebase TRUTH AUDIT against current prod HEADs foodops.counter.app@df086e4 (main), hubits-api-sales@f79eb7b (main), foodops.delivery.mobile@3d9ff2c (master), haafai.domain@a2bd90e (staging). All customer-facing claims confirmed TRUE; line-number citations re-pinned to current HEAD and @branch tags added. Specifics verified in code: status enum New(1)…OutForDelivery(6)/Delivered(7)/Picked(8) against haafai.domain ModelConstants.cs:RestaurantOrderOperationStatus; rendered delivery tabs Open/Preparing/Ready/Enroute/Delivered (last tab internal key=Served, label=Delivered) at POSPage.tsx:4425-4434; no-auto-advance-on-item-served for delivery at POSPage.tsx:774-777; Sidebar/MobileBottomNav ?mode=delivery + ?intent=delivery nav; no /deliveries Route (only vestigial NavigationContext mapping); DeliveryManagementController cash collect(182)/handover(208)/on-hand(234) — FIXED transposed handover/on-hand line cites; DeliveryOrdersController mark-enroute(291)/mark-delivered(349)/payment(154); RestaurantSettings delivery-sectors CRUD(749+); Flutter api_constant baseUrl=sales-api.hubits.io + WaiterScreen/DeliveryScreen dirs; foodops.delivery.api dormant (master HEAD 51a1f8c dated 2025-11-27 ✓). Third-party platform integration re-verified ABSENT via grep. ONE soft claim flagged UNVERIFIED: delivery KOTs appear on KDS (no order-type gating found that excludes delivery, but no affirmative delivery-specific KOT path — deferred to kitchen-display.md).

  • 2026-06-29 — codebase: NEW-STACK launch re-verification (July-10). Re-pinned to current prod HEADs: foodops.counter.app@32669a9f3a, hubits-api-sales@19190b9a04, haafai.domain@e1389444ca (staging). CONFIRMED the live delivery surface is the counter delivery queue (POS ?mode=delivery) + hubits-api-sales Services/Counter/Delivery/** (DeliveryController/DeliveryOrdersController/DeliveryManagementController/DeliverySectorsController/DeliveryService all present on main). Removed dormant foodops.delivery.api from source_repos (retired 2025-11-27; superseded by sales-api). LAUNCH POSTURE FLAGGED: the standalone Flutter rider app (foodops.delivery.mobile, master HEAD 1ff0a759f3, re-point commit 2026-06-15, no CI) is dormant/legacy, not a primary launch surface — added a warning to the rider workflow section. Retired-monolith Delivery views edge case updated. Customer-facing delivery-queue claims (status tabs, sector filter, driver assignment, rider cash loop, no-auto-advance-on-item-served) unchanged from the 2026-06-14 audit.

Additional verification events are appended here by the weekly KB sync and by manual re-verification passes. See _meta/failure-log.md for the global failure index.

Go beyond POS.
Choose the total solution.

Focus on creating the best experience for your guests while we handle the rest.