POS-Dependent Metrics¶
Metrics that require POS (Point of Sale) data correlated with the video session. All POS metrics require pos_correlation.status == "confirmed".
POS v2 category dependency
Category-specific financial metrics use metadata.items[*].category from the correlated POS session. Category-specific timing metrics use metadata.order_events[] timestamps when available; if those operational event items are uncategorized, metrics inherits categories from categorized final items by normalized item name. This is read-time mapping only — POS v2 rows are not mutated. When POS Sessions v2 item categories are backfilled or corrected, rerun metrics enrichment so category-dependent fields are recalculated and new shift versions are written where fingerprints change.
POS Item Offset Calculation¶
POS items have UTC timestamps. To relate them to the video timeline, we calculate:
flowchart TD
A["POS Item Timestamp<br/>UTC"] --> B{Parse UTC}
B --> C[item_dt]
D["Video Start UTC<br/>from shift_meta"] --> E["offset = item_dt - video_start"]
C --> E
E --> F{"offset >= 0?"}
F -->|Yes| G["Valid offset<br/>in seconds"]
F -->|No| H["null<br/>item predates video"] Items with negative offsets (before video start) are excluded — they cannot belong to the current video.
M-2: Time to First POS Order¶
Field: time_to_first_pos_order_seconds · Type: int | null
Seconds from start-session annotation to the first POS item timestamp.
Gate: start-session + confirmed POS + video_start_utc
Formula: max(0, first_pos_item_offset - start_session.time)
M-7: Food Delivery from First POS Item¶
Field: food_delivery_from_first_pos_item_seconds · Type: int | null
Seconds from the first POS item (any category) to food-arrived.
Gate: confirmed POS + video_start_utc + start-session + food-arrived
M-9: Drink Delivery from First POS Item¶
Field: drink_delivery_from_first_pos_item_seconds · Type: int | null
Seconds from the first POS item (any category) to drinks-arrived.
M-10: Drink Delivery from First Drink Order¶
Field: drink_delivery_from_first_drink_order_seconds · Type: int | null
Seconds from the first POS item with category == "drink" to drinks-arrived.
For POS Sessions v2, this uses metadata.order_events[] as the preferred timestamp source. If an order-event item lacks category, the metrics mapper inherits the category from metadata.items[] using the shared normalized item-name contract.
Formula: max(0, drinks_arrived.time - first_drink_offset)
Tip
This metric is used by SLA Detection to flag drink delays (threshold: 480s / 8 min).
M-11: Food Delivery from First Main Dish Order¶
Field: food_delivery_from_first_main_dish_order_seconds · Type: int | null
Seconds from the first POS item with category == "main_plate" to food-arrived.
For POS Sessions v2, this uses metadata.order_events[] as the preferred timestamp source. If an order-event item lacks category, the metrics mapper inherits the category from metadata.items[] using the shared normalized item-name contract.
Tip
This metric is used by SLA Detection to flag food delays (threshold: 1200s / 20 min).
M-15: Drink Item Count¶
Field: drink_item_count · Type: int · Default: 0
Count of POS items where category == "drink". Only requires confirmed POS (no video_start_utc or start-session needed).
M-16: Main Dish Item Count¶
Field: main_dish_item_count · Type: int · Default: 0
Count of POS items where category == "main_plate".
M-17: Dessert Item Count¶
Field: dessert_item_count · Type: int · Default: 0
Count of POS items where category == "dessert".
M-18: Ticket Subtotal¶
Field: pos_ticket_subtotal · Type: float | null
Total ticket value from pos_data.totals.subtotal. Rounded to 2 decimals.
M-19: Ticket Average Per Person¶
Field: pos_ticket_avg · Type: float | null
pos_ticket_subtotal / people_count. Returns null if people_count is missing or zero.
M-20: Drink Ticket Total¶
Field: pos_drink_ticket_total · Type: float | null
Sum of price for all POS items with category == "drink".
M-21: Dessert Ticket Total¶
Field: pos_dessert_ticket_total · Type: float | null
Sum of price for all POS items with category == "dessert".
M-22: Server Name (Open)¶
Field: pos_server_name_open · Type: str | null
Employee who opened the POS session. Excludes "root" (system user).
M-23: Server Name (Close)¶
Field: pos_server_name_close · Type: str | null
Employee who closed the POS session. Excludes "root".
M-24: Top Seller¶
Field: pos_top_seller · Type: str | null
Employee with the most items sold in the session. Groups by employee_id when available (resolves to employee_name or str(employee_id)). Falls back to grouping by employee_name when no item has employee_id (e.g., Queops POS). No hardcoded employee maps.
Changed in version 2.3.1
Added fallback to group by employee_name when employee_id is absent, enabling M-24 for Queops-style POS systems.