Default-checked items nested inside modifier groups were not being found
because the function only looked one level deep. Now it recurses through
all child items to find defaults at any depth.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add IsDeleted=0 filter to existing item search query
- Add support for OrderLineItemID parameter for direct item targeting
- Fixes duplicate items being created on quantity increment
- Fixes item deletion not working due to finding wrong/deleted records
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
For inverted display: when user deselects a default-checked item, keep it
in cart with Quantity=0 instead of deleting. Cart displays "NO X" for these.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
For inverted groups, when user deselects a default item, keep it in cart
with Quantity=0 instead of deleting. This allows cart to display "NO X".
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Child items need to know if their parent group is inverted for proper
display logic (showing "NO X" instead of listing selected items).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Required for inverted modifier display (showing "NO X" for removed defaults
instead of listing all selected items).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When deselecting a modifier (IsSelected=false), Quantity was incorrectly
set to 1 instead of 0, preventing the removal logic from working.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When enabled on a modifier group, KDS and cart only show removed
defaults (e.g., "NO Mustard") instead of listing all selected items.
Useful for groups where all options are checked by default.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- getOrCreateCart: only require ServicePointID for dine-in (OrderTypeID=1)
- get.cfm + items.cfm: return OrderTypes from Businesses table
- saveOrderTypes.cfm: new endpoint to save business order type config
- KDS: add PICKUP/DELIVERY badges on order cards
- Portal: add Order Types toggle card in settings (Dine-In always on, Takeaway toggle)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Staff cash goes to worker payout ledger, admin/manager cash deletes
pending payout and reverses withholding. Add RoleID to myBusinesses
response. Various order and webhook improvements.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each station can mark their items done independently. When all
stations are done, the order auto-promotes to Ready (status 3)
and delivery/pickup tasks are created automatically.
- New markStationDone.cfm endpoint for per-station completion
- Extract task creation into shared _createOrderTasks.cfm include
- Add line item StatusID to listForKDS.cfm response
- KDS shows per-station "Mark Station Done" button when filtered
- Done items display with strikethrough and checkmark
- Manager view retains full manual control (no station selected)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MySQL rejects ORDER BY o.SubmittedOn when SELECT DISTINCT has
DATE_FORMAT(o.SubmittedOn) AS SubmittedOn. Use the alias instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend returns all line items for every order (removes station
filter from sub-query). Frontend filters by station, showing only
relevant items by default. An expand toggle reveals other stations'
items dimmed at 35% opacity for full order context.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents sub-cent precision (e.g. $0.883125) from accumulating in
BalanceApplied and payment records. All balance math now rounds to
nearest cent first.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Balance from cash change now silently reduces the amount owed on the
next order. For cash: deducted immediately in submitCash, reduces cash
the worker needs to collect (or skips cash task entirely if fully
covered). For card: reduces the Stripe PaymentIntent amount, deducted
in webhook on successful payment. Receipt shows "Balance applied" line.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
submitCash.cfm: Calculate platform fee from subtotal * PayfritFee,
store in Orders.PlatformFee and Payments.PaymentPayfritsCut on submission.
complete.cfm: Replace bogus 2.25% cash transaction fee with the real
platform fee (customer fee + business fee = 2 × PayfritFee × subtotal).
Credit full Payfrit revenue to User 0. Record business fee in
PaymentPayfritNetworkFees.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PaymentFromCreditCard column is NOT NULL with no default value,
causing INSERT to fail silently. Set to 0 for cash payments.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Payments table still uses old prefixed names (PaymentID as PK, no UUID
column, no PaymentTip column, required PaymentReceivedByUserID). Updated
INSERT to match actual production schema.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extra </cfif> at line 243 had no matching opener. Was hidden by
Lucee's template cache until the Tomcat restart exposed it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All servers (db, dev, biz) migrated to UTC:
- MySQL default-time-zone changed from America/Los_Angeles to +00:00
- All existing datetime data converted from Pacific to UTC
- JVM timezone set to UTC on dev and biz servers
- OS timezone set to UTC on all three servers
Removed CONVERT_TZ hack from listForKDS.cfm — data is natively UTC.
Simplified toISO8601() — no dateConvert needed since data is already UTC.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MySQL is in America/Los_Angeles, not UTC. Use CONVERT_TZ to properly
convert to UTC before appending the Z suffix.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dateTimeFormat() converts to JVM local time before formatting, so
appending 'Z' was wrong. Use DATE_FORMAT in SQL instead since the DB
values are already UTC.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DB stores timestamps in UTC but the API returned them without timezone
info, causing JS to parse them as local time. Append 'Z' suffix so
new Date() correctly interprets them as UTC.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New api/tabs/ directory with 13 endpoints: open, close, cancel, get, getActive,
addOrder, increaseAuth, addMember, removeMember, getPresence, approveOrder,
rejectOrder, pendingOrders
- New api/presence/heartbeat.cfm for beacon-based user presence tracking
- New cron/expireTabs.cfm for idle tab expiry and presence cleanup
- Modified submit.cfm for tab-aware order submission (skip payment, update running total)
- Modified getOrCreateCart.cfm to auto-detect active tab and set TabID on new carts
- Modified webhook.cfm to handle tab capture events (metadata type=tab_close)
- Modified businesses/get.cfm and updateTabs.cfm with new tab config columns
- Updated portal tab settings UI with auth amounts, max members, approval toggle
- Added tab and presence endpoints to Application.cfm public allowlist
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Check for existing active (uncompleted) cash task before creating
a new one. Prevents duplicate "Pay With Cash" tasks if order status
changes are triggered multiple times.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Looks up task type by name for the business instead of hardcoding ID
- Dine-in: 'Deliver to Table'
- Takeaway: 'Order Ready for Pickup'
- Delivery: 'Deliver to Address'
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The duplicate check was preventing delivery task creation if ANY task
existed for the order (e.g., Cash or Chat tasks). Now only checks for
TaskTypeID=1 (delivery/pickup tasks) to allow proper task creation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- getActiveCart now returns existing cart for user
- Optional BusinessID parameter to filter by specific business
- Used by Android app for cart recovery when scanning at a business
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Auto-create cash task when order status transitions to 3 (Final Prep)
and has a pending cash payment (Payments.PaymentPaidInCash > 0)
- Task includes OrderID so Android can display OrderTotal
- Task title includes service point name when available
- Fix duplicate task check: was WHERE ID = ?, now WHERE OrderID = ?
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- getCart.cfm: Include TaxRate from Businesses table
- getOrCreateCart.cfm: Include TaxRate from Businesses table
- items.cfm: Include TaxRate in menu response for cart calculation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Redesign KDS with HUD-matching dark theme (pure black background)
- Header styling identical to HUD: position, font, clock format
- Status indicator moved to bottom-right corner like HUD
- Remove business ID config - now uses portal localStorage only
- Keep station toggle functionality
- Fix updateStatus.cfm: use correct column names for dev DB
(sp.Name instead of sp.ServicePointName, sp.ID instead of sp.ServicePointID)
- Use relative API URL instead of hardcoded production URL
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix menu builder dropdown showing empty names (return MenuName instead of Name)
- Add default menu selection (setDefault action, DefaultMenuID in getForBuilder)
- Fix createPaymentIntent column names for dev schema (ID, StripeAccountID, etc.)
- Fix menu-builder favicon and remove redundant business label
- Comment out Tabs/Running Checks feature for launch (HTML + JS)
- Comment out Service Point Marketing/Grants feature for launch (HTML + JS)
- Add testMarkPaid.cfm for testing orders without Stripe webhooks
- Task API updates for worker payout ledger integration
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>