diff --git a/api/menu/menus.cfm b/api/menu/menus.cfm index cb5884f..9b72c00 100644 --- a/api/menu/menus.cfm +++ b/api/menu/menus.cfm @@ -242,7 +242,7 @@ try { response["ERROR"] = "server_error"; response["MESSAGE"] = e.message; response["DETAIL"] = e.detail ?: ""; - response["TAGCONTEXT"] = e.tagContext[1].template & ":" & e.tagContext[1].line; + } writeOutput(serializeJSON(response)); diff --git a/api/setup/saveWizard.cfm b/api/setup/saveWizard.cfm index c6bee07..f40fbc4 100644 --- a/api/setup/saveWizard.cfm +++ b/api/setup/saveWizard.cfm @@ -34,6 +34,7 @@ try { businessId = structKeyExists(data, "businessId") ? val(data.businessId) : 0; userId = structKeyExists(data, "userId") ? val(data.userId) : 0; + providedMenuId = structKeyExists(data, "menuId") ? val(data.menuId) : 0; wizardData = structKeyExists(data, "data") ? data.data : {}; biz = structKeyExists(wizardData, "business") ? wizardData.business : {}; @@ -290,81 +291,87 @@ try { } } - // Create a Menu record for this business (or get existing menu with same name) - menuName = structKeyExists(wizardData, "menuName") && isSimpleValue(wizardData.menuName) && len(trim(wizardData.menuName)) - ? trim(wizardData.menuName) - : "Main Menu"; - - // Get menu time range (optional) - menuStartTime = structKeyExists(wizardData, "menuStartTime") && isSimpleValue(wizardData.menuStartTime) && len(trim(wizardData.menuStartTime)) - ? trim(wizardData.menuStartTime) - : ""; - menuEndTime = structKeyExists(wizardData, "menuEndTime") && isSimpleValue(wizardData.menuEndTime) && len(trim(wizardData.menuEndTime)) - ? trim(wizardData.menuEndTime) - : ""; - - // Convert HH:MM to HH:MM:SS if needed - if (len(menuStartTime) == 5) menuStartTime = menuStartTime & ":00"; - if (len(menuEndTime) == 5) menuEndTime = menuEndTime & ":00"; - - // Validate menu hours fall within business operating hours - if (len(menuStartTime) && len(menuEndTime)) { - qHours = queryExecute(" - SELECT MIN(HoursOpenTime) as earliestOpen, MAX(HoursClosingTime) as latestClose - FROM Hours - WHERE HoursBusinessID = :bizID - ", { bizID: businessId }, { datasource: "payfrit" }); - - if (qHours.recordCount > 0 && !isNull(qHours.earliestOpen) && !isNull(qHours.latestClose)) { - earliestOpen = timeFormat(qHours.earliestOpen, "HH:mm:ss"); - latestClose = timeFormat(qHours.latestClose, "HH:mm:ss"); - - if (menuStartTime < earliestOpen || menuEndTime > latestClose) { - throw(message="Menu hours (" & menuStartTime & " - " & menuEndTime & ") must be within business operating hours (" & earliestOpen & " - " & latestClose & ")"); - } - response.steps.append("Validated menu hours against business hours (" & earliestOpen & " - " & latestClose & ")"); - } - } - - qMenu = queryExecute(" - SELECT MenuID FROM Menus - WHERE MenuBusinessID = :bizID AND MenuName = :name AND MenuIsActive = 1 - ", { bizID: businessId, name: menuName }, { datasource: "payfrit" }); - - if (qMenu.recordCount > 0) { - menuID = qMenu.MenuID; - // Update existing menu with new time range if provided - if (len(menuStartTime) && len(menuEndTime)) { - queryExecute(" - UPDATE Menus SET MenuStartTime = :startTime, MenuEndTime = :endTime - WHERE MenuID = :menuID - ", { - menuID: menuID, - startTime: menuStartTime, - endTime: menuEndTime - }, { datasource: "payfrit" }); - response.steps.append("Updated existing menu: " & menuName & " (ID: " & menuID & ") with hours " & menuStartTime & " - " & menuEndTime); - } else { - response.steps.append("Using existing menu: " & menuName & " (ID: " & menuID & ")"); - } + // Use provided menuId (add-menu mode) or create/find menu + if (providedMenuId > 0) { + menuID = providedMenuId; + response.steps.append("Using provided menu ID: " & menuID); } else { - queryExecute(" - INSERT INTO Menus ( - MenuBusinessID, MenuName, MenuDaysActive, MenuStartTime, MenuEndTime, MenuSortOrder, MenuIsActive, MenuAddedOn - ) VALUES ( - :bizID, :name, 127, :startTime, :endTime, 0, 1, NOW() - ) - ", { - bizID: businessId, - name: menuName, - startTime: len(menuStartTime) ? menuStartTime : javaCast("null", ""), - endTime: len(menuEndTime) ? menuEndTime : javaCast("null", "") - }, { datasource: "payfrit" }); + // Create a Menu record for this business (or get existing menu with same name) + menuName = structKeyExists(wizardData, "menuName") && isSimpleValue(wizardData.menuName) && len(trim(wizardData.menuName)) + ? trim(wizardData.menuName) + : "Main Menu"; - qNewMenu = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" }); - menuID = qNewMenu.id; - timeInfo = len(menuStartTime) && len(menuEndTime) ? " (" & menuStartTime & " - " & menuEndTime & ")" : " (all day)"; - response.steps.append("Created menu: " & menuName & timeInfo & " (ID: " & menuID & ")"); + // Get menu time range (optional) + menuStartTime = structKeyExists(wizardData, "menuStartTime") && isSimpleValue(wizardData.menuStartTime) && len(trim(wizardData.menuStartTime)) + ? trim(wizardData.menuStartTime) + : ""; + menuEndTime = structKeyExists(wizardData, "menuEndTime") && isSimpleValue(wizardData.menuEndTime) && len(trim(wizardData.menuEndTime)) + ? trim(wizardData.menuEndTime) + : ""; + + // Convert HH:MM to HH:MM:SS if needed + if (len(menuStartTime) == 5) menuStartTime = menuStartTime & ":00"; + if (len(menuEndTime) == 5) menuEndTime = menuEndTime & ":00"; + + // Validate menu hours fall within business operating hours + if (len(menuStartTime) && len(menuEndTime)) { + qHours = queryExecute(" + SELECT MIN(HoursOpenTime) as earliestOpen, MAX(HoursClosingTime) as latestClose + FROM Hours + WHERE HoursBusinessID = :bizID + ", { bizID: businessId }, { datasource: "payfrit" }); + + if (qHours.recordCount > 0 && !isNull(qHours.earliestOpen) && !isNull(qHours.latestClose)) { + earliestOpen = timeFormat(qHours.earliestOpen, "HH:mm:ss"); + latestClose = timeFormat(qHours.latestClose, "HH:mm:ss"); + + if (menuStartTime < earliestOpen || menuEndTime > latestClose) { + throw(message="Menu hours (" & menuStartTime & " - " & menuEndTime & ") must be within business operating hours (" & earliestOpen & " - " & latestClose & ")"); + } + response.steps.append("Validated menu hours against business hours (" & earliestOpen & " - " & latestClose & ")"); + } + } + + qMenu = queryExecute(" + SELECT MenuID FROM Menus + WHERE MenuBusinessID = :bizID AND MenuName = :name AND MenuIsActive = 1 + ", { bizID: businessId, name: menuName }, { datasource: "payfrit" }); + + if (qMenu.recordCount > 0) { + menuID = qMenu.MenuID; + // Update existing menu with new time range if provided + if (len(menuStartTime) && len(menuEndTime)) { + queryExecute(" + UPDATE Menus SET MenuStartTime = :startTime, MenuEndTime = :endTime + WHERE MenuID = :menuID + ", { + menuID: menuID, + startTime: menuStartTime, + endTime: menuEndTime + }, { datasource: "payfrit" }); + response.steps.append("Updated existing menu: " & menuName & " (ID: " & menuID & ") with hours " & menuStartTime & " - " & menuEndTime); + } else { + response.steps.append("Using existing menu: " & menuName & " (ID: " & menuID & ")"); + } + } else { + queryExecute(" + INSERT INTO Menus ( + MenuBusinessID, MenuName, MenuDaysActive, MenuStartTime, MenuEndTime, MenuSortOrder, MenuIsActive, MenuAddedOn + ) VALUES ( + :bizID, :name, 127, :startTime, :endTime, 0, 1, NOW() + ) + ", { + bizID: businessId, + name: menuName, + startTime: len(menuStartTime) ? menuStartTime : javaCast("null", ""), + endTime: len(menuEndTime) ? menuEndTime : javaCast("null", "") + }, { datasource: "payfrit" }); + + qNewMenu = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" }); + menuID = qNewMenu.id; + timeInfo = len(menuStartTime) && len(menuEndTime) ? " (" & menuStartTime & " - " & menuEndTime & ")" : " (all day)"; + response.steps.append("Created menu: " & menuName & timeInfo & " (ID: " & menuID & ")"); + } } // Build category map diff --git a/portal/menu-builder.html b/portal/menu-builder.html index cdb465f..79411ec 100644 --- a/portal/menu-builder.html +++ b/portal/menu-builder.html @@ -3503,6 +3503,11 @@ }); const data = await response.json(); if (data.OK) { + if (data.ACTION === 'created') { + // New menu — redirect to wizard to populate it + window.location.href = `${BASE_PATH}/portal/setup-wizard.html?businessId=${this.config.businessId}&menuId=${data.MENUID}`; + return; + } this.toast(`Menu ${data.ACTION}!`, 'success'); this.closeModal(); await this.loadMenu(); diff --git a/portal/setup-wizard.html b/portal/setup-wizard.html index bc69054..5c84729 100644 --- a/portal/setup-wizard.html +++ b/portal/setup-wizard.html @@ -1048,8 +1048,13 @@ }); function initializeConfig() { - // Wizard is for creating NEW businesses - businessId starts as null - config.businessId = null; + // Parse URL parameters for add-menu mode + const params = new URLSearchParams(window.location.search); + const paramBusinessId = params.get('businessId'); + const paramMenuId = params.get('menuId'); + + config.businessId = paramBusinessId ? parseInt(paramBusinessId) : null; + config.menuId = paramMenuId ? parseInt(paramMenuId) : null; // Determine API base URL const basePath = window.location.pathname.includes('/biz.payfrit.com/') @@ -1065,8 +1070,7 @@ } config.userId = userId; - // BusinessId is optional - will be created if not provided - console.log('Wizard initialized. BusinessId:', config.businessId, 'UserId:', config.userId); + console.log('Wizard initialized. BusinessId:', config.businessId, 'MenuId:', config.menuId, 'UserId:', config.userId); } function setupUploadZone() { @@ -1250,8 +1254,12 @@ // Remove loading message and start conversation flow document.getElementById('conversation').innerHTML = ''; - // Start with business info - showBusinessInfoStep(); + // In add-menu mode, skip business info and header — go straight to categories + if (config.businessId && config.menuId) { + showCategoriesStep(); + } else { + showBusinessInfoStep(); + } } catch (error) { console.error('Analysis error:', error); @@ -2157,22 +2165,28 @@ document.getElementById('summaryModifiers').textContent = modifiers.length; document.getElementById('summaryItems').textContent = items.length; - // Set default menu hours based on business hours (earliest open, latest close) - const hoursSchedule = business.hoursSchedule || []; - if (hoursSchedule.length > 0) { - let earliestOpen = '23:59'; - let latestClose = '00:00'; - hoursSchedule.forEach(day => { - if (day.open && day.open < earliestOpen) earliestOpen = day.open; - if (day.close && day.close > latestClose) latestClose = day.close; - }); - document.getElementById('menuStartTime').value = earliestOpen; - document.getElementById('menuEndTime').value = latestClose; + // In add-menu mode, hide menu name/hours/community meal (already set during menu creation) + if (config.menuId) { + document.getElementById('menuNameInput').parentElement.style.display = 'none'; + document.getElementById('menuStartTime').closest('.summary-stat').style.display = 'none'; + } else { + // Set default menu hours based on business hours (earliest open, latest close) + const hoursSchedule = business.hoursSchedule || []; + if (hoursSchedule.length > 0) { + let earliestOpen = '23:59'; + let latestClose = '00:00'; + hoursSchedule.forEach(day => { + if (day.open && day.open < earliestOpen) earliestOpen = day.open; + if (day.close && day.close > latestClose) latestClose = day.close; + }); + document.getElementById('menuStartTime').value = earliestOpen; + document.getElementById('menuEndTime').value = latestClose; + } } addMessage('ai', `

Your menu is ready to save!

-

${business.name || 'Your Restaurant'}

+ ${config.menuId ? '' : `

${business.name || 'Your Restaurant'}

`}