Appearance
Transactions (Orders)
Overview
Transactions represent all orders placed through any channel. This is where you view, manage, and process orders.
Key Purpose: View and manage all orders from all channels.
Purpose
This page lets you view, filter, and manage all orders across every sales channel, including reviewing order details, resending receipts, exporting data, and tracking payment and fulfillment status.
Key Concepts
- Transaction: A complete order record stored in MongoDB, containing items, pricing, customer data, and an order channel identifier (Kiosk, POS, Online Ordering, Table Qr Ordering, Uber Eats, Takeaway, Shopify).
- Order Status: A single
statusfield tracks the combined payment and fulfillment state of an order (Unpaid, Awaiting Capture, Awaiting Invoice, Awaiting Payment, Pending, Complete, Queued, In Progress, Ready, Cancelled). There is no separate payment-status field; all status filtering uses this one enum. - Idempotency Key: A unique key per transaction that prevents duplicate order creation; the system checks for an existing transaction with the same key before processing a new one.
- Stats Aggregation: The stats endpoint aggregates completed transactions for a date range and optional location, returning completed transaction count, total item quantity, total revenue, and currency.
- Spreadsheet Export: Transactions can be exported to Excel spreadsheets in paginated chunks of 500 records, including columns for order number, date, location, customer, status, total, items, dining option, type, device, receipt number, and channel.
Actions
View Transaction Details
Open any transaction to see the full order breakdown including items, modifiers, pricing, customer information, payment method, and status history.
Resend Receipt
Re-send a receipt for a completed transaction via the ReceiptService; only transactions with a "Complete" status are eligible for receipt resend.
Export Transactions
Download transaction data as a spreadsheet filtered by date range, location, and other criteria; the export processes records in chunks of 500 for efficiency.
Filter and Search Orders
Filter orders by date range, status (via the All / Completed / Unpaid / Stuck tabs), channel, dining option, order type, device, and location, or search by order number, customer name, email, or phone.
View Transaction Statistics
Access aggregated stats showing completed transaction count, total quantity sold, and total revenue for a selected date range and location.
Retry POS Sync
For orders that failed to sync to the POS (shown under the "Stuck" tab), re-dispatch the POS sync job so the order is sent again.
Delete Test Transaction
Delete a transaction that was created in test mode. Only test-mode transactions can be deleted; deleting a live transaction is blocked.
Location
- Backoffice Route:
/transactions - Backend Controller:
app/Http/Controllers/Api/BackOffice/TransactionController.php - Vue Component:
src/views/transactions/Transactions.vue
Order Fields
Order Number
| Property | Value |
|---|---|
| Field ID | order_number |
| Label | Order # |
| Type | String |
| Auto-generated | Yes |
Description: Unique identifier for the order.
Format: Sequential number or custom format (e.g., #1234, ORD-2024-001)
Order Status
| Property | Value |
|---|---|
| Field ID | status |
| Label | Status |
| Type | Select |
| Options | Unpaid, Awaiting Capture, Awaiting Invoice, Awaiting Payment, Pending, Complete, Queued, In Progress, Ready, Cancelled |
Description: Combined payment and fulfillment status of the order (single status field; there is no separate payment-status field).
Statuses:
- Unpaid: Order placed but not yet paid
- Awaiting Capture: Payment authorized, awaiting capture
- Awaiting Invoice: Awaiting an invoice payment
- Awaiting Payment: Awaiting payment
- Pending: Order is in but no payment is made/requested (e.g. third-party orders)
- Complete: Order paid and fulfilled
- Queued: Order queued for processing
- In Progress: Order is being processed/prepared
- Ready: Order ready for pickup/delivery
- Cancelled: Order cancelled
Order Channel
| Property | Value |
|---|---|
| Field ID | order_channel |
| Label | Order Channel |
| Type | String |
Description: Where the order originated.
Channels (from App\Enums\ChannelOptions):
Kiosk- Self-service kioskPOS- Point of saleOnline Ordering- Online ordering websiteTable Qr Ordering- QR table orderingUber Eats- Uber Eats integrationTakeaway- TakeawayShopify- Shopify integration
Note: the Channel filter dropdown in the Transactions list currently only offers "All", "Online Ordering", and "Kiosk", even though more channel values can appear on records.
Dining Option
| Property | Value |
|---|---|
| Field ID | dining_option |
| Label | Type |
| Type | Select |
| Options | Delivery, For Here, Pickup, Takeout |
Description: How the customer will receive the order. (Note: "Dine In" is deprecated and replaced by "For Here".)
Order Date/Time
| Property | Value |
|---|---|
| Field ID | created_at |
| Label | Order Time |
| Type | DateTime |
Description: When the order was placed.
Scheduled Time
| Property | Value |
|---|---|
| Field ID | scheduled_time |
| Label | Scheduled For |
| Type | DateTime |
Description: When the order should be ready (pickup) or delivered.
Customer
| Property | Value |
|---|---|
| Field ID | customer |
| Label | Customer |
| Type | Object |
Description: Customer information.
Fields:
name- Customer nameemail- Email addressphone- Phone numbercustomer_id- Account ID (if logged in)
Delivery Address
| Property | Value |
|---|---|
| Field ID | delivery_address |
| Label | Delivery Address |
| Type | Object |
| Depends On | dining_option = delivery |
Description: Address for delivery orders.
Items
| Property | Value |
|---|---|
| Field ID | items |
| Label | Order Items |
| Type | Array |
Description: Items in the order.
Item Structure:
json
{
"item_id": "item-123",
"name": "Cheeseburger",
"quantity": 2,
"unit_price": 8.95,
"modifiers": [
{ "name": "Large", "price": 2.00 },
{ "name": "Extra Cheese", "price": 1.50 }
],
"notes": "No pickles",
"line_total": 24.90
}Subtotal
| Property | Value |
|---|---|
| Field ID | subtotal |
| Label | Subtotal |
| Type | Currency |
Description: Total of all items before fees and discounts.
Delivery Fee
| Property | Value |
|---|---|
| Field ID | delivery_fee |
| Label | Delivery Fee |
| Type | Currency |
Description: Delivery fee (for delivery orders).
Discount
| Property | Value |
|---|---|
| Field ID | discount |
| Label | Discount |
| Type | Currency |
Description: Discount applied (from offers/promo codes).
Tip
| Property | Value |
|---|---|
| Field ID | tip |
| Label | Tip |
| Type | Currency |
Description: Tip amount (if tips enabled).
Tax
| Property | Value |
|---|---|
| Field ID | tax |
| Label | Tax |
| Type | Currency |
Description: Total tax amount.
Total
| Property | Value |
|---|---|
| Field ID | total |
| Label | Total |
| Type | Currency |
Description: Final order total.
Calculation: Subtotal + Delivery Fee - Discount + Tip + Tax
Payment Method
| Property | Value |
|---|---|
| Field ID | payment_method |
| Label | Payment |
| Type | String |
Description: How the order was paid.
Methods:
card- Credit/debit cardideal- iDEAL (NL)bancontact- Bancontact (BE)cash- Cash paymentapple_pay- Apple Paygoogle_pay- Google Pay
Notes
| Property | Value |
|---|---|
| Field ID | notes |
| Label | Order Notes |
| Type | Text |
Description: Special instructions from customer.
Order Actions
The back-office Transactions feature is read-and-manage only. There are no manual status-progression actions (no Confirm / Mark as Preparing / Mark as Ready / Complete buttons) — order status changes are driven by payment events and the ordering/KDS flow, not by the back office. The TransactionController exposes only: show, dataTable, stats, export, resendReceipt, retrySync, deleteTestTransaction.
Resend Receipt
Re-send a receipt for a transaction (only when its status is "Complete").
Retry POS Sync
Re-dispatch the POS sync job for an order that failed to sync (shown under the "Stuck" tab).
Delete Test Transaction
Delete a transaction that was created in test mode. Live transactions cannot be deleted.
Refund Order (not currently available)
A refund flow exists in the UI but is not wired up: the refund button in OrderDetail.vue is commented out and the store's refundOrder action is a simulated mock with no backend endpoint. Refunds are not processed from the back office today; handle refunds through your payment provider (e.g. the Stripe dashboard).
Business Logic
Order Status
An order's lifecycle is reflected by the single status field. Typical paid orders move toward Complete; unpaid/awaiting-payment orders sit in the Unpaid / Awaiting Payment / Awaiting Capture / Awaiting Invoice / Pending states; fulfillment progresses through Queued → In Progress → Ready; and orders can end in Cancelled. These transitions are driven by payment events and the ordering/KDS flow rather than by manual back-office actions.
Filtering & Search
Filter Options
- Date range
- Status (via the All / Completed / Unpaid / Stuck tabs)
- Channel
- Dining option
- Order type
- Device
- Location
Search
- Order number
- Customer name
- Customer email
- Customer phone
Customer Impact
Order Confirmation
Customer receives:
- Confirmation email
- Order number
- Estimated time
- Order details
Order Updates
Customer notified when:
- Order is placed/paid
- Order ready
- Order cancelled
Relations
Depends On
- Locations: Orders belong to locations
- Menu Items: Items in orders
- Customers: Order attribution
- Payments: Payment processing
Affects
- Inventory: Stock decremented
- Loyalty: Points earned
- Reports: Sales data
- KDS: Orders displayed
Related Features
Business Rules
- Only transactions with a status of "Complete" can have their receipt resent; attempting to resend for an incomplete transaction returns a 400 error with "Transaction is incomplete."
- There are no separate payment-status and order-status fields — a single
statusenum captures both the payment and fulfillment state. - Refunds are not processed from the back office: the refund UI is disabled (button commented out, store action is a mock) and there is no refund endpoint on the
TransactionController. - There are no manual status-progression actions in the back office (no Confirm / Mark as Preparing / Mark as Ready / Complete). Status changes are driven by payment events and the ordering/KDS flow.
- Only test-mode transactions can be deleted; deleting a live transaction is blocked with "Only test mode transactions can be deleted".
- Transaction stats only count orders with status "Complete" and apply date range filtering using MongoDB date queries with timezone-aware parsing via the location's timezone.
- The spreadsheet export aborts with a 400 error if no transactions match the given filters, rather than producing an empty file.
- Tip validation enforces mutual exclusivity: a transaction request cannot specify both a tip percentage and a tip amount; providing both throws an InvalidArgumentException.
- When a customer places an order and no existing customer record matches their email or phone, a new customer and customer-vendor record are created automatically, and any applicable loyalty sign-up bonus is applied.
FAQs
"Why can I not resend a receipt for an order?" Receipts can only be resent for transactions with a "Complete" status; if the order is still pending or was cancelled, the resend option is blocked.
"How does the export handle large volumes of transactions?" The export processes records in chunks of 500, writing each batch sequentially to the spreadsheet until all matching records are retrieved, preventing memory issues.
"What timezone are transaction dates displayed in?" Transaction dates are stored in UTC (MongoDB UTCDateTime) but are displayed and filtered using the location's configured timezone.
"Can a transaction belong to multiple locations?" No, each transaction is tied to exactly one location via its location_id; filtering by location returns only that location's transactions.
"How are duplicate orders prevented?" Each transaction carries an idempotency key; before creating a new transaction, the system checks for an existing record with the same key and returns the existing order if found.
"Which sales channels can I filter transactions by, and what are they called?" Transactions carry an order channel; the recognised values are Online Ordering, Kiosk, POS, Table Qr Ordering, Uber Eats, Takeaway, and Shopify. Note the Channel filter dropdown currently only offers "All", "Online Ordering", and "Kiosk".
"What do the status tabs at the top of the Transactions list mean?" Four tabs: All, Completed, Unpaid, and Stuck. Completed shows orders with status Complete, Unpaid shows orders with status Unpaid, and Stuck shows orders whose POS sync failed.
"What does the 'Stuck' tab show and how do I fix a stuck order?" The Stuck tab lists transactions that failed to sync to your POS. Each stuck row has a retry icon; clicking it (Retry Sync) clears the failed flag and re-dispatches the POS sync job so the order is sent again.
"Why can't I resend a receipt for some orders?" Resend Receipt only works for transactions whose status is Complete. For any other status you get "Transaction is incomplete", so pending, unpaid, or cancelled orders can't have a receipt resent.
"What columns are included when I export transactions?" The Excel export includes Order No, Date, Location, Customer, Payment Status, Total, Items, Dining Option, Type, Device, Receipt No, and Channel.
"My export downloaded nothing / gave an error — why?" If no transactions match your current filters, the export stops with a "No transactions found" error instead of an empty file. Adjust your date range, location, or filters so at least one order matches, then export again.
"What do the four summary cards at the top mean?" Completed Transactions (count of fully paid orders), Total Items (quantity sold), Total Collected (amount collected before fees), and Total Pending (money still awaiting invoice or payment). The Total Pending card only appears if your account accepts invoice payments.
"Why doesn't 'Total Pending' change when I change the date range?" The first three figures are scoped to the selected date range, but Total Pending is intentionally not date-scoped — an invoice raised months ago is still outstanding today. It's still limited to the selected location.
"Can I filter transactions to a single location?" Yes. If your account has more than one location, a Location filter appears; each transaction belongs to exactly one location. The export and stats respect the same filter.
"Which transaction date and timezone are used for filtering?" Date filtering uses the order date, evaluated in your location's configured timezone. Dates are stored in UTC but parsed against the location timezone, so "today" reflects your local trading day.
"Can I delete a transaction?" Only test-mode transactions can be deleted; deleting a real (live) transaction is blocked with "Only test mode transactions can be deleted".
Troubleshooting
Problem: Order stuck in an unpaid/pending status
Causes:
- Payment not completed
- Payment failed
- System error
Solutions:
- Check the payment in your payment provider (e.g. Stripe)
- Contact the customer to retry payment
- Note: the back office has no "manually confirm" action — status is updated by the payment flow, not manually
Problem: Order stuck (failed POS sync)
Causes:
- POS offline or unreachable
- Transient sync error
- POS integration misconfiguration
Solutions:
- Open the "Stuck" tab, which lists orders whose POS sync failed
- Click the retry icon (Retry Sync) on the row to re-dispatch the POS sync job
- If it keeps failing, check the POS connection and integration settings
Problem: Order not appearing on KDS
Causes:
- KDS not connected
- Channel filter on KDS
- Order status not yet eligible for KDS
Solutions:
- Check KDS connection
- Review KDS channel settings
- Confirm the order has reached a status that routes it to the KDS
Problem: Customer didn't receive an order email
Causes:
- Wrong email address
- Email in spam
- Email service issue
Solutions:
- Verify the email address on the order
- Ask the customer to check spam
- For receipts on completed orders, use Resend Receipt from the order detail (there is no separate "resend confirmation" action)
Problem: Need to refund an order
Note: Refunds are not processed from the back office today — the refund UI is disabled and there is no refund endpoint.
Solutions:
- Process the refund directly in your payment provider (e.g. the Stripe dashboard)
- For cash payments, handle the refund at the point of sale
- Contact your payment provider if the refund fails
Examples
Online Order (Delivery)
json
{
"order_number": "1234",
"status": "Complete",
"order_channel": "Online Ordering",
"dining_option": "Delivery",
"created_at": "2024-01-15T12:30:00Z",
"scheduled_time": "2024-01-15T13:15:00Z",
"customer": {
"name": "Jan de Vries",
"email": "jan@example.com",
"phone": "+31612345678"
},
"delivery_address": {
"address_line_1": "Kalverstraat 123",
"city": "Amsterdam",
"postal_code": "1012 AB"
},
"items": [
{
"name": "Margherita Pizza",
"quantity": 1,
"unit_price": 12.50,
"modifiers": [
{ "name": "Large", "price": 3.00 }
],
"line_total": 15.50
},
{
"name": "Garlic Bread",
"quantity": 1,
"unit_price": 4.50,
"line_total": 4.50
}
],
"subtotal": 20.00,
"delivery_fee": 3.50,
"discount": 0,
"tip": 2.00,
"tax": 1.89,
"total": 27.39,
"payment_method": "ideal"
}Kiosk Order (For Here)
json
{
"order_number": "42",
"status": "In Progress",
"order_channel": "Kiosk",
"dining_option": "For Here",
"created_at": "2024-01-15T12:45:00Z",
"items": [
{
"name": "Cheeseburger",
"quantity": 2,
"unit_price": 8.95,
"modifiers": [
{ "name": "Extra Cheese", "price": 1.50 }
],
"line_total": 20.90
},
{
"name": "French Fries",
"quantity": 2,
"unit_price": 3.50,
"line_total": 7.00
},
{
"name": "Cola",
"quantity": 2,
"unit_price": 2.50,
"line_total": 5.00
}
],
"subtotal": 32.90,
"tip": 5.00,
"tax": 2.81,
"total": 40.71,
"payment_method": "card"
}Order Summary View
Order #1234 - Jan de Vries
Status: Complete
Channel: Online Ordering
Type: Delivery
Items:
1x Margherita Pizza (Large) €15.50
1x Garlic Bread €4.50
─────────────
Subtotal €20.00
Delivery Fee €3.50
Tip €2.00
Tax €1.89
─────────────
Total €27.39
Payment: iDEAL ✓ Paid
Delivery: Kalverstraat 123, Amsterdam
Scheduled: 13:15