Koovira Dev Docs
20-modules/food/overview.md

Module: FoodVerse / Restaurant (food / food+tiffin)

Status: ๐ŸŸข Production verified (real order lines + commission) ยท Last validated: 2026-09-06 ยท Priority: P0

Restaurant discovery + food ordering + tiffin subscriptions + dine-in table booking + group orders. Validated against classs/RestaurantModule.php (6,422 lines by wc -l, 2026-09-06 โ€” corrected from an earlier "~4,700 lines" estimate) and the live schema.


A. Purpose

Customers discover restaurants and place food orders (instant delivery), subscribe to tiffin plans, book dine-in tables, and run group orders. Merchants (restaurant owners) manage menu, branches, orders, and refunds. Revenue = 5% commission (platform_commission_settings.setting_key='food_order', live โ€” 19 processed rows in commission_transactions for order_table='food_orders', 2026-09-06; corrected from an earlier count of 17 โ€” this is a moving snapshot on an actively-tested environment).

B. Actors

Customer/buyer; restaurant owner + restaurant_staff; delivery partner (hyperlocal/courier); admin. Tiffin provider is the tiffin enrollment type.

C. Entry points

Consumer: /restaurants.php, /foodverse.php, restaurant detail, cart/checkout; tracking JS assets/newjs/food_track_order.js. Merchant: food dashboard, menu, orders (owner methods below). Writes flow through RestaurantModule (via forms/doaction_*).

D. Onboarding

registerRestaurant(userId, companyId, data) (:794) โ†’ restaurant_master. Module food on; merchant enrolled; menu built before publishing. Food is FSSAI/licence-sensitive (see ../../30-core/kyc-trust.md).

E. Feature registry (prefix FOOD-)

IDFeatureActorMethodTables (write)Status
FOOD-001List / discover restaurantsanon+custlistRestaurants :1000โ€”๐ŸŸข
FOOD-002Restaurant detail (buyer)anon+custgetRestaurantDetails(publicOnly) :1191โ€”๐ŸŸข
FOOD-003View menuanon+custgetMenu(publicOnly) :1293โ€”๐ŸŸข
FOOD-004Register restaurantownerregisterRestaurant :794restaurant_master, restaurant_operating_hours, restaurant_meal_slots๐ŸŸข
FOOD-005Menu CRUDowner/staffownerAddCategory/AddMenuItem/UpdateMenuItem/ToggleMenuItem :1482-1793menu tables๐ŸŸข
FOOD-006BranchesownerownerListBranches/CreateBranch :1877/:1913restaurant_master (branch)๐ŸŸข
FOOD-007Place order (instant)customerplaceOrderInstant :2432food_orders, food_order_items, food_order_status_history๐ŸŸข (money)
FOOD-008Order status updateownerupdateRestaurantOrderStatus :2164food_orders, food_order_status_history๐ŸŸข
FOOD-009Cancel ordercustomercancelOrderByUser :3646food_orders, ledger๐ŸŸก
FOOD-010Merchant refundownerrefundOrderByMerchant :4033refund + wallet๐ŸŸก
FOOD-011Tiffin subscriptioncustomercreateTiffinSubscription :4254tiffin_plans, tiffin_order_map, tiffin_plan_items๐ŸŸข
FOOD-012Dine-in table bookingcustomer(writes restaurant_table_bookings :6236)restaurant_table_bookings๐ŸŸก
FOOD-013Group ordercustomer(writes food_group_orders :5240)food_group_orders, food_group_order_items๐ŸŸก
FOOD-014Meal preferencescustomersaveMealPreferences/getMealPreferences :4635/:4714food_meal_preferences๐ŸŸข

F. Order flow (FOOD-007, the money path)

restaurants.php โ†’ restaurant detail โ†’ cart โ†’ placeOrderInstant(userId, restaurantId, items, deliveryData)  :2432
  validate items + delivery; server-side pricing from menu (like CommerceX, not client)
  wallet debit (wallet-first)  :2774
  escrow credit to CLASSIFIED_ESCROW_BUCKET_USER_ID  :2809  (platform holds funds until delivery โ€”
    CommerceSettlementModule::releaseFoodPayouts() pays the restaurant out later)
  INSERT food_orders (header)              :2875
  INSERT food_order_items (one per line)   :3063   โ† FoodVerse IS normalized (header+items)
  INSERT food_order_status_history         :3087
  commission โ†’ CommissionEngineModule::computeAndRecord('food_order', โ€ฆ) :2937 โ†’ commission_transactions
  central payments ledger (PaymentsModule::recordWalletPayment)  :2977
  notify restaurant + customer

Correction (2026-09-06): an earlier pass of this page cited the header/items/status-history INSERTs at :6043/:6075/:6113. Those line numbers are real INSERTs into the same three tables, but they belong to a different method further down the file โ€” the tiffin daily-order auto-generator (it builds a food_orders row from tiffin_plan_items/sub['plan_id'], not from a customer's cart) โ€” not placeOrderInstant. The actual placeOrderInstant writes are at :2875 (header, confirmed by the 'placeOrderInstant ledger error' log string right after it at :2989), :3063 (items), and :3087 (status history), corrected above. Contrast with CommerceX: Food normalizes lines into food_order_items, whereas CommerceX keeps lines on orders_master. When aggregating "an order", Food = 1 header + N item rows.

G. Data model (2026-09-06)

TableRowsRole
restaurant_master872restaurants (+ branches)
food_orders1order header
food_order_items82order lines
food_order_status_history80status transitions
restaurant_table_bookings0dine-in bookings (feature wired, no live bookings yet)
tiffin_plans / tiffin_order_map15 / 30tiffin subscription plans + orders
food_group_orders / food_group_order_items3 / 0group ordering
food_meal_preferences0customer diet prefs (no rows yet)
restaurant_staff0staff sub-users (no rows yet)
Data-state anomaly (requires verification): food_orders = 1 header but food_order_items = 82 and food_order_status_history = 80. Child rows without matching headers strongly suggests the order-header table was purged/reset while child + finance rows were retained. The schema is header+items (validated from the INSERT sites); the counts need a reconcile before quoting "N orders". Same pattern seen in StayGo โ€” see ../hotels/overview.md for its current (2026-09-06) counts, which have themselves moved since this page's hotel_payments cross-reference was first written; do not copy a specific number across module pages, re-check live.

H. Financial impact

Wallet-first debit (:2774) โ†’ escrow credit to CLASSIFIED_ESCROW_BUCKET_USER_ID (:2809, held until delivery) โ†’ central ledger (module_key='food') โ†’ 5% commission (commission_transactions, live) โ†’ CommerceSettlementModule::releaseFoodPayouts() settles the restaurant. Refund via refundOrderByMerchant (:4033) โ†’ wallet credit + ledger refund_processed entry. See ../../40-financial/central-finance-ledger.md. Note: neither the customer debit (:2774) nor the escrow credit (:2809) passes an acct_purpose in $meta to WalletModule, so both fall through to the historical default account mapping in WalletModule::journalAccountsFor() (classs/WalletModule.php:952-983) โ€” the debit is journaled as USER_WALLET_LIABILITY โ†’ REVENUE_GENERAL (booked as recognised revenue) rather than an escrow-liability movement, even though the money is actually being held, not earned, at this point. This is the same class of gap the function's own docblock documents (WalletModule.php:938-946, "AccountingJournalModule context-blind mapping"); flagging here because Food's checkout path is a live, unfixed caller of the vulnerable default โ€” see this audit's cover report for the corresponding note on Hotels/Freelancer/Events.

K. State machine (food_orders.order status)

placed โ†’ accepted โ†’ preparing โ†’ ready โ†’ out_for_delivery โ†’ delivered โ†’ completed, with cancelled / rejected / refunded. Transitions via updateRestaurantOrderStatus (owner) and cancelOrderByUser (customer); each writes food_order_status_history.

L. Errors (prefix FOOD-E)

  • FOOD-E001 item unavailable / restaurant closed at checkout โ€” placeOrderInstant refuses (menu

publicOnly/availability); inspect menu item is_available + operating hours/meal slots.

  • FOOD-E002 order-header/item count mismatch โ€” see data-state anomaly above.

M. Cross-module dependencies

Wallet, finance ledger, commission, hyperlocal/courier delivery, notifications, trust (getFoodSellerTrust :2373).

N. Change-impact

Changing placeOrderInstant affects money (wallet/ledger/commission), menu pricing integrity, delivery routing, and status history. Re-test the order money path + normalized item writes.