Commit graph

360 commits

Author SHA1 Message Date
John Pinkyfloyd
50307efa8d Fix cart item lookup to use orderLineItemId directly
- 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>
2026-03-09 09:25:20 -07:00
John Pinkyfloyd
fc9bbd78be Only keep Quantity=0 for modifiers, not root items 2026-03-09 09:13:55 -07:00
John Pinkyfloyd
029279658d Keep default-checked items with Quantity=0 when deselected
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>
2026-03-09 09:11:15 -07:00
John Pinkyfloyd
6ffc77fcaf Revert inverted deselect logic - back to simple delete 2026-03-09 07:34:39 -07:00
John Pinkyfloyd
5e01bcd989 Add error handling to inverted group check 2026-03-08 23:10:48 -07:00
John Pinkyfloyd
503754e248 Keep deselected inverted defaults in cart with Quantity=0
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>
2026-03-08 23:05:44 -07:00
John Pinkyfloyd
f57d249fee Add ParentIsInvertedGroup to cart line items
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>
2026-03-08 23:00:49 -07:00
John Pinkyfloyd
bae4293055 Add IsInvertedGroup to cart line items API response
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>
2026-03-08 22:58:54 -07:00
John Pinkyfloyd
446addd66d Fix inverted modifier not removing from cart
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>
2026-03-08 21:24:56 -07:00
John Mizerek
588e6ef26d Add IsInvertedGroup + RemovedDefaults to task detail API
Works app can now display inverted modifier groups with "NO" prefix
for removed defaults, matching KDS behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 20:11:06 -07:00
John Mizerek
57d31c0428 Fix unescaped # in Uber Eats HTML entity unescaping
CFML was failing to compile analyzeMenuUrl.cfm because &#39; contains
a # character that Lucee interprets as variable expression start.
Escaped all 4 occurrences to &##39;.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 18:46:33 -07:00
John Mizerek
717d60d6e6 Add IsInvertedGroup support for modifier groups
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>
2026-03-08 18:14:19 -07:00
John Mizerek
49d724f9b2 Add Uber Eats menu import and fix header image upload step
- Parse JSON-LD structured menu data from saved Uber Eats pages
  (categories, items, prices, descriptions, business info)
- Show save-and-upload instructions when user pastes Uber Eats URL
- Always show header image upload step (was skipped for URL imports)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:59:40 -07:00
John Mizerek
6346ffdb02 Add markStationDone.cfm to public routes for KDS access
KDS doesn't send auth tokens, so markStationDone needs to be a public
route like listForKDS and updateStatus already are.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 11:04:34 -07:00
John Mizerek
6cdbff129f Add takeaway/pickup order support
- 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>
2026-03-08 10:45:06 -07:00
John Mizerek
b0fa48ab64 Pass WooCommerce business info (name, address, phone) to wizard
The WooCommerce fast path was returning empty business info. Now the
Playwright script extracts it from the page and the CFML passes it through.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 20:18:17 -08:00
John Mizerek
41cf2820f6 Save modifier type, maxSelections, and default-checked state from WooCommerce
- checkbox groups get MaxNumSelectionReq=0 (unlimited), radio/select get 1
- Pre-checked options (e.g. preselected condiments) saved with IsCheckedByDefault=1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:47:32 -08:00
John Mizerek
8fd0ccb8da Include imageUrl on WooCommerce items for wizard image download
The wizard checks item.imageUrl to decide whether to skip the image
upload step and download images from remote URLs instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 16:47:06 -08:00
John Mizerek
a7138ba958 Fix loginOTP case sensitivity with preserveCaseForStructKey
The beacon app sends "Phone" (uppercase) but loginOTP.cfm checked for
"phone" (lowercase). With preserveCaseForStructKey=true this fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 16:12:03 -08:00
John Mizerek
fb92748784 Add WooCommerce fast-path with Playwright modifier extraction
Detects WooCommerce sites from Playwright HTML (woocommerce, wc-add-to-cart,
tm-extra-product-options). Runs woo-modifiers.js which navigates all product
pages, extracts items with categories, and scrapes TMEPO/variation modifiers.
Falls through to Claude if extraction fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:24:22 -08:00
John Mizerek
d9262e83c0 Re-enable magic OTP on production for App Store review
The revert from the other session disabled this. 123456 must work
alongside real codes on production for Apple reviewer testing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 17:52:17 -08:00
John Pinkyfloyd
d7c9ae23ef Revert "Enable magic OTP on production for App Store review"
This reverts commit 4109e3dac4.
2026-03-06 16:39:14 -08:00
John Mizerek
b39f8bf1e8 Magic OTP: accept 123456 alongside real codes (for App Store review) 2026-03-06 16:32:39 -08:00
John Pinkyfloyd
4109e3dac4 Enable magic OTP on production for App Store review
Code 123456 will work for any phone number to facilitate
App Store review testing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-06 16:23:19 -08:00
John Mizerek
1568686ff1 Add BrandColorLight to menu API and setup wizard
- items.cfm: return BrandColorLight in menu response
- saveWizard.cfm: save BrandColorLight during business creation
- setup-wizard.html: second color picker for light brand color

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 19:24:45 -08:00
John Mizerek
3bd7585383 Add BrandColorLight for subtle card tinting in menu builder
New BrandColorLight column on Businesses table. Menu builder cards
(categories, subcategories, items) get a very subtle tint from the
light brand color. White when no color is set. Brand color picker
now has both dark and light fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 14:48:11 -08:00
John Pinkyfloyd
b9755a1e72 Add role-aware cash routing and backend improvements
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>
2026-03-04 20:04:46 -08:00
John Mizerek
a44dfd79ae Fix every-item-as-category pattern in menu import
Post-process Claude menu extraction to detect when >60% of categories
have exactly 1 item (a common misparse). Collapses pseudo-categories
into the nearest preceding real (0-item) category.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:51:09 -08:00
John Mizerek
84985d98d8 Improve Claude prompt to distinguish categories from items
Added explicit guidance that categories are broad section headings
(5-15 typical) and items are individual products (30-150 typical).
Prevents Claude from treating each menu item as its own category.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 16:45:33 -08:00
John Mizerek
983ba7c2e4 Fix image media type detection from content, not extension
Claude API rejects images when the declared media type doesn't
match the actual content. Now detects JPEG/PNG/GIF/WebP from
base64 magic bytes instead of trusting file extensions or
Content-Type headers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:33:39 -08:00
John Mizerek
496ef74c4c fix: prevent tab cancel when approved orders exist
cancel.cfm previously only blocked cancel if orders had StatusID >= 1
(submitted to kitchen). If submitOrder() failed after addOrderToTab()
succeeded, the order stayed at StatusID 0 but was linked to the tab
with ApprovalStatus='approved'. This allowed cancelling the tab free.

Now checks TabOrders directly — any approved orders with non-zero
subtotals block the cancel, regardless of kitchen submission status.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 12:56:14 -08:00
John Mizerek
c40e5c0181 Add Grubhub menu import via API
Detect Grubhub URLs and fetch menu data directly via their
REST API instead of scraping HTML. Gets anonymous auth token,
then fetches full restaurant data including categories, items,
modifiers, prices, hours, lat/lng, tax rate, and item images.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 12:20:53 -08:00
John Mizerek
2f9bb2b869 Extract lat/lng from Toast and save directly to address
Toast provides latitude/longitude in the location object. Extract
in analyzeMenuUrl.cfm and pass through to saveWizard.cfm, which
now includes lat/lng in the address INSERT. Skips the background
Nominatim geocode when coordinates are already available.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:47:32 -08:00
John Mizerek
9225a53eee Fix saveWizard.cfm Lucee 7 syntax error
Convert cfthread from tag-based to cfscript syntax. Lucee 7
no longer allows </cfscript> mid-file to switch to tag mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:41:30 -08:00
John Mizerek
2b441e166e Extract business hours from Toast schedule data
Parses upcomingSchedules from ROOT_QUERY.restaurantV2.schedule
and formats as "Mon 7:30am-6:30pm, Tue 7:30am-6:30pm" text string
that the setup wizard's parseHoursString() can consume.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:24:45 -08:00
John Mizerek
4351978c10 Fix Toast menu import for new URL format and prices array
- Add item.prices array support to first code path (was only checking
  item.price scalar, but Toast now uses prices: [4.50] array)
- Extract individual address fields (addressLine1, city, state, zip)
  from ROOT_QUERY restaurant data for saveWizard compatibility
- Update modifier extraction URL detection to match any toasttab.com
  domain (not just order.toasttab.com)
- Update slug-based URL construction to use www.toasttab.com/local/order/
  format instead of deprecated order.toasttab.com/online/ format

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:45:28 -08:00
John Mizerek
d822fcad5a feat: per-station item completion on KDS
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>
2026-03-02 19:19:25 -08:00
John Mizerek
f3a41bf01a fix: validate Stripe customer before using, handle mode mismatch
If a user has a live-mode StripeCustomerId but the API is running in
test mode (or vice versa), the PI creation fails. Now validates the
customer with Stripe first and creates a new one if invalid.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 18:06:09 -08:00
John Mizerek
5dd0884b8f feat: include SessionEnabled in menu items API response
Android app uses this to show/hide the tab icon per business.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:34:08 -08:00
John Mizerek
576c90fffd Fix DISTINCT ORDER BY error in KDS station-filtered query
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>
2026-03-02 17:30:44 -08:00
John Mizerek
a2ed13981e Fix CFML hash escape in station save default color
## in CFML strings is required for literal # characters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:49:07 -08:00
John Mizerek
f5ff9cdfeb Add station CRUD endpoints and wire into portal UI
New endpoints: save.cfm (combined add/update) and delete.cfm
(soft-delete with item unassignment). Registered in Application.cfm.

Portal station-assignment page now uses real API calls for add,
edit, and delete instead of client-side-only prompt(). Fixed key
naming mismatch (StationName/StationColor → Name/Color) so the
page works with real API data. Removed hardcoded demo fallbacks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:26:45 -08:00
John Mizerek
94b5bbbce1 KDS: per-station line item filtering with expand toggle
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>
2026-03-02 15:30:59 -08:00
John Mizerek
c65cd8242b Round balance amounts to cents before applying
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>
2026-03-02 14:32:54 -08:00
John Mizerek
c580e6ec78 Auto-apply user balance on cash and card orders
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>
2026-03-02 14:16:21 -08:00
John Mizerek
96c2ed3fc1 Fix cash payment fee: use real Payfrit platform fee, not 2.25% cash handling fee
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>
2026-03-02 12:59:22 -08:00
John Mizerek
cb7e3b7fc6 fix: include PaymentFromCreditCard in cash payment INSERT
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>
2026-03-02 12:44:53 -08:00
John Mizerek
eda8010927 Fix restaurant distance sorting to use numeric comparison
CFML compare() does string comparison, causing distances like 1.9 to
sort after 12.3. Switched to numeric < > operators.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 11:57:45 -08:00
John Mizerek
8adac1a242 Fix submitCash.cfm for legacy Payments table columns
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>
2026-03-02 11:29:40 -08:00
John Mizerek
ff24cfa79b Fix column names: Latitude/Longitude not Lat/Lng
The Addresses table uses Latitude and Longitude column names,
not Lat and Lng.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:13:47 -08:00