Commit graph

298 commits

Author SHA1 Message Date
John Mizerek
f09777eaa5 Add get_beacon_config endpoint — single call for all beacon config
Combines allocate_business_namespace + allocate_servicepoint_minor into one
endpoint that returns UUID, Major, Minor, MeasuredPower, AdvInterval, TxPower,
ServicePointName, and BusinessName. No more hardcoded defaults on the client.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:20:16 -08:00
John Mizerek
95dc4c49fc Strip address from business name when Toast embeds it in the name field
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:12:58 -08:00
John Mizerek
e403e49487 Fix Toast OO_STATE: restaurant from ROOT_QUERY, prices from prices[]
- Restaurant info is in ROOT_QUERY.restaurantV2(...) keys, not
  Restaurant:* top-level keys (Apollo cache format)
- Prices are in item.prices array [4.50], not item.price scalar
- Added null checks for imageUrls (can be null, not missing)
- Fallback to title tag for business name

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:11:44 -08:00
John Mizerek
a0d86d6e87 Add Toast __OO_STATE__ fast-path for URL-fetched menu pages
Instead of sending 450KB of HTML to Claude (which truncates to 100K
and only extracts ~60 items), parse the structured __OO_STATE__ data
directly on the server. This captures all menus, groups, items, prices,
and images from Toast pages - 169 items for Jus Family Cafe vs 60 before.

Falls back to Claude analysis if __OO_STATE__ parsing fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:08:07 -08:00
John Mizerek
ced4082993 Fix JSON parsing when Claude returns text preamble before menu JSON
The Claude API sometimes returns explanatory text before the JSON
response even when instructed to return only JSON. Added extraction
logic to find the first { character and strip any leading text.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:30:21 -08:00
John Mizerek
9acf4aa511 Add server-side h2/h3 hierarchy detection for subcategory discovery
- Parse HTML heading structure to detect h2 parents with h3 subcategories
- Append detected hierarchy to Claude prompt as explicit hint
- Post-process Claude response to enforce hierarchy even if Claude returns flat

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:36:36 -08:00
John Mizerek
495b03c76d Add subcategory detection to wizard URL analyzer and display
- analyzeMenuUrl.cfm: Detect subcategories from Toast subgroups and
  Claude API responses, preserve hierarchy with parentCategoryName
- setup-wizard.html: Display subcategories indented under parents
  throughout wizard flow (categories step, items review, summary, preview)
- menu-builder.html: Show subcategories nested in outline modal view

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:08:59 -08:00
John Mizerek
3ccc82c9f2 Add subcategory support (2 levels deep)
- saveCategory.cfm: Accept ParentCategoryID, enforce max 2-level nesting
- items.cfm: Include ParentCategoryID on virtual category rows for Android
- getForBuilder.cfm: Return ParentCategoryID in builder API response
- saveFromBuilder.cfm: Persist ParentCategoryID on save, track JS-to-DB id mapping
- saveWizard.cfm: Two-pass category creation (parents first, then subcategories)
- menu-builder.html: Parent category dropdown in properties, visual nesting in canvas,
  add subcategory button, renderItemCard() extracted for reuse

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:29:40 -08:00
John Mizerek
e02e124610 Increase max_tokens to 16384 for menu URL analysis
Large menus (20+ categories) were getting truncated JSON responses
at 8192 tokens, causing parse failures.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-28 16:17:13 -08:00
John Mizerek
698d31f62c Fix cash debit: attribute to business owner for admin/manager roles
Staff cash_debit goes to the worker (they keep the cash).
Admin/Manager cash_debit goes to the business owner (restaurant has it).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 12:10:59 -08:00
John Mizerek
d1910a7d34 Add staff role system: Staff keeps cash, Manager/Admin collect for restaurant
- Create tt_StaffRoles lookup table (Staff, Manager, Admin)
- Add RoleID column to Employees table (default: Staff)
- Wire portal role dropdown to addTeamMember API
- Return RoleName in team list and RoleID to Android
- Skip worker payout ledger and cash_debit for Manager/Admin roles
  on cash task completion (they collect on behalf of the restaurant)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 11:19:22 -08:00
John Mizerek
476d7f9df1 Add HasChildren flag and filter child businesses from list
Return HasChildren boolean so Android can route food court parents
directly to business selector. Exclude child businesses from top-level
restaurant list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:10:51 -08:00
John Mizerek
ec3a15013b Add per-tab ApprovalMode override for member order approval
- open.cfm: accept optional ApprovalMode param (0=auto, 1=manual, NULL=business default)
- addOrder.cfm: check tab ApprovalMode first, fall back to business TabApprovalRequired
- getActive.cfm: return resolved ApprovalRequired in tab response

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:44:06 -08:00
John Mizerek
48fa6e4482 Fix missing UserID in submit.cfm order query
Tab-aware submit references qOrder.UserID but the SELECT didn't include it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 22:53:17 -08:00
John Mizerek
9ed200d7ea Fix open tab: accept AuthAmountCents from Android client
Android sends cents, server was reading dollars only, falling back to default $150.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 21:43:52 -08:00
John Mizerek
4c0479db5c Add Open Tabs feature: tab APIs, presence tracking, shared tabs, cron, portal settings
- 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>
2026-02-24 20:56:07 -08:00
John Mizerek
802d48f049 Fix tt_TaskTypes column names for dev database
Changed tt_TaskTypeID to ID in task type CRUD operations to match
the migrated dev database schema.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-23 14:13:19 -08:00
John Mizerek
d628f7eb50 Fix column name in listAllTypes: tt_TaskTypeID -> ID
The tt_TaskTypes table uses 'ID' not 'tt_TaskTypeID'.
This was causing "Failed to load services" in the portal.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-23 13:24:46 -08:00
John Mizerek
2c655a5963 Add business timezone support for menu scheduling
- Add getTimeInZone() and getDayInZone() helpers in Application.cfm
- Update items.cfm and getForBuilder.cfm to use business timezone
- Menu availability now correctly respects each business's timezone

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-20 12:09:36 -08:00
John Mizerek
9e5770f131 Add toISO8601() helper for UTC date formatting 2026-02-20 11:56:31 -08:00
John Mizerek
ea34f302ac Require TaxRate and PayfritFee to be configured - no fallbacks
Both values MUST be set per business. If not configured, the menu
API will return an error instead of silently using defaults.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 11:31:31 -08:00
John Mizerek
ed001fd0b0 Remove hardcoded 5% fee fallback, require Businesses.PayfritFee
If PayfritFee is not configured for a business, the payment intent
creation now errors instead of silently using 5%. This ensures fees
are always explicitly set per business.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 11:16:41 -08:00
John Mizerek
c17f624787 Fix Stripe webhook and add dev webhook secret
- Add SubmittedOn = COALESCE(SubmittedOn, NOW()) to webhook for KDS timer
- Add test mode webhook secret for dev.payfrit.com
- Keep live mode webhook secret for biz.payfrit.com

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 10:08:35 -08:00
John Mizerek
6a8ded9857 Add getPaymentConfig.cfm to public allowlist
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-18 20:25:30 -08:00
John Mizerek
bbfbbf1963 Update PaymentIntent amount if cart changed on retry
Moved fee calculation before PI check so we can compare amounts.
If existing PaymentIntent has different amount than current cart,
update it via Stripe API before returning.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 19:06:01 -08:00
John Mizerek
d0f0f86176 Reuse existing PaymentIntent instead of blocking on retry
When user abandons checkout and retries, retrieve the existing
PaymentIntent from Stripe. If still usable (requires_payment_method,
requires_confirmation, requires_action), return its client_secret.
If already succeeded, block with clear error. If terminal/canceled,
clear and create new one.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 19:01:17 -08:00
John Mizerek
29327c4a13 Add getPaymentConfig endpoint for Payment Sheet saved cards
Returns customer ID, ephemeral key, and publishable key needed for
Stripe Payment Sheet to display saved payment methods on iOS/Android.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 18:00:56 -08:00
John Mizerek
07c2f24d67 Add Stripe Customer creation to save payment methods
- Get user info (StripeCustomerId, email, name) when creating PaymentIntent
- Create Stripe Customer if user doesn't have one
- Add customer and setup_future_usage=off_session to PaymentIntent
- Cards are automatically saved after successful payment

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 17:56:13 -08:00
John Mizerek
9e2c3a8478 Fix CFML syntax error in webhook.cfm breaking all Stripe webhooks
The ## escape sequence was missing the closing # for variable interpolation,
causing 500 errors on all webhook requests. Fixed ##metaTipID# -> ###metaTipID#
and similar patterns.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 16:48:25 -08:00
John Mizerek
160144d40d Remove ExpectedAmountCents column reference (migration pending)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 14:31:30 -08:00
John Mizerek
695df9fc8e Fix createChat.cfm column name: TaskID → ID
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 11:22:47 -08:00
John Mizerek
fc310c35cf Fix cancel task to not cancel order, standardize OTP messages
- Cancel Task now leaves order untouched (customer can pay another way)
- Standardized SMS text to "Your Payfrit code is:" across all endpoints

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 11:11:37 -08:00
John Mizerek
43afe9ae8c Prevent duplicate cash tasks for same order
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>
2026-02-17 09:41:58 -08:00
John Mizerek
7f4af8b910 Add CancelOrder option for cash tasks
When worker passes CancelOrder: true to complete.cfm:
- Skips all cash validation and financial processing
- Sets order status to 6 (cancelled)
- Completes the task normally
- Returns OrderCancelled: true in response

For when customer changes their mind about paying with cash.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 09:39:35 -08:00
John Mizerek
eb92042de5 Use business PayfritFee instead of hardcoded 5% in task order totals
Fixed complete.cfm, getDetails.cfm, listMine.cfm, listPending.cfm to pull
PayfritFee from Businesses table with 0.05 fallback if not set.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 09:20:18 -08:00
John Mizerek
0a08b1da3e Fix beacon sharding: use ServicePoints.BeaconMinor not BeaconHardware
Matches the lookup.cfm approach:
- UUID from BeaconShards
- Major from Businesses.BeaconMajor
- Minor from ServicePoints.BeaconMinor

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 20:10:04 -08:00
John Mizerek
957f494ba8 Get beacon info from BeaconHardware table
Looks up actual ShardUUID, Major, Minor from BeaconHardware
instead of deriving from Business/ServicePoint tables.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 20:06:38 -08:00
John Mizerek
dd7a4dda4a Return beacon sharding info (UUID, Major, Minor) for task completion
- UUID from BeaconShards via Business.BeaconShardID
- Major from Business.BeaconMajor
- Minor = ServicePointID

Replaces old beacon lookup via ServicePoints.BeaconID

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 20:02:19 -08:00
John Mizerek
06c4b99a66 Include ServicePointID when creating delivery tasks
Needed for beacon dwell auto-completion to work.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 19:32:37 -08:00
John Mizerek
2019b9ff43 Use proper task types for delivery/pickup tasks
- 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>
2026-02-16 19:29:47 -08:00
John Mizerek
7caf4d60b0 Fix delivery task creation when other tasks exist for order
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>
2026-02-16 19:24:59 -08:00
John Mizerek
aeeba3c6e5 Update about screen content
- Improved feature descriptions
- Updated main description
- Added "coming soon" note for delivery

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 18:36:15 -08:00
John Mizerek
01cb11dad3 fix: Cash task completion now triggers kitchen flow
When a cash task is completed, the order now goes to status 1 (submitted)
instead of directly to status 5 (complete). This allows the normal kitchen
flow to proceed: kitchen sees order → prepares → marks status 3 → delivery
task is auto-created.

Also sets PaymentStatus, PaymentCompletedOn, and SubmittedOn to match the
Stripe webhook behavior for paid orders.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 18:22:14 -08:00
John Mizerek
703a283d32 Enable cart recovery API with optional business filter
- 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>
2026-02-16 12:53:57 -08:00
John Mizerek
084e815c6c Stripe and beacon API updates
- createPaymentIntent: improved error handling
- webhook: updated payment processing
- resolve_business: minor fix

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 12:53:05 -08:00
John Pinkyfloyd
ec0f2dea6a Add Latitude/Longitude to businesses list response
iOS app needs lat/lng for client-side distance calculations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 12:41:00 -08:00
John Pinkyfloyd
df903a9c75 Allow completing orphaned cash tasks without payment processing
Skip cash validation and processing for tasks with no linked order.
These are likely test tasks that were created before order linking.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 12:26:24 -08:00
John Pinkyfloyd
dc2d66b50b Add OrderTotalCents to task details for cash collection
Returns order total in cents as integer for Flutter Works app
to display exact cash amount due for cash payment tasks.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 12:01:46 -08:00
John Mizerek
c5614f0f50 Disable worker-rates-customer rating prompt temporarily
Rating UI not ready in Works app yet. Will re-enable when implemented.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-16 11:58:20 -08:00
John Pinkyfloyd
eebf231aad Fix column names in submitCash.cfm (PaymentAddedOn, TipAmount) 2026-02-16 11:50:57 -08:00