StorePageCarouselItem uses imgUrl, but MenuPageItem uses imageUrl.
This gives ~540 item images instead of 26.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
listToArray treats delimiter as individual chars, not a string.
Rewritten to use position-based find() traversal for proper
multi-character delimiter splitting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract items from MenuPageItemList (171 items) instead of StorePageCarouselItem (54)
- Categories already mapped to items via MenuPageItemList sections
- Cross-reference images from carousel entries by item name
- No need for Claude category assignment - data already structured
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract menu data directly from embedded JSON in DoorDash HTML:
- Categories from MenuBookCategory entries
- Items with names, descriptions, prices, and image URLs from StorePageCarouselItem
- Business info from page title and StoreHeaderAddress
- Uses Claude to assign items to categories
- Upgrades image URLs to 600px for better quality
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update render.js on dev server to scroll page before capturing images
- Increase Playwright wait from 4s to 5s and timeout from 90s to 120s
- Upsize DoorDash CDN thumbnails from 150px to 600px when downloading
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude sometimes returns category or modifiers as objects instead
of strings. Added isSimpleValue checks to prevent cast errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Claude response was being truncated mid-JSON for larger menus,
causing parse errors. The Lazy Daisy menu needed >8192 tokens.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The PDF upload goes to analyzeMenuImages.cfm (not analyzeMenuUrl.cfm).
Added control character cleaning, smart quote replacement, and Jackson
fallback parser with error handling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lucee's deserializeJSON fails on certain Claude outputs and the error
bypasses inner cftry/cfcatch. Parse via Jackson from file instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add smart quote/dash replacement for PDF-sourced text
- Add Jackson fallback parser for when Lucee's deserializeJSON fails
- Strengthen prompt to request properly escaped JSON
- Clean control characters more selectively
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lucee's deserializeJSON chokes on control characters in description
fields that JSON.stringify escapes but Lucee can't parse.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
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>
CFML was failing to compile analyzeMenuUrl.cfm because ' 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>
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>
- 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>
Cash orders have no card processing fee. Now checks PaymentPaidInCash
to determine payment type and skips the Stripe fee calculation + display
for cash orders.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Previously station-filtered view skipped the acknowledge step and went
straight to "Mark Station Done" for new orders. Now new orders show
"Start Preparing" first, then "Mark Station Done" once preparing.
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>
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>
- 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>
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>
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>
Changed from cover/fixed-height to contain/aspect-ratio 3:1 so the
full 1200x400 header image is visible without cropping.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
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>