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, plus the two deferred-payment figures (Total Pending and Collected at till) and the uncollected count. See Summary cards.
- Deferred payment: A payment method that collects nothing online — Cash on delivery and Invoice. The order reaches the POS open and unpaid, and the money is taken in person or billed afterwards. See Cash on Delivery settlement.
- Spreadsheet Export: Transactions can be exported to Excel spreadsheets in paginated chunks of 500 records, including columns for order number, date, location, customer, payment 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 / Paid / Unpaid / Stuck POS / Uncollected 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. The response also carries the two deferred-payment figures, Total Pending and Collected at till. Both are location-scoped but deliberately not date-scoped: an invoice raised months ago is still outstanding today, and cash collected last week is still cash the merchant took. See Summary cards.
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.
Mark as Collected
Record that a deferred order's money was collected in person. Available from the order's action menu on any deferred-payment order — Cash on delivery or Invoice — that has not been settled yet. It is meant for Cash on delivery; see Cash on Delivery settlement.
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.
persons is the party size on a per-person (MPLUS bestelbeperking) line; the key is absent on the stored snapshot line for every other item and is emitted as null in the order payload. On such a line quantity holds article units (party size × how many of the dish), because that is what the money and any re-order are computed from. The order-detail line-items table shows the dish count instead: it divides quantity by persons only when persons > 1 and quantity divides evenly, otherwise it shows quantity unchanged. A "For N people" note appears under the item name whenever persons is set (including persons: 1, where no division happens). So a line displayed as 2x Gourmet — For 6 people has quantity: 12, persons: 6 in the payload. Display only — no stored value changes, and the per-unit price shown is still per article unit.
Item Structure:
json
{
"item_id": "item-123",
"name": "Cheeseburger",
"quantity": 2,
"persons": null,
"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 (the stored value is set by the payment provider / POS, so exact casing varies by source — e.g. Card, iDEAL, Bancontact, Cash):
card- Credit/debit cardideal- iDEAL (NL)bancontact- Bancontact (BE)cash- Cash paymentCashOnDelivery- Cash on delivery, a deferred method: nothing was collected onlineInvoice- Pay by invoice (Mplus locations), also deferred
Note: there are no distinct
apple_pay/google_paypayment_methodvalues — the code never sets them. Wallet payments made through Stripe are recorded under the underlying card method, not as separate values.
How a Cash on delivery order is labelled in the Payment Status column:
A prepaid order that reaches Complete reads Paid. A Cash on delivery order reaches Complete at placement, with nothing captured, so it reads Pay in person instead — the order is real and confirmed, but the money is still in the customer's pocket. Once the cash is confirmed collected it reads Paid at till, not plain "Paid", because that money arrived at the merchant's own till and so never appears in an Upvendo payout or commission line. The stored payment method never changes; only the settlement does.
Invoice orders sit on Awaiting Invoice until the customer pays, and that status is what the column shows.
See Cash on Delivery settlement.
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 fulfilment-progression actions (no Confirm / Mark as Preparing / Mark as Ready / Complete buttons) — fulfilment status changes are driven by payment events and the ordering/KDS flow, not by the back office. Two manual actions can change what is known about payment: Verify payment status (for orders paid through Upvendo) and Mark as collected (for deferred orders collected in person, which in practice means Cash on delivery).
Resend Receipt
Re-send a receipt for a transaction (only when its status is "Complete").
Verify Payment Status
Re-check an order's true payment status at the payment provider and settle it if the money was actually taken.
- Where: the order-detail 3-dots overflow menu (the same menu as Resend receipt).
- When it is shown: only when the order status is Unpaid, Awaiting Payment, Awaiting Capture or Pending, and the payment method is not Cash.
- Endpoint:
POST /back-office/transactions/{id}/verify-payment-status(permissionview-transactions). - Outcomes:
settled,settlement_queued,already_settledornot_paid. Each raises its own toast; the first three reload the order.
This is the one back-office action that can move an order out of Unpaid.
Retry POS Sync
Re-dispatch the POS sync job for an order that failed to sync (shown under the "Stuck" tab).
Mark as Collected
Record that the money for a deferred order was collected in person.
- Where: the order-detail 3-dots overflow menu (the same menu as Resend receipt).
- When it is shown: on any deferred-payment order that has not been settled yet — Cash on delivery or Invoice. It is intended for Cash on delivery.
- Amount: always the full order total. The action takes no amount input.
- Outcome on a Cash on delivery order: the Payment Status becomes Paid at till and the amount moves from Total Pending to Collected at till. A second attempt is refused. The person who confirmed it is recorded on the Transaction Lifecycle timeline.
- Outcome on an Invoice order: almost nothing visible. The order stays on Awaiting Invoice and stays in Total Pending, and it does not join Collected at till, which counts Cash on delivery only. It simply records a confirmation on the timeline. Collect an invoice through Invoice Collection instead — that is the path that actually closes it.
Unlike Verify payment status, this moves no money and contacts no payment provider — it records something that happened at the merchant's own counter. See Cash on Delivery settlement.
Delete Test Transaction
Delete a transaction that was created in test mode. Live transactions cannot be deleted.
Transaction Lifecycle Timeline
Order detail renders a Transaction Lifecycle card whenever the order's lifecycle_logs array is non-empty. It is a read-only audit trail — nothing on it changes the order. The only interactive control is the Load More (N) button that appears when the timeline is collapsed.
- One entry per lifecycle log, drawn as a Vuetify timeline. The dot colour comes from
log.level:success,info,warningorerror; anything else falls back toinfo. - Event label is the
transactions.lifecycle.events.<event>translation. The template also writes|| log.label, but that branch is unreachable: on a missing key the translation helper returns the key path itself, which is truthy. An event with noenentry therefore renders as the literal stringtransactions.lifecycle.events.<event>. Only theenfile has to carry the key — a locale that is missing it falls back to English. - Elapsed delta from the first entry is shown next to each timestamp (
+12s,+1m 4s,+1h 3m). It is blank for the first entry and for any non-positive or invalid delta. - Metadata chips: a tonal chip per shown metadata key. Two filters run first: (1) keys with no translation under
transactions.lifecycle.metadata.<key>are dropped entirely, and (2) a givenkey=valuepair is shown only the first time it appears in the timeline, so unchanging context (e.g.Provider: hendrickxon every Kassanet step) appears once and later entries show only what actually changed. The chip label is the translated key name (Provider,Order number,Idempotency key, …), not the raw key. Values:nullandundefinedare skipped; objects and arrays are JSON-encoded and truncated to 60 characters with an ellipsis. The de-duplication is computed over the currently visible entries, so pressing Load More re-evaluates it across the full timeline. - Long timelines collapse: with more than 8 entries only the 6 most recent render, behind a Load More (N) control.
- On mobile the timestamp moves inline underneath the event label.
- Backend cap: only the most recent 200 lifecycle entries are stored per transaction.
Timestamps render in the venue's timezone, taken from the order's
location_timezone(the timezone on the order's location snapshot). Every time carries an explicit timezone label, so a support agent and the merchant read the same clock time off the same order — e.g.Jul 17, 20:40:36 CEST. The label's form follows the viewer's locale (an en-US viewer seesGMT+2and a 12-hour clock for the same instant), but the underlying wall-clock time is always the venue's. If an order has nolocation_timezone(older orders with no location-snapshot timezone), the time falls back to the viewer's local timezone — still labelled — so the two cases are distinguishable on screen. The year is deliberately dropped from the format.
Refund Order (not currently available)
A RefundDialog exists in the shared OrderDetailView.vue, but it is not wired up: no refund button is ever rendered (the dialog's showRefundDialog flag is never set to true, so it is unreachable), and the store's refundOrder action is a simulated mock (a setTimeout that returns a fake REF_<timestamp> id, no Axios call, 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
Item counts: dishes vs article units
The Item column in the transactions list and its Excel export count dishes: Transaction::getQuantity() divides a per-person line by its party size and passes every other line through untouched. The Total Items stats card is a separate aggregation (sumTransactionQuantity) and still sums article units, so it can exceed the sum of the Item column when per-person lines are present.
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 / Paid / Unpaid / Stuck POS / Uncollected tabs)
- Channel
- Dining option
- Order type
- Device
- Location
Search
- Order number
- Customer name
- Customer email
- Customer phone
Summary cards
The cards above the list are scoped to the selected date range and location, with two exceptions noted below.
| Card | What it is |
|---|---|
| Completed transactions | How many orders completed. Cash on delivery orders are counted — they were really placed and really made. |
| Total items | Quantity sold, before adjustments. |
| Total collected | Money that arrived through Upvendo. Deferred orders (Cash on delivery, Invoice) are deliberately excluded: that money never passed through Upvendo, and this is the figure fees and payouts reconcile against. |
| Total Pending | Money still owed — orders awaiting invoice or payment, plus Cash on delivery orders whose cash has not been confirmed collected. |
| Collected at till | Cash on delivery your staff took at your own till. |
Total Pending and Collected at till are not limited by the date range — an invoice raised months ago is still outstanding today, and cash taken last week is still cash you took. Both do respect the location filter.
These two cards are shown only when they have something to say: when the figure is non-zero, or when the matching method is switched on for the locations in scope. So a merchant who has just enabled Cash on delivery sees the card before the first such order arrives, and one who never offers it is not shown a permanent €0.00. A non-zero figure always wins, so switching a method off with money still outstanding never hides that money.
Confirming a payment moves an order from Total Pending to Collected at till rather than removing it from both. The two amounts are not expected to net out exactly: Total Pending carries each order at its order total, while Collected at till reports what was actually taken at the till. Where they differ — a discount given at the counter, a short payment, a keying error — that gap is the over/short, which is the number cash handling exists to surface. Only an automatic reading (Mplus or Lightspeed K-Series) can produce such a gap; a manual Mark as collected always records the full order total.
Cash on Delivery settlement
A Cash on delivery order is placed with no payment at all: it goes to the kitchen and to the POS like any other order, and the customer hands over the money in person. Upvendo therefore has to be told separately that the cash arrived.
How an order gets settled
- Automatically, on Mplus and Lightspeed K-Series locations. Upvendo reads settlement back from the POS roughly every fifteen minutes, so an order paid at the till clears on its own. On Lightspeed, Upvendo looks up the order's sale in Lightspeed and records what the till took; only orders from the last two days are checked, and tax-exclusive (US / Canada) Lightspeed locations are not read automatically. On Mplus, a partial payment does not settle the order — the amount taken is recorded and the order stays outstanding, which it is. Automatic reading starts from the moment it is first switched on for a merchant, so Cash on delivery orders placed before that were never going to clear by themselves; settle those by hand.
- Manually, everywhere else. Open the order and use Mark as collected. This is the only route on Kassanet (Hendrickx / Vanhoutte) locations, and it is also the correction path on Mplus when the till settled in a way the POS did not attribute to the order. A manual confirmation records the full order total — there is no field for entering a different figure, so a manual mark cannot express a short payment.
The action is offered only on a deferred-payment order that is not settled yet, and it refuses a second attempt. Settlement is recorded once, so an automatic reading landing at the same moment cannot overwrite a manual confirmation — and because a manual mark is somebody's word about money rather than an observation, the order's timeline records who made it.
Settling an order changes its Payment Status from Pay in person to Paid at till, moves its amount from Total Pending to Collected at till, and clears the not-paid marker on the kitchen display.
If a Cash on delivery order is voided at the till on an Mplus location, Upvendo waits for the void to still stand on a later reading before cancelling its own copy of the order, and records the POS as the reason on the timeline. A void that turns out to be the cashier re-ringing the order is abandoned instead, and a payment that arrives after the void wins over it — the order settles rather than cancelling.
Uncollected
The Uncollected tab lists Cash on delivery orders nobody came to pay for. An order qualifies once it is more than four hours past the time it was due and still has no confirmed payment; cancelled orders are excluded. Four hours is fixed — it is not a per-location setting.
The same definition drives the tab, the count shown under Total Pending, and the badge on the row, so the three always agree.
Uncollected orders are a subset of Total Pending, not a separate pot of money — they are shown as a note under that card rather than as a card of their own. This is surfaced where the merchant is already looking; nothing about an uncollected order sends an alert or an email.
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: no refund button is rendered (the
RefundDialoginOrderDetailView.vueis unreachable), the store'srefundOrderaction is a mock, and there is no refund endpoint on theTransactionController. - There are no manual fulfilment-progression actions in the back office (no Confirm / Mark as Preparing / Mark as Ready / Complete). Fulfilment changes are driven by payment events and the ordering/KDS flow. The exceptions on the payment side are Verify payment status, which can settle an order that was actually paid through Upvendo, and Mark as collected, which records money collected in person on a deferred order. Mark as collected is offered on any unsettled deferred order, Invoice included, but only a Cash on delivery order changes its Payment Status and moves between Total Pending and Collected at till as a result.
- A Cash on delivery order is Complete from the moment it is placed, with nothing collected. It is excluded from Total Collected and sits in Total Pending until its payment is confirmed, at which point it counts towards Collected at till. Confirming a payment never changes the order's status.
- Cash on delivery settlement is recorded once: whichever confirmation lands first wins, and a later one cannot overwrite it.
- An order counts as uncollected when it is a Cash on delivery order more than four hours past its due time with no confirmed payment and not cancelled. Four hours is fixed, not a per-location setting, and the same definition drives the tab, the count and the row badge.
- Only test-mode transactions can be deleted; deleting a live transaction is blocked with a 403 error, "Only test mode transactions can be deleted".
- Transaction stats only count orders with status "Complete" and apply date-range filtering on the
order_datefield, with timezone-aware parsing via the request'stimezoneparameter (falling back to the app default 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?" Five tabs: All, Paid, Unpaid, Stuck POS and Uncollected. The Paid tab shows orders with status Complete, Unpaid shows orders with status Unpaid, Stuck POS shows orders whose POS sync failed, and Uncollected shows Cash on delivery orders nobody came to pay for. Uncollected is not a status — those orders are Complete and stay that way.
"What does the 'Uncollected' tab show?" Cash on delivery orders that are more than four hours past when they were due and still have no confirmed payment. Cancelled orders are excluded. If the customer did turn up and paid, use Mark as collected on the order and it leaves the tab. Uncollected orders are also counted in a note under the Total Pending card, and each row carries an UNCOLLECTED badge.
"What does the 'Stuck POS' tab show and how do I fix a stuck order?" The Stuck POS 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. Exception on Lightspeed K-Series: an order the POS voided or permanently rejected cannot be re-sent — Retry answers "This order was cancelled or rejected by the POS and cannot be re-sent. Enter it on the POS by hand or refund the customer." See the Lightspeed onboarding guide.
"The order reached my till but the ticket didn't print — can I send it a second time?" Not from the back office. The only way to send an order to the POS again is Retry POS Sync, and that red retry icon appears only on orders whose POS sync failed (the ones on the Stuck POS tab). An order the till already received has no retry icon, and the order detail has no resend-to-POS or reprint action — its menu only ever offers Resend receipt (the customer's receipt, not a kitchen ticket), Verify payment status, Mark as collected and Delete test transaction, each where it applies. If the order is on the till but did not print, check the printer and the till's own print queue rather than sending the order 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 summary cards at the top mean?" Three are always there: Completed transactions (how many orders completed), Total items (quantity sold) and Total collected (money that arrived through Upvendo) — all scoped to your date range and location. Up to two more appear when they have something to say: Total Pending (money still owed) and Collected at till (Cash on delivery your staff took at your own till). Those two are not limited by your date range, though they do respect the location filter. See Summary cards for the full breakdown.
"Why doesn't Total collected include my Cash on delivery orders?" Because that money never passed through Upvendo — it went straight from the customer into your till. Total collected is the figure your fees and payouts reconcile against, so including cash you handled yourself would make it wrong. Cash on delivery money is tracked separately: outstanding in Total Pending, confirmed in Collected at till.
"Why don't Total Pending and Collected at till add up to the same money?" They are measuring two different things on purpose. Total Pending carries each order at its order total — what you are owed. Collected at till reports what was actually taken. If a cashier gave a discount, took a short payment or keyed the wrong amount, the gap between the two is exactly that difference. This only arises on Mplus and Lightspeed K-Series locations, where the figure comes from the till itself; marking an order collected by hand always records the full order total.
"One of my summary cards disappeared." Total Pending and Collected at till only show when the figure is non-zero or the matching payment method is switched on for the locations in scope. If you turned the method off and the figure is zero, the card goes away. A non-zero figure always keeps its card, so money you are still owed is never hidden.
"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 reached the POS but its ticket did not print
Causes:
- The printer attached to the till is offline, out of paper or jammed
- The till received the order but did not print it
Solutions:
- Confirm the order is not on the Stuck POS tab. If it is, its sync to the till did not complete — use Retry POS Sync there
- If it is not stuck, the back office cannot send it again: Retry POS Sync is only offered on failed orders, and there is no reprint action in the order detail
- Check the printer and the till itself for the missing ticket
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