From 1210249f54d2c2175060155d9f6e64f5c6eb5eaf Mon Sep 17 00:00:00 2001 From: John Mizerek Date: Fri, 30 Jan 2026 15:39:12 -0800 Subject: [PATCH] Normalize database column and table names across entire codebase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update all SQL queries, query result references, and ColdFusion code to match the renamed database schema. Tables use plural CamelCase, PKs are all `ID`, column prefixes stripped (e.g. BusinessName→Name, UserFirstName→FirstName). Key changes: - Strip table-name prefixes from all column references (Businesses, Users, Addresses, Hours, Menus, Categories, Items, Stations, Orders, OrderLineItems, Tasks, TaskCategories, TaskRatings, QuickTaskTemplates, ScheduledTaskDefinitions, ChatMessages, Beacons, ServicePoints, Employees, VisitorTrackings, ApiPerfLogs, tt_States, tt_Days, tt_AddressTypes, tt_OrderTypes, tt_TaskTypes) - Rename PK references from {TableName}ID to ID in all queries - Rewrite 7 admin beacon files to use ServicePoints.BeaconID instead of dropped lt_Beacon_Businesses_ServicePoints link table - Rewrite beacon assignment files (list, save, delete) for new schema - Fix FK references incorrectly changed to ID (OrderLineItems.OrderID, Categories.MenuID, Tasks.CategoryID, ServicePoints.BeaconID) - Update Addresses: AddressLat→Latitude, AddressLng→Longitude - Update Users: UserPassword→Password, UserIsEmailVerified→IsEmailVerified, UserIsActive→IsActive, UserBalance→Balance, etc. Co-Authored-By: Claude Opus 4.5 --- Application.cfm | 8 +- _process.cfm | 14 +- admin/beacon_servicepoint.cfm | 16 +- admin/beacons.cfm | 22 +- admin/email_users.cfm | 14 +- admin/god_mode.cfm | 34 +- admin/servicepoints.cfm | 42 +- api/Application.cfm | 10 +- api/addresses/add.cfm | 24 +- api/addresses/delete.cfm | 34 +- api/addresses/list.cfm | 44 +- api/addresses/setDefault.cfm | 14 +- api/addresses/states.cfm | 18 +- api/admin/addCategoryIsActiveColumn.cfm | 8 +- api/admin/addCategoryScheduleFields.cfm | 32 +- api/admin/addDrinkModifiers.cfm | 40 +- api/admin/addItemCategoryColumn.cfm | 12 +- api/admin/addLatLng.cfm | 6 +- api/admin/addServiceCategoryColumn.cfm | 6 +- api/admin/addTaskSourceColumns.cfm | 26 +- api/admin/beaconStatus.cfm | 48 +- api/admin/checkBigDeans.cfm | 12 +- api/admin/checkUser.cfm | 16 +- api/admin/cleanupBeacons.cfm | 46 +- api/admin/cleanupCategories.cfm | 58 +- api/admin/cleanupDuplicateEmployees.cfm | 20 +- api/admin/cleanupForLazyDaisy.cfm | 70 +- api/admin/cleanupOrphanItem.cfm | 26 +- api/admin/clearCarts.cfm | 6 +- api/admin/clearLocalCoffee.cfm | 18 +- api/admin/closeAllChats.cfm | 4 +- api/admin/copyDrinksToBigDeans.cfm | 30 +- api/admin/createBeacons.cfm | 53 +- api/admin/createChatMessagesTable.cfm | 10 +- api/admin/createMenusTable.cfm | 38 +- api/admin/createParentBusiness.cfm | 20 +- api/admin/debugBigDeansDeactivated.cfm | 20 +- api/admin/debugBigDeansLinks.cfm | 34 +- api/admin/debugBigDeansMenu.cfm | 28 +- api/admin/debugBigDeansTemplates.cfm | 34 +- api/admin/debugBigDeansTemplates2.cfm | 56 +- api/admin/debugBigDeansTemplates3.cfm | 50 +- api/admin/debugBusinesses.cfm | 20 +- api/admin/debugChatMessages.cfm | 4 +- api/admin/debugDrinkStructure.cfm | 42 +- api/admin/debugEmployees.cfm | 50 +- api/admin/debugTasks.cfm | 42 +- api/admin/debugTasksRaw.cfm | 14 +- api/admin/debugTemplateLinks.cfm | 28 +- api/admin/debugUserByPhone.cfm | 34 +- api/admin/deleteBusiness.cfm | 8 +- api/admin/deleteOrphanModifiers.cfm | 32 +- api/admin/deleteOrphans.cfm | 18 +- api/admin/eliminateCategories.cfm | 146 +- api/admin/fixBigDeansCategories.cfm | 20 +- api/admin/fixBigDeansModifiers.cfm | 22 +- api/admin/fixBrandColors.cfm | 16 +- api/admin/fixShakeFlavors.cfm | 60 +- api/admin/geocode.cfm | 70 +- api/admin/linkChildBusiness.cfm | 2 +- api/admin/migrateModifierTemplates.cfm | 58 +- api/admin/migrateToCategories.cfm | 42 +- api/admin/perf-dashboard.cfm | 299 ++++ api/admin/perf.cfm | 8 +- api/admin/quickTasks/addTypeIdColumn.cfm | 8 +- api/admin/quickTasks/cleanup.cfm | 2 +- api/admin/quickTasks/create.cfm | 18 +- api/admin/quickTasks/debug.cfm | 20 +- api/admin/quickTasks/delete.cfm | 6 +- api/admin/quickTasks/list.cfm | 34 +- api/admin/quickTasks/purge.cfm | 2 +- api/admin/quickTasks/save.cfm | 26 +- api/admin/quickTasks/setup.cfm | 28 +- api/admin/randomizePrices.cfm | 58 +- api/admin/scheduledTasks/delete.cfm | 4 +- api/admin/scheduledTasks/list.cfm | 38 +- api/admin/scheduledTasks/run.cfm | 14 +- api/admin/scheduledTasks/runDue.cfm | 34 +- api/admin/scheduledTasks/save.cfm | 40 +- api/admin/scheduledTasks/setup.cfm | 38 +- api/admin/scheduledTasks/toggle.cfm | 20 +- api/admin/setEmployeeActive.cfm | 26 +- api/admin/setHeaderExtension.cfm | 4 +- api/admin/setupBeaconTables.cfm | 48 +- api/admin/setupBigDeansInfo.cfm | 58 +- api/admin/setupBigDeansStations.cfm | 18 +- api/admin/setupLazyDaisyBeacons.cfm | 57 +- api/admin/setupModifierTemplates.cfm | 22 +- api/admin/setupStations.cfm | 24 +- api/admin/switchBeacons.cfm | 53 +- api/admin/testTaskInsert.cfm | 8 +- api/admin/testTaskType.cfm | 10 +- api/admin/updateBeaconMapping.cfm | 77 +- api/admin/updateBigDeans.cfm | 90 +- api/assignments/delete.cfm | 50 +- api/assignments/list.cfm | 33 +- api/assignments/save.cfm | 79 +- api/auth/completeProfile.cfm | 22 +- api/auth/login.cfm | 24 +- api/auth/loginOTP.cfm | 16 +- api/auth/profile.cfm | 48 +- api/auth/sendOTP.cfm | 42 +- api/auth/validateToken.cfm | 15 +- api/auth/verifyLoginOTP.cfm | 28 +- api/auth/verifyOTP.cfm | 30 +- api/beacons/delete.cfm | 26 +- api/beacons/get.cfm | 33 +- api/beacons/getBusinessFromBeacon.cfm | 82 +- api/beacons/list.cfm | 37 +- api/beacons/list_all.cfm | 12 +- api/beacons/lookup.cfm | 60 +- api/beacons/reassign_all.cfm | 4 +- api/beacons/save.cfm | 128 +- api/businesses/get.cfm | 114 +- api/businesses/getChildren.cfm | 12 +- api/businesses/list.cfm | 32 +- api/businesses/saveBrandColor.cfm | 3 +- api/businesses/setHiring.cfm | 2 +- api/businesses/update.cfm | 35 +- api/businesses/updateHours.cfm | 5 +- api/chat/closeChat.cfm | 4 +- api/chat/getActiveChat.cfm | 18 +- api/chat/getMessages.cfm | 26 +- api/chat/sendMessage.cfm | 6 +- api/config/environment.cfm | 136 -- api/config/stripe.cfm | 4 + api/debug/checkTask.cfm | 30 +- api/debug/checkToken.cfm | 10 +- api/dev/seedData.cfm | 40 +- api/dev/timeTravel.cfm | 16 +- api/import/crimson_menu.cfm | 102 +- api/menu/clearAllData.cfm | 4 +- api/menu/clearBusinessData.cfm | 14 +- api/menu/debug.cfm | 32 +- api/menu/getForBuilder.cfm | 329 ++--- api/menu/items.cfm | 484 +++--- api/menu/listCategories.cfm | 48 +- api/menu/menus.cfm | 106 +- api/menu/saveCategory.cfm | 82 +- api/menu/saveFromBuilder.cfm | 101 +- api/menu/updateStations.cfm | 8 +- api/menu/uploadHeader.cfm | 10 +- api/orders/abandonOrder.cfm | 8 +- api/orders/checkStatusUpdate.cfm | 23 +- api/orders/debugLineItems.cfm | 40 +- api/orders/getActiveCart.cfm | 50 +- api/orders/getCart.cfm | 132 +- api/orders/getDetail.cfm | 163 ++- api/orders/getOrCreateCart.cfm | 212 +-- api/orders/getPendingForUser.cfm | 50 +- api/orders/history.cfm | 96 +- api/orders/listForKDS.cfm | 234 ++- api/orders/setLineItem.cfm | 248 ++-- api/orders/setOrderType.cfm | 148 +- api/orders/submit.cfm | 62 +- api/orders/updateStatus.cfm | 34 +- api/portal/addTeamMember.cfm | 14 +- api/portal/getSettings.cfm | 64 +- api/portal/myBusinesses.cfm | 17 +- api/portal/reassign_employees.cfm | 4 +- api/portal/searchUser.cfm | 26 +- api/portal/stats.cfm | 76 +- api/portal/team.cfm | 38 +- api/portal/updateSettings.cfm | 132 +- api/ratings/createAdminRating.cfm | 18 +- api/ratings/listForAdmin.cfm | 42 +- api/ratings/setup.cfm | 40 +- api/ratings/submit.cfm | 64 +- api/servicepoints/delete.cfm | 10 +- api/servicepoints/get.cfm | 28 +- api/servicepoints/list.cfm | 34 +- api/servicepoints/reassign_all.cfm | 4 +- api/servicepoints/save.cfm | 72 +- api/setup/checkDuplicate.cfm | 38 +- api/setup/importBusiness.cfm | 58 +- api/setup/reimportBigDeans.cfm | 24 +- api/setup/saveWizard.cfm | 92 +- api/stations/list.cfm | 16 +- api/stripe/createPaymentIntent.cfm | 33 +- api/stripe/onboard.cfm | 12 +- api/stripe/status.cfm | 14 +- api/stripe/webhook.cfm | 146 +- api/tasks/accept.cfm | 12 +- api/tasks/callServer.cfm | 42 +- api/tasks/complete.cfm | 101 +- api/tasks/completeChat.cfm | 8 +- api/tasks/create.cfm | 28 +- api/tasks/createChat.cfm | 66 +- api/tasks/deleteCategory.cfm | 12 +- api/tasks/deleteType.cfm | 6 +- api/tasks/expireStaleChats.cfm | 16 +- api/tasks/getDetails.cfm | 152 +- api/tasks/listAllTypes.cfm | 16 +- api/tasks/listCategories.cfm | 18 +- api/tasks/listMine.cfm | 94 +- api/tasks/listPending.cfm | 74 +- api/tasks/listTypes.cfm | 14 +- api/tasks/reorderTypes.cfm | 4 +- api/tasks/saveCategory.cfm | 12 +- api/tasks/saveType.cfm | 14 +- api/tasks/seedCategories.cfm | 28 +- api/tasks/setup.cfm | 22 +- api/users/search.cfm | 32 +- api/workers/createAccount.cfm | 94 ++ api/workers/earlyUnlock.cfm | 85 ++ api/workers/ledger.cfm | 72 + api/workers/myBusinesses.cfm | 30 +- api/workers/onboardingLink.cfm | 77 + api/workers/tierStatus.cfm | 72 + confirm.cfm | 14 +- confirm_email.cfm | 32 +- confirm_mobile.cfm | 34 +- cron/expireStaleChats.cfm | 16 +- favicon.svg | 6 + hud/hud.js | 34 +- includes/track_visitors.cfm | 24 +- index.cfm | 1292 ++++++++--------- kds/kds.js | 60 +- library/cfc/businessMaster.cfc | 2 +- modules/get_children_of_item_id.cfm | 8 +- ...get_children_of_item_id_browsemenu_new.cfm | 22 +- modules/get_children_of_item_id_clone.cfm | 8 +- modules/get_children_of_item_id_clone_do.cfm | 54 +- modules/get_children_of_item_id_with_add.cfm | 30 +- modules/get_delivery_fee.cfm | 8 +- portal/portal.js | 128 +- receipt/Application.cfm | 2 + receipt/index.cfm | 341 +++++ register.cfm | 96 +- show_order.cfm | 78 +- test_date_search.cfm | 10 +- test_expand_checkbox3.cfm | 2 +- test_infinite original.cfm | 56 +- test_infinite.cfm | 60 +- yelpforexes.com/Application.cfm | 6 +- .../Application.cfm.2020-07-10.bup.cfm | 28 +- yelpforexes.com/UserWasReviewed.cfm | 4 +- yelpforexes.com/_process.cfm | 14 +- yelpforexes.com/confirm_email.cfm | 30 +- yelpforexes.com/index.cfm | 247 ++-- 240 files changed, 6644 insertions(+), 5542 deletions(-) create mode 100644 api/admin/perf-dashboard.cfm create mode 100644 api/workers/createAccount.cfm create mode 100644 api/workers/earlyUnlock.cfm create mode 100644 api/workers/ledger.cfm create mode 100644 api/workers/onboardingLink.cfm create mode 100644 api/workers/tierStatus.cfm create mode 100644 favicon.svg create mode 100644 receipt/Application.cfm create mode 100644 receipt/index.cfm diff --git a/Application.cfm b/Application.cfm index bc4d830..d61ff73 100644 --- a/Application.cfm +++ b/Application.cfm @@ -24,9 +24,9 @@ - SELECT UserFirstName, UserBalance, UserImageExtension + SELECT FirstName, Balance, ImageExtension FROM Users - WHERE UserID = #request.UserID# + WHERE ID = #request.UserID# @@ -320,8 +320,8 @@ -
- Hi, #check_user.UserFirstName#
#dollarformat(check_user.UserBalance)#Payfrit User

+
+ Hi, #check_user.FirstName#
#dollarformat(check_user.Balance)#Payfrit User

diff --git a/_process.cfm b/_process.cfm index be55822..8e556ae 100644 --- a/_process.cfm +++ b/_process.cfm @@ -116,13 +116,13 @@ - SELECT A.CartID, A.AddedOn, A.Quantity, A.SpecialRemark, B.BusinessName, B.UserID, C.ItemName, A.Price, D.UserFirstName, D.LaerFirstName, D.Balance + SELECT A.CartID, A.AddedOn, A.Quantity, A.SpecialRemark, B.Name, B.UserID, C.Name, A.Price, D.FirstName, D.LaerFirstName, D.Balance FROM dbo.Business_CartMaster A, dbo.BusinessMaster B, dbo.Business_ItemMaster C, Users D WHERE A.UserID = D.UserID AND A.ItemID = C.ItemID AND - B.BusinessID = C.BusinessID + B.ID = C.BusinessID AND C.BusinessID = #form.bizid# AND @@ -170,11 +170,11 @@ - SELECT TOP 1 O.OrderID, M.UserID as person_to_pay_for_orderID, U.Balance + SELECT TOP 1 O.ID, M.UserID as person_to_pay_for_orderID, U.Balance FROM dbo.Business_OrderMaster O, dbo.BusinessMaster M, Users U WHERE O.BusinessID = M.BusinessID AND - M.UserID = U.UserID + M.UserID = U.ID ORDER BY O.AddedOn DESC @@ -185,7 +185,7 @@ ) VALUES ( - #get_last_inserted.OrderID#, + #get_last_inserted.ID#, #get_queued_food.CartID# ) @@ -268,7 +268,7 @@ SELECT balance FROM Users - WHERE UserID = 104 + WHERE ID = 104 @@ -346,7 +346,7 @@ SELECT balance FROM Users - WHERE UserID = 104 + WHERE ID = 104 diff --git a/admin/beacon_servicepoint.cfm b/admin/beacon_servicepoint.cfm index ab2a3f6..28242c3 100644 --- a/admin/beacon_servicepoint.cfm +++ b/admin/beacon_servicepoint.cfm @@ -164,8 +164,8 @@ async function refreshAssignments(){ const tr = document.createElement("tr"); tr.innerHTML = ` ${a.lt_Beacon_Businesses_ServicePointID} - ${escapeHtml((a.BeaconName || "") + " (ID " + a.BeaconID + ")")} - ${escapeHtml((a.ServicePointName || "") + " (ID " + a.ServicePointID + ")")} + ${escapeHtml((a.Name || "") + " (ID " + a.BeaconID + ")")} + ${escapeHtml((a.Name || "") + " (ID " + a.ServicePointID + ")")} ${escapeHtml(a.lt_Beacon_Businesses_ServicePointNotes || "")} ${escapeHtml(a.CreatedAt || "")} `; @@ -183,12 +183,12 @@ async function refreshBeacons(assignedBeaconIDs, keepSelectedBeaconID){ setSelectPlaceholder(sel, "-- Select Beacon --"); (out.BEACONS || []).forEach(b => { - const isAssigned = assignedBeaconIDs.has(String(b.BeaconID)); + const isAssigned = assignedBeaconIDs.has(String(b.ID)); if (HIDE_ASSIGNED_BEACONS && isAssigned) return; const opt = document.createElement("option"); - opt.value = b.BeaconID; - opt.textContent = String(b.BeaconID) + " - " + (b.BeaconName || ""); + opt.value = b.ID; + opt.textContent = String(b.ID) + " - " + (b.Name || ""); sel.appendChild(opt); }); @@ -203,12 +203,12 @@ async function refreshServicePoints(assignedServicePointIDs, keepSelectedService setSelectPlaceholder(sel, "-- Select ServicePoint --"); (out.SERVICEPOINTS || []).forEach(sp => { - const isAssigned = assignedServicePointIDs.has(String(sp.ServicePointID)); + const isAssigned = assignedServicePointIDs.has(String(sp.ID)); if (HIDE_ASSIGNED_SERVICEPOINTS && isAssigned) return; const opt = document.createElement("option"); - opt.value = sp.ServicePointID; - opt.textContent = String(sp.ServicePointID) + " - " + (sp.ServicePointName || ""); + opt.value = sp.ID; + opt.textContent = String(sp.ID) + " - " + (sp.Name || ""); sel.appendChild(opt); }); diff --git a/admin/beacons.cfm b/admin/beacons.cfm index 137769d..ea483f3 100644 --- a/admin/beacons.cfm +++ b/admin/beacons.cfm @@ -25,7 +25,7 @@

Beacons

-
Required: BeaconName
+
Required: Name
(JS not loaded yet)
@@ -38,8 +38,8 @@
-
- +
+
@@ -160,13 +160,13 @@ function escapeHtml(s){ } function loadIntoForm(b){ - document.getElementById("BeaconID").value = b.BeaconID || ""; - document.getElementById("BeaconName").value = b.BeaconName || ""; + document.getElementById("BeaconID").value = b.ID || ""; + document.getElementById("Name").value = b.Name || ""; document.getElementById("UUID").value = b.UUID || ""; document.getElementById("NamespaceId").value = b.NamespaceId || ""; document.getElementById("InstanceId").value = b.InstanceId || ""; document.getElementById("IsActive").value = ("" + (b.IsActive ?? 1)); - document.getElementById("DelBeaconID").value = b.BeaconID || ""; + document.getElementById("DelBeaconID").value = b.ID || ""; } async function refresh() { @@ -180,8 +180,8 @@ async function refresh() { for (const b of items) { const tr = document.createElement("tr"); tr.innerHTML = ` - ${b.BeaconID} - ${escapeHtml(b.BeaconName||"")} + ${b.ID} + ${escapeHtml(b.Name||"")} ${escapeHtml(b.UUID||"")} ${escapeHtml(b.NamespaceId||"")} ${escapeHtml(b.InstanceId||"")} @@ -194,15 +194,15 @@ async function refresh() { } async function saveBeacon() { - const name = (document.getElementById("BeaconName").value || "").trim(); + const name = (document.getElementById("Name").value || "").trim(); if (!name) { - show({ OK:false, ERROR:"missing_beacon_name", MESSAGE:"BeaconName is required" }); + show({ OK:false, ERROR:"missing_beacon_name", MESSAGE:"Name is required" }); return; } const body = { BeaconID: valIntOrNull("BeaconID"), - BeaconName: name, + Name: name, UUID: (document.getElementById("UUID").value || "").trim(), NamespaceId: (document.getElementById("NamespaceId").value || "").trim(), InstanceId: (document.getElementById("InstanceId").value || "").trim(), diff --git a/admin/email_users.cfm b/admin/email_users.cfm index 2ee08ac..8c01f0b 100644 --- a/admin/email_users.cfm +++ b/admin/email_users.cfm @@ -7,16 +7,16 @@ - SELECT U.UserEmailAddress + SELECT U.EmailAddress FROM Users U WHERE UserID in (0,1,2) - #UserEmailAddress#, + #EmailAddress#, - +

@@ -95,18 +95,18 @@ - SELECT UserUUID + SELECT UUID FROM Users - WHERE UserEmailAddress = '#the_email_address#' + WHERE EmailAddress = '#the_email_address#' AND UserIsEmailverified = 1 AND - UserIsContactVerified > 0 + IsContactVerified > 0 #HTMLCodeFormat(form.this_email_body)# diff --git a/admin/god_mode.cfm b/admin/god_mode.cfm index 3ce8349..4e67427 100644 --- a/admin/god_mode.cfm +++ b/admin/god_mode.cfm @@ -5,14 +5,14 @@ - SELECT U.UserID, U.UserEmailAddress, U.UserContactNumber,U.UserAddedOn + SELECT U.ID, U.EmailAddress, U.ContactNumber,U.AddedOn FROM Users U - WHERE U.UserIsEmailVerified = 1 + WHERE U.IsEmailVerified = 1 AND U.UserIsCOntactVerified > 0 AND - U.UserID > 435 - ORDER BY U.UserID DESC + U.ID > 435 + ORDER BY U.ID DESC @@ -48,16 +48,16 @@ - #UserEmailAddress# - #UserContactNumber# - #dateformat(UserAddedOn, "mmmm dd, YYYY")# at #timeformat(UserAddedOn, "hh:nn tt")# + #EmailAddress# + #ContactNumber# + #dateformat(AddedOn, "mmmm dd, YYYY")# at #timeformat(AddedOn, "hh:nn tt")# - SELECT O.OrderUUID + SELECT O.UUID FROM Orders O - WHERE O.OrderUserID = #get_verified_users.UserID# - ORDER BY O.OrderID DESC + WHERE O.UserID = #get_verified_users.ID# + ORDER BY O.ID DESC @@ -66,7 +66,7 @@ - #looper#,   + #looper#,   @@ -79,10 +79,10 @@ - SELECT V.VisitorTrackingPageMode, V.VisitorTrackingAddedOn - FROM VisitorTracking V - WHERE V.VisitorTrackingUserID = #form.chip# - ORDER BY V.VisitorTrackingAddedOn DESC + SELECT V.PageMode, V.AddedOn + FROM VisitorTrackings V + WHERE V.UserID = #form.chip# + ORDER BY V.AddedOn DESC @@ -92,8 +92,8 @@ - - + +
#VisitorTrackingPageMode##VisitorTrackingAddedOn##PageMode##AddedOn#
diff --git a/admin/servicepoints.cfm b/admin/servicepoints.cfm index b6cc6a5..1ed9d88 100644 --- a/admin/servicepoints.cfm +++ b/admin/servicepoints.cfm @@ -25,7 +25,7 @@

ServicePoints

-
Required: ServicePointName
+
Required: Name
(JS not loaded yet)
@@ -38,18 +38,18 @@
-
- +
+
-
- +
+
-
- +
+
@@ -160,14 +160,14 @@ function escapeHtml(s){ } function loadIntoForm(sp){ - document.getElementById("ServicePointID").value = sp.ServicePointID || ""; - document.getElementById("ServicePointName").value = sp.ServicePointName || ""; - document.getElementById("ServicePointTypeID").value = (sp.ServicePointTypeID ?? 0); - document.getElementById("ServicePointCode").value = sp.ServicePointCode || ""; + document.getElementById("ServicePointID").value = sp.ID || ""; + document.getElementById("Name").value = sp.Name || ""; + document.getElementById("TypeID").value = (sp.TypeID ?? 0); + document.getElementById("Code").value = sp.Code || ""; document.getElementById("Description").value = sp.Description || ""; document.getElementById("SortOrder").value = (sp.SortOrder ?? 0); document.getElementById("IsActive").value = ("" + (sp.IsActive ?? 1)); - document.getElementById("DelServicePointID").value = sp.ServicePointID || ""; + document.getElementById("DelServicePointID").value = sp.ID || ""; } async function refresh() { @@ -181,10 +181,10 @@ async function refresh() { for (const sp of items) { const tr = document.createElement("tr"); tr.innerHTML = ` - ${sp.ServicePointID} - ${escapeHtml(sp.ServicePointName||"")} - ${sp.ServicePointTypeID} - ${escapeHtml(sp.ServicePointCode||"")} + ${sp.ID} + ${escapeHtml(sp.Name||"")} + ${sp.TypeID} + ${escapeHtml(sp.Code||"")} ${sp.SortOrder} ${sp.IsActive} `; @@ -195,17 +195,17 @@ async function refresh() { } async function saveSP() { - const name = (document.getElementById("ServicePointName").value || "").trim(); + const name = (document.getElementById("Name").value || "").trim(); if (!name) { - show({ OK:false, ERROR:"missing_servicepoint_name", MESSAGE:"ServicePointName is required" }); + show({ OK:false, ERROR:"missing_servicepoint_name", MESSAGE:"Name is required" }); return; } const body = { ServicePointID: valIntOrNull("ServicePointID"), - ServicePointName: name, - ServicePointTypeID: valIntOrZero("ServicePointTypeID"), - ServicePointCode: (document.getElementById("ServicePointCode").value || "").trim(), + Name: name, + TypeID: valIntOrZero("TypeID"), + Code: (document.getElementById("Code").value || "").trim(), Description: (document.getElementById("Description").value || "").trim(), SortOrder: valIntOrZero("SortOrder"), IsActive: parseInt(document.getElementById("IsActive").value, 10) diff --git a/api/Application.cfm b/api/Application.cfm index 8e1d4b3..3fef6e3 100644 --- a/api/Application.cfm +++ b/api/Application.cfm @@ -1,11 +1,6 @@ - - - - - + try { - cached = appCacheGet("states", 86400); - if (!isNull(cached)) { - writeOutput(cached); - abort; - } - qStates = queryExecute(" - SELECT tt_StateID as StateID, tt_StateAbbreviation as StateAbbreviation, tt_StateName as StateName + SELECT tt_StateID as StateID, Abbreviation as StateAbbreviation, Name as StateName FROM tt_States - ORDER BY tt_StateName + ORDER BY Name ", {}, { datasource: "payfrit" }); states = []; @@ -26,12 +20,10 @@ try { }); } - jsonResponse = serializeJSON({ + writeOutput(serializeJSON({ "OK": true, "STATES": states - }); - appCachePut("states", jsonResponse); - writeOutput(jsonResponse); + })); } catch (any e) { writeOutput(serializeJSON({ diff --git a/api/admin/addCategoryIsActiveColumn.cfm b/api/admin/addCategoryIsActiveColumn.cfm index 65f53ab..046935d 100644 --- a/api/admin/addCategoryIsActiveColumn.cfm +++ b/api/admin/addCategoryIsActiveColumn.cfm @@ -2,25 +2,25 @@ -// Add TaskCategoryIsActive column to TaskCategories table +// Add IsActive column to TaskCategories table try { // Check if column exists qCheck = queryExecute(" SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'payfrit' AND TABLE_NAME = 'TaskCategories' - AND COLUMN_NAME = 'TaskCategoryIsActive' + AND COLUMN_NAME = 'IsActive' ", [], { datasource: "payfrit" }); if (qCheck.recordCount == 0) { queryExecute(" ALTER TABLE TaskCategories - ADD COLUMN TaskCategoryIsActive TINYINT(1) NOT NULL DEFAULT 1 + ADD COLUMN IsActive TINYINT(1) NOT NULL DEFAULT 1 ", [], { datasource: "payfrit" }); writeOutput(serializeJSON({ "OK": true, - "MESSAGE": "Column TaskCategoryIsActive added to TaskCategories" + "MESSAGE": "Column IsActive added to TaskCategories" })); } else { writeOutput(serializeJSON({ diff --git a/api/admin/addCategoryScheduleFields.cfm b/api/admin/addCategoryScheduleFields.cfm index f5be694..963e600 100644 --- a/api/admin/addCategoryScheduleFields.cfm +++ b/api/admin/addCategoryScheduleFields.cfm @@ -8,9 +8,9 @@ * Add Schedule Fields to Categories Table * * Adds time-based scheduling fields: - * - CategoryScheduleStart: TIME - Start time when category is available (e.g., 06:00:00 for breakfast) - * - CategoryScheduleEnd: TIME - End time when category stops being available (e.g., 11:00:00) - * - CategoryScheduleDays: VARCHAR(20) - Comma-separated list of day IDs (1=Sun, 2=Mon, etc.) or NULL for all days + * - ScheduleStart: TIME - Start time when category is available (e.g., 06:00:00 for breakfast) + * - ScheduleEnd: TIME - End time when category stops being available (e.g., 11:00:00) + * - ScheduleDays: VARCHAR(20) - Comma-separated list of day IDs (1=Sun, 2=Mon, etc.) or NULL for all days * * Run this once to migrate the schema. */ @@ -24,38 +24,38 @@ try { FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'payfrit' AND TABLE_NAME = 'Categories' - AND COLUMN_NAME IN ('CategoryScheduleStart', 'CategoryScheduleEnd', 'CategoryScheduleDays') + AND COLUMN_NAME IN ('ScheduleStart', 'ScheduleEnd', 'ScheduleDays') ", {}, { datasource: "payfrit" }); existingCols = valueList(qCheck.COLUMN_NAME); added = []; - // Add CategoryScheduleStart if not exists - if (!listFindNoCase(existingCols, "CategoryScheduleStart")) { + // Add ScheduleStart if not exists + if (!listFindNoCase(existingCols, "ScheduleStart")) { queryExecute(" ALTER TABLE Categories - ADD COLUMN CategoryScheduleStart TIME NULL + ADD COLUMN ScheduleStart TIME NULL ", {}, { datasource: "payfrit" }); - arrayAppend(added, "CategoryScheduleStart"); + arrayAppend(added, "ScheduleStart"); } - // Add CategoryScheduleEnd if not exists - if (!listFindNoCase(existingCols, "CategoryScheduleEnd")) { + // Add ScheduleEnd if not exists + if (!listFindNoCase(existingCols, "ScheduleEnd")) { queryExecute(" ALTER TABLE Categories - ADD COLUMN CategoryScheduleEnd TIME NULL + ADD COLUMN ScheduleEnd TIME NULL ", {}, { datasource: "payfrit" }); - arrayAppend(added, "CategoryScheduleEnd"); + arrayAppend(added, "ScheduleEnd"); } - // Add CategoryScheduleDays if not exists - if (!listFindNoCase(existingCols, "CategoryScheduleDays")) { + // Add ScheduleDays if not exists + if (!listFindNoCase(existingCols, "ScheduleDays")) { queryExecute(" ALTER TABLE Categories - ADD COLUMN CategoryScheduleDays VARCHAR(20) NULL + ADD COLUMN ScheduleDays VARCHAR(20) NULL ", {}, { datasource: "payfrit" }); - arrayAppend(added, "CategoryScheduleDays"); + arrayAppend(added, "ScheduleDays"); } response["OK"] = true; diff --git a/api/admin/addDrinkModifiers.cfm b/api/admin/addDrinkModifiers.cfm index ec4cea2..81b24d6 100644 --- a/api/admin/addDrinkModifiers.cfm +++ b/api/admin/addDrinkModifiers.cfm @@ -15,8 +15,8 @@ try { // Find the Fountain Soda item we created qFountain = queryExecute(" - SELECT ItemID, ItemName FROM Items - WHERE ItemBusinessID = :bizId AND ItemName = 'Fountain Soda' + SELECT ID, Name FROM Items + WHERE BusinessID = :bizId AND Name = 'Fountain Soda' ", { bizId: bigDeansBusinessId }, { datasource: "payfrit" }); if (qFountain.recordCount == 0) { @@ -31,13 +31,13 @@ try { // Update Fountain Soda to require child selection and be collapsible queryExecute(" UPDATE Items - SET ItemRequiresChildSelection = 1, ItemIsCollapsible = 1 + SET RequiresChildSelection = 1, IsCollapsible = 1 WHERE ItemID = :itemId ", { itemId: fountainId }, { datasource: "payfrit" }); // Check if modifiers already exist qExisting = queryExecute(" - SELECT COUNT(*) as cnt FROM Items WHERE ItemParentItemID = :parentId + SELECT COUNT(*) as cnt FROM Items WHERE ParentItemID = :parentId ", { parentId: fountainId }, { datasource: "payfrit" }); if (qExisting.cnt > 0) { @@ -53,10 +53,10 @@ try { queryExecute(" INSERT INTO Items ( - ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID, - ItemName, ItemDescription, ItemPrice, ItemIsActive, - ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection, - ItemMaxNumSelectionReq, ItemAddedOn + ItemID, BusinessID, CategoryID, ParentItemID, + Name, Description, Price, IsActive, + SortOrder, IsCollapsible, RequiresChildSelection, + MaxNumSelectionReq, AddedOn ) VALUES ( :itemId, :bizId, 0, :parentId, 'Size', 'Choose your size', 0, 1, @@ -80,10 +80,10 @@ try { qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" }); queryExecute(" INSERT INTO Items ( - ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID, - ItemName, ItemDescription, ItemPrice, ItemIsActive, - ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault, - ItemAddedOn + ItemID, BusinessID, CategoryID, ParentItemID, + Name, Description, Price, IsActive, + SortOrder, IsCollapsible, IsCheckedByDefault, + AddedOn ) VALUES ( :itemId, :bizId, 0, :parentId, :name, '', :price, 1, @@ -108,10 +108,10 @@ try { queryExecute(" INSERT INTO Items ( - ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID, - ItemName, ItemDescription, ItemPrice, ItemIsActive, - ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection, - ItemMaxNumSelectionReq, ItemAddedOn + ItemID, BusinessID, CategoryID, ParentItemID, + Name, Description, Price, IsActive, + SortOrder, IsCollapsible, RequiresChildSelection, + MaxNumSelectionReq, AddedOn ) VALUES ( :itemId, :bizId, 0, :parentId, 'Flavor', 'Choose your drink', 0, 1, @@ -139,10 +139,10 @@ try { qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" }); queryExecute(" INSERT INTO Items ( - ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID, - ItemName, ItemDescription, ItemPrice, ItemIsActive, - ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault, - ItemAddedOn + ItemID, BusinessID, CategoryID, ParentItemID, + Name, Description, Price, IsActive, + SortOrder, IsCollapsible, IsCheckedByDefault, + AddedOn ) VALUES ( :itemId, :bizId, 0, :parentId, :name, '', 0, 1, diff --git a/api/admin/addItemCategoryColumn.cfm b/api/admin/addItemCategoryColumn.cfm index 61589f2..c04b791 100644 --- a/api/admin/addItemCategoryColumn.cfm +++ b/api/admin/addItemCategoryColumn.cfm @@ -5,7 +5,7 @@ /** - * Add ItemCategoryID column to Items table + * Add CategoryID column to Items table */ response = { "OK": false }; @@ -17,30 +17,30 @@ try { FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'payfrit' AND TABLE_NAME = 'Items' - AND COLUMN_NAME = 'ItemCategoryID' + AND COLUMN_NAME = 'CategoryID' ", {}, { datasource: "payfrit" }); if (qCheck.recordCount > 0) { response["OK"] = true; - response["MESSAGE"] = "ItemCategoryID column already exists"; + response["MESSAGE"] = "CategoryID column already exists"; } else { // Add the column queryExecute(" ALTER TABLE Items - ADD COLUMN ItemCategoryID INT NULL DEFAULT 0 AFTER ItemParentItemID + ADD COLUMN CategoryID INT NULL DEFAULT 0 AFTER ParentItemID ", {}, { datasource: "payfrit" }); // Add index for performance try { queryExecute(" - CREATE INDEX idx_items_categoryid ON Items(ItemCategoryID) + CREATE INDEX idx_items_categoryid ON Items(CategoryID) ", {}, { datasource: "payfrit" }); } catch (any indexErr) { // Index might already exist } response["OK"] = true; - response["MESSAGE"] = "ItemCategoryID column added successfully"; + response["MESSAGE"] = "CategoryID column added successfully"; } } catch (any e) { diff --git a/api/admin/addLatLng.cfm b/api/admin/addLatLng.cfm index 983cda6..5c89c1d 100644 --- a/api/admin/addLatLng.cfm +++ b/api/admin/addLatLng.cfm @@ -6,7 +6,7 @@ try { // Check if columns already exist checkCols = queryExecute( - "SHOW COLUMNS FROM Addresses LIKE 'AddressLat'", + "SHOW COLUMNS FROM Addresses LIKE 'Latitude'", [], { datasource = "payfrit" } ); @@ -15,8 +15,8 @@ try { // Add the columns queryExecute( "ALTER TABLE Addresses - ADD COLUMN AddressLat DECIMAL(10,7) NULL, - ADD COLUMN AddressLng DECIMAL(10,7) NULL", + ADD COLUMN Latitude DECIMAL(10,7) NULL, + ADD COLUMN Longitude DECIMAL(10,7) NULL", [], { datasource = "payfrit" } ); diff --git a/api/admin/addServiceCategoryColumn.cfm b/api/admin/addServiceCategoryColumn.cfm index 9a7939d..bdbccbc 100644 --- a/api/admin/addServiceCategoryColumn.cfm +++ b/api/admin/addServiceCategoryColumn.cfm @@ -9,18 +9,18 @@ try { SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'payfrit' AND TABLE_NAME = 'tt_TaskTypes' - AND COLUMN_NAME = 'tt_TaskTypeCategoryID' + AND COLUMN_NAME = 'TaskCategoryID' ", [], { datasource: "payfrit" }); if (qCheck.recordCount == 0) { queryExecute(" ALTER TABLE tt_TaskTypes - ADD COLUMN tt_TaskTypeCategoryID INT NULL + ADD COLUMN TaskCategoryID INT NULL ", [], { datasource: "payfrit" }); writeOutput(serializeJSON({ "OK": true, - "MESSAGE": "Column tt_TaskTypeCategoryID added to tt_TaskTypes" + "MESSAGE": "Column TaskCategoryID added to tt_TaskTypes" })); } else { writeOutput(serializeJSON({ diff --git a/api/admin/addTaskSourceColumns.cfm b/api/admin/addTaskSourceColumns.cfm index 20b5147..df621f0 100644 --- a/api/admin/addTaskSourceColumns.cfm +++ b/api/admin/addTaskSourceColumns.cfm @@ -3,7 +3,7 @@ -// Add TaskSourceType and TaskSourceID columns to Tasks table +// Add SourceType and SourceID columns to Tasks table // These are needed for chat persistence feature result = { "OK": true, "STEPS": [] }; @@ -15,30 +15,30 @@ try { FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'payfrit' AND TABLE_NAME = 'Tasks' - AND COLUMN_NAME IN ('TaskSourceType', 'TaskSourceID') + AND COLUMN_NAME IN ('SourceType', 'SourceID') ", [], { datasource: "payfrit" }); existingCols = valueList(cols.COLUMN_NAME); arrayAppend(result.STEPS, "Existing columns: #existingCols#"); - // Add TaskSourceType if missing - if (!listFindNoCase(existingCols, "TaskSourceType")) { + // Add SourceType if missing + if (!listFindNoCase(existingCols, "SourceType")) { queryExecute(" - ALTER TABLE Tasks ADD COLUMN TaskSourceType VARCHAR(50) NULL + ALTER TABLE Tasks ADD COLUMN SourceType VARCHAR(50) NULL ", [], { datasource: "payfrit" }); - arrayAppend(result.STEPS, "Added TaskSourceType column"); + arrayAppend(result.STEPS, "Added SourceType column"); } else { - arrayAppend(result.STEPS, "TaskSourceType already exists"); + arrayAppend(result.STEPS, "SourceType already exists"); } - // Add TaskSourceID if missing - if (!listFindNoCase(existingCols, "TaskSourceID")) { + // Add SourceID if missing + if (!listFindNoCase(existingCols, "SourceID")) { queryExecute(" - ALTER TABLE Tasks ADD COLUMN TaskSourceID INT NULL + ALTER TABLE Tasks ADD COLUMN SourceID INT NULL ", [], { datasource: "payfrit" }); - arrayAppend(result.STEPS, "Added TaskSourceID column"); + arrayAppend(result.STEPS, "Added SourceID column"); } else { - arrayAppend(result.STEPS, "TaskSourceID already exists"); + arrayAppend(result.STEPS, "SourceID already exists"); } // Verify columns now exist @@ -47,7 +47,7 @@ try { FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'payfrit' AND TABLE_NAME = 'Tasks' - AND COLUMN_NAME IN ('TaskSourceType', 'TaskSourceID') + AND COLUMN_NAME IN ('SourceType', 'SourceID') ", [], { datasource: "payfrit" }); result.COLUMNS = []; diff --git a/api/admin/beaconStatus.cfm b/api/admin/beaconStatus.cfm index 1eab4df..7252e25 100644 --- a/api/admin/beaconStatus.cfm +++ b/api/admin/beaconStatus.cfm @@ -6,49 +6,49 @@ // Show all beacons with their current business/service point assignments q = queryExecute(" SELECT - b.BeaconID, - b.BeaconUUID, - b.BeaconName, - lt.BusinessID, - lt.ServicePointID, - biz.BusinessName, - sp.ServicePointName + b.ID, + b.UUID, + b.Name, + sp_link.BusinessID, + sp_link.ID, + biz.Name, + sp.Name FROM Beacons b - LEFT JOIN lt_Beacon_Businesses_ServicePoints lt ON lt.BeaconID = b.BeaconID - LEFT JOIN Businesses biz ON biz.BusinessID = lt.BusinessID - LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID - WHERE b.BeaconIsActive = 1 - ORDER BY b.BeaconID + LEFT JOIN ServicePoints sp_link ON sp_link.BeaconID = b.ID + LEFT JOIN Businesses biz ON biz.ID = sp_link.BusinessID + LEFT JOIN ServicePoints sp ON sp.ID = sp_link.ID + WHERE b.IsActive = 1 + ORDER BY b.ID ", {}, { datasource: "payfrit" }); rows = []; for (row in q) { arrayAppend(rows, { - "BeaconID": row.BeaconID, - "BeaconUUID": row.BeaconUUID, - "BeaconName": row.BeaconName ?: "", + "BeaconID": row.ID, + "UUID": row.UUID, + "Name": row.Name ?: "", "BusinessID": row.BusinessID ?: 0, - "BusinessName": row.BusinessName ?: "", + "Name": row.Name ?: "", "ServicePointID": row.ServicePointID ?: 0, - "ServicePointName": row.ServicePointName ?: "" + "Name": row.Name ?: "" }); } // Also get service points for reference spQuery = queryExecute(" - SELECT sp.ServicePointID, sp.ServicePointName, sp.ServicePointBusinessID, b.BusinessName + SELECT sp.ID, sp.Name, sp.BusinessID, b.Name FROM ServicePoints sp - JOIN Businesses b ON b.BusinessID = sp.ServicePointBusinessID - ORDER BY sp.ServicePointBusinessID, sp.ServicePointID + JOIN Businesses b ON b.ID = sp.BusinessID + ORDER BY sp.BusinessID, sp.ID ", {}, { datasource: "payfrit" }); servicePoints = []; for (sp in spQuery) { arrayAppend(servicePoints, { - "ServicePointID": sp.ServicePointID, - "ServicePointName": sp.ServicePointName, - "BusinessID": sp.ServicePointBusinessID, - "BusinessName": sp.BusinessName + "ServicePointID": sp.ID, + "Name": sp.Name, + "BusinessID": sp.BusinessID, + "Name": sp.Name }); } diff --git a/api/admin/checkBigDeans.cfm b/api/admin/checkBigDeans.cfm index 5262e7c..ef674a7 100644 --- a/api/admin/checkBigDeans.cfm +++ b/api/admin/checkBigDeans.cfm @@ -5,16 +5,16 @@ // Check Big Dean's owner q = queryExecute(" - SELECT b.BusinessID, b.BusinessName, b.BusinessUserID + SELECT b.ID, b.Name, b.UserID FROM Businesses b - WHERE b.BusinessID = 27 + WHERE b.ID = 27 ", {}, { datasource: "payfrit" }); // Get users users = queryExecute(" SELECT * FROM Users - ORDER BY UserID + ORDER BY ID LIMIT 20 ", {}, { datasource: "payfrit" }); @@ -23,9 +23,9 @@ colNames = users.getColumnNames(); writeOutput(serializeJSON({ "OK": true, "BigDeans": { - "BusinessID": q.BusinessID, - "BusinessName": q.BusinessName, - "BusinessUserID": q.BusinessUserID + "BusinessID": q.ID, + "Name": q.Name, + "UserID": q.UserID }, "UserColumns": colNames, "UserCount": users.recordCount diff --git a/api/admin/checkUser.cfm b/api/admin/checkUser.cfm index 1f558e5..6994ce8 100644 --- a/api/admin/checkUser.cfm +++ b/api/admin/checkUser.cfm @@ -12,9 +12,9 @@ if (!len(phone)) { } q = queryExecute(" - SELECT UserID, UserFirstName, UserLastName, UserEmail, UserPhone, UserIsContactVerified + SELECT ID, FirstName, LastName, EmailAddress, ContactNumber, IsContactVerified FROM Users - WHERE UserPhone = :phone OR UserEmail = :phone + WHERE ContactNumber = :phone OR EmailAddress = :phone LIMIT 1 ", { phone: phone }, { datasource: "payfrit" }); @@ -25,11 +25,11 @@ if (q.recordCount EQ 0) { writeOutput(serializeJSON({ "OK": true, - "UserID": q.UserID, - "FirstName": q.UserFirstName, - "LastName": q.UserLastName, - "Email": q.UserEmail, - "Phone": q.UserPhone, - "Verified": q.UserIsContactVerified + "UserID": q.ID, + "FirstName": q.FirstName, + "LastName": q.LastName, + "Email": q.EmailAddress, + "Phone": q.ContactNumber, + "Verified": q.IsContactVerified })); diff --git a/api/admin/cleanupBeacons.cfm b/api/admin/cleanupBeacons.cfm index c8b925a..40dba28 100644 --- a/api/admin/cleanupBeacons.cfm +++ b/api/admin/cleanupBeacons.cfm @@ -5,7 +5,8 @@ /** * Cleanup Lazy Daisy Beacons - * - Removes duplicate beacons created by setupBeaconTables + * - Unassigns beacons 7, 8, 9 from service points + * - Deletes beacons 7, 8, 9 * - Updates original beacons with proper names */ response = { "OK": false, "steps": [] }; @@ -13,52 +14,50 @@ response = { "OK": false, "steps": [] }; try { lazyDaisyID = 37; - // Delete duplicate assignments for beacons 7, 8, 9 + // Unassign beacons 7, 8, 9 from any service points queryExecute(" - DELETE FROM lt_Beacon_Businesses_ServicePoints + UPDATE ServicePoints + SET BeaconID = NULL, AssignedByUserID = NULL WHERE BeaconID IN (7, 8, 9) AND BusinessID = :bizId ", { bizId: lazyDaisyID }, { datasource: "payfrit" }); - response.steps.append("Deleted duplicate assignments for beacons 7, 8, 9"); + response.steps.append("Unassigned beacons 7, 8, 9 from service points"); // Delete duplicate beacons 7, 8, 9 queryExecute(" DELETE FROM Beacons - WHERE BeaconID IN (7, 8, 9) AND BeaconBusinessID = :bizId + WHERE ID IN (7, 8, 9) AND BusinessID = :bizId ", { bizId: lazyDaisyID }, { datasource: "payfrit" }); response.steps.append("Deleted duplicate beacons 7, 8, 9"); // Update original beacons with names based on their service point assignments - // Beacon 4 -> Table 1 (ServicePointID 4) - // Beacon 5 -> Table 2 (ServicePointID 5) - // Beacon 6 -> Table 3 (ServicePointID 6) - queryExecute(" - UPDATE Beacons SET BeaconName = 'Beacon - Table 1' - WHERE BeaconID = 4 AND BeaconBusinessID = :bizId + UPDATE Beacons SET Name = 'Beacon - Table 1' + WHERE ID = 4 AND BusinessID = :bizId ", { bizId: lazyDaisyID }, { datasource: "payfrit" }); response.steps.append("Updated Beacon 4 name to 'Beacon - Table 1'"); queryExecute(" - UPDATE Beacons SET BeaconName = 'Beacon - Table 2' - WHERE BeaconID = 5 AND BeaconBusinessID = :bizId + UPDATE Beacons SET Name = 'Beacon - Table 2' + WHERE ID = 5 AND BusinessID = :bizId ", { bizId: lazyDaisyID }, { datasource: "payfrit" }); response.steps.append("Updated Beacon 5 name to 'Beacon - Table 2'"); queryExecute(" - UPDATE Beacons SET BeaconName = 'Beacon - Table 3' - WHERE BeaconID = 6 AND BeaconBusinessID = :bizId + UPDATE Beacons SET Name = 'Beacon - Table 3' + WHERE ID = 6 AND BusinessID = :bizId ", { bizId: lazyDaisyID }, { datasource: "payfrit" }); response.steps.append("Updated Beacon 6 name to 'Beacon - Table 3'"); // Get final status qFinal = queryExecute(" - SELECT lt.BeaconID, b.BeaconUUID, b.BeaconName, lt.BusinessID, biz.BusinessName, lt.ServicePointID, sp.ServicePointName - FROM lt_Beacon_Businesses_ServicePoints lt - JOIN Beacons b ON b.BeaconID = lt.BeaconID - JOIN Businesses biz ON biz.BusinessID = lt.BusinessID - LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID - WHERE lt.BusinessID = :bizId - ORDER BY lt.BeaconID + SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID, + b.Name AS BeaconName, b.UUID, sp.Name AS ServicePointName, + biz.Name AS BusinessName + FROM ServicePoints sp + JOIN Beacons b ON b.ID = sp.BeaconID + JOIN Businesses biz ON biz.ID = sp.BusinessID + WHERE sp.BusinessID = :bizId AND sp.BeaconID IS NOT NULL + ORDER BY sp.BeaconID ", { bizId: lazyDaisyID }, { datasource: "payfrit" }); beacons = []; @@ -66,8 +65,9 @@ try { arrayAppend(beacons, { "BeaconID": qFinal.BeaconID[i], "BeaconName": qFinal.BeaconName[i], - "UUID": qFinal.BeaconUUID[i], + "UUID": qFinal.UUID[i], "BusinessName": qFinal.BusinessName[i], + "ServicePointID": qFinal.ServicePointID[i], "ServicePointName": qFinal.ServicePointName[i] }); } diff --git a/api/admin/cleanupCategories.cfm b/api/admin/cleanupCategories.cfm index 2f73a50..b842664 100644 --- a/api/admin/cleanupCategories.cfm +++ b/api/admin/cleanupCategories.cfm @@ -13,10 +13,10 @@ * Cleanup Categories - Final step after migration verification * * This script: - * 1. Verifies all Items have ItemBusinessID set + * 1. Verifies all Items have BusinessID set * 2. Finds orphan items (ParentID=0, no children, not in links) - * 3. Drops ItemCategoryID column - * 4. Drops ItemIsModifierTemplate column (derived from ItemTemplateLinks now) + * 3. Drops CategoryID column + * 4. Drops IsModifierTemplate column (derived from lt_ItemID_TemplateItemID now) * 5. Drops Categories table * * Query param: ?confirm=YES to actually execute (otherwise shows verification only) @@ -30,7 +30,7 @@ try { // Verification Step 1: Check for items without BusinessID qNoBusinessID = queryExecute(" SELECT COUNT(*) as cnt FROM Items - WHERE ItemBusinessID IS NULL OR ItemBusinessID = 0 + WHERE BusinessID IS NULL OR BusinessID = 0 ", {}, { datasource: "payfrit" }); response.verification["itemsWithoutBusinessID"] = qNoBusinessID.cnt; @@ -46,38 +46,38 @@ try { qCategoryItems = queryExecute(" SELECT COUNT(DISTINCT p.ItemID) as cnt FROM Items p - INNER JOIN Items c ON c.ItemParentItemID = p.ItemID - WHERE p.ItemParentItemID = 0 - AND p.ItemBusinessID > 0 + INNER JOIN Items c ON c.ParentItemID = p.ItemID + WHERE p.ParentItemID = 0 + AND p.BusinessID > 0 AND NOT EXISTS ( - SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = p.ItemID + SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = p.ItemID ) ", {}, { datasource: "payfrit" }); response.verification["categoryItemsCreated"] = qCategoryItems.cnt; - // Verification Step 4: Check templates exist (in ItemTemplateLinks) + // Verification Step 4: Check templates exist (in lt_ItemID_TemplateItemID) qTemplates = queryExecute(" SELECT COUNT(DISTINCT tl.TemplateItemID) as cnt - FROM ItemTemplateLinks tl + FROM lt_ItemID_TemplateItemID tl INNER JOIN Items t ON t.ItemID = tl.TemplateItemID ", {}, { datasource: "payfrit" }); response.verification["templatesInLinks"] = qTemplates.cnt; // Verification Step 5: Find orphans at ParentID=0 - // Orphan = ParentID=0, no children pointing to it, not in ItemTemplateLinks + // Orphan = ParentID=0, no children pointing to it, not in lt_ItemID_TemplateItemID qOrphans = queryExecute(" - SELECT i.ItemID, i.ItemName, i.ItemBusinessID + SELECT i.ID, i.Name, i.BusinessID FROM Items i - WHERE i.ItemParentItemID = 0 + WHERE i.ParentItemID = 0 AND NOT EXISTS ( - SELECT 1 FROM Items child WHERE child.ItemParentItemID = i.ItemID + SELECT 1 FROM Items child WHERE child.ParentItemID = i.ID ) AND NOT EXISTS ( - SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = i.ItemID + SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = i.ID ) - ORDER BY i.ItemBusinessID, i.ItemName + ORDER BY i.BusinessID, i.Name ", {}, { datasource: "payfrit" }); response.verification["orphanCount"] = qOrphans.recordCount; @@ -85,8 +85,8 @@ try { for (orphan in qOrphans) { arrayAppend(response.orphans, { "ItemID": orphan.ItemID, - "ItemName": orphan.ItemName, - "BusinessID": orphan.ItemBusinessID + "Name": orphan.Name, + "BusinessID": orphan.BusinessID }); } @@ -96,7 +96,7 @@ try { if (!safeToCleanup) { arrayAppend(response.steps, "VERIFICATION FAILED - Cannot cleanup yet"); - arrayAppend(response.steps, "- " & qNoBusinessID.cnt & " items still missing ItemBusinessID"); + arrayAppend(response.steps, "- " & qNoBusinessID.cnt & " items still missing BusinessID"); response["OK"] = false; writeOutput(serializeJSON(response)); abort; @@ -119,31 +119,31 @@ try { // Execute cleanup arrayAppend(response.steps, "Executing cleanup..."); - // Step 1: Drop ItemCategoryID column + // Step 1: Drop CategoryID column try { queryExecute(" - ALTER TABLE Items DROP COLUMN ItemCategoryID + ALTER TABLE Items DROP COLUMN CategoryID ", {}, { datasource: "payfrit" }); - arrayAppend(response.steps, "Dropped ItemCategoryID column from Items"); + arrayAppend(response.steps, "Dropped CategoryID column from Items"); } catch (any e) { if (findNoCase("check that column", e.message) || findNoCase("Unknown column", e.message)) { - arrayAppend(response.steps, "ItemCategoryID column already dropped"); + arrayAppend(response.steps, "CategoryID column already dropped"); } else { - arrayAppend(response.steps, "Warning dropping ItemCategoryID: " & e.message); + arrayAppend(response.steps, "Warning dropping CategoryID: " & e.message); } } - // Step 2: Drop ItemIsModifierTemplate column (now derived from ItemTemplateLinks) + // Step 2: Drop IsModifierTemplate column (now derived from lt_ItemID_TemplateItemID) try { queryExecute(" - ALTER TABLE Items DROP COLUMN ItemIsModifierTemplate + ALTER TABLE Items DROP COLUMN IsModifierTemplate ", {}, { datasource: "payfrit" }); - arrayAppend(response.steps, "Dropped ItemIsModifierTemplate column from Items"); + arrayAppend(response.steps, "Dropped IsModifierTemplate column from Items"); } catch (any e) { if (findNoCase("check that column", e.message) || findNoCase("Unknown column", e.message)) { - arrayAppend(response.steps, "ItemIsModifierTemplate column already dropped"); + arrayAppend(response.steps, "IsModifierTemplate column already dropped"); } else { - arrayAppend(response.steps, "Warning dropping ItemIsModifierTemplate: " & e.message); + arrayAppend(response.steps, "Warning dropping IsModifierTemplate: " & e.message); } } diff --git a/api/admin/cleanupDuplicateEmployees.cfm b/api/admin/cleanupDuplicateEmployees.cfm index c2f5170..40e76d8 100644 --- a/api/admin/cleanupDuplicateEmployees.cfm +++ b/api/admin/cleanupDuplicateEmployees.cfm @@ -34,8 +34,8 @@ if (businessId <= 0) { try { // Find duplicate UserIDs for this business (keep the one with highest status or oldest) qDupes = queryExecute(" - SELECT UserID, COUNT(*) as cnt, MIN(EmployeeID) as keepId - FROM lt_Users_Businesses_Employees + SELECT ID, COUNT(*) as cnt, MIN(ID) as keepId + FROM Employees WHERE BusinessID = ? GROUP BY UserID HAVING COUNT(*) > 1 @@ -45,8 +45,8 @@ try { for (row in qDupes) { // Delete all but the one we want to keep (the one with lowest EmployeeID) qDel = queryExecute(" - DELETE FROM lt_Users_Businesses_Employees - WHERE BusinessID = ? AND UserID = ? AND EmployeeID != ? + DELETE FROM Employees + WHERE BusinessID = ? AND UserID = ? AND ID != ? ", [ { value: businessId, cfsqltype: "cf_sql_integer" }, { value: row.UserID, cfsqltype: "cf_sql_integer" }, @@ -57,19 +57,19 @@ try { // Get remaining employees qRemaining = queryExecute(" - SELECT e.EmployeeID, e.UserID, u.UserFirstName, u.UserLastName - FROM lt_Users_Businesses_Employees e - JOIN Users u ON e.UserID = u.UserID + SELECT e.ID, e.UserID, u.FirstName, u.LastName + FROM Employees e + JOIN Users u ON e.UserID = u.ID WHERE e.BusinessID = ? - ORDER BY e.EmployeeID + ORDER BY e.ID ", [{ value: businessId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" }); remaining = []; for (r in qRemaining) { arrayAppend(remaining, { - "EmployeeID": r.EmployeeID, + "EmployeeID": r.ID, "UserID": r.UserID, - "Name": trim(r.UserFirstName & " " & r.UserLastName) + "Name": trim(r.FirstName & " " & r.LastName) }); } diff --git a/api/admin/cleanupForLazyDaisy.cfm b/api/admin/cleanupForLazyDaisy.cfm index b663b50..e4ff9ac 100644 --- a/api/admin/cleanupForLazyDaisy.cfm +++ b/api/admin/cleanupForLazyDaisy.cfm @@ -9,106 +9,120 @@ try { // Keep only Lazy Daisy (BusinessID 37) keepBusinessID = 37; - // First, reassign all beacons to Lazy Daisy + // Unassign all beacons from service points of other businesses queryExecute(" - UPDATE lt_Beacon_Businesses_ServicePoints - SET BusinessID = :keepID + UPDATE ServicePoints + SET BeaconID = NULL, AssignedByUserID = NULL + WHERE BusinessID != :keepID AND BeaconID IS NOT NULL ", { keepID: keepBusinessID }, { datasource: "payfrit" }); - response.steps.append("Reassigned all beacons to Lazy Daisy"); + response.steps.append("Unassigned beacons from other businesses' service points"); // Get list of businesses to delete qBiz = queryExecute(" - SELECT BusinessID, BusinessName FROM Businesses WHERE BusinessID != :keepID + SELECT ID, Name FROM Businesses WHERE ID != :keepID ", { keepID: keepBusinessID }, { datasource: "payfrit" }); deletedBusinesses = []; for (i = 1; i <= qBiz.recordCount; i++) { - arrayAppend(deletedBusinesses, qBiz.BusinessName[i]); + arrayAppend(deletedBusinesses, qBiz.Name[i]); } response.steps.append("Found " & qBiz.recordCount & " businesses to delete"); // Delete related data first (foreign key constraints) - // Delete ItemTemplateLinks for items from other businesses + // Delete lt_ItemID_TemplateItemID for items from other businesses queryExecute(" - DELETE itl FROM ItemTemplateLinks itl - JOIN Items i ON i.ItemID = itl.ItemID - WHERE i.ItemBusinessID != :keepID + DELETE itl FROM lt_ItemID_TemplateItemID itl + JOIN Items i ON i.ID = itl.ItemID + WHERE i.BusinessID != :keepID ", { keepID: keepBusinessID }, { datasource: "payfrit" }); - response.steps.append("Deleted ItemTemplateLinks for other businesses"); + response.steps.append("Deleted lt_ItemID_TemplateItemID for other businesses"); // Delete Items for other businesses qItems = queryExecute(" - SELECT COUNT(*) as cnt FROM Items WHERE ItemBusinessID != :keepID + SELECT COUNT(*) as cnt FROM Items WHERE BusinessID != :keepID ", { keepID: keepBusinessID }, { datasource: "payfrit" }); queryExecute(" - DELETE FROM Items WHERE ItemBusinessID != :keepID + DELETE FROM Items WHERE BusinessID != :keepID ", { keepID: keepBusinessID }, { datasource: "payfrit" }); response.steps.append("Deleted " & qItems.cnt & " items from other businesses"); // Delete Categories for other businesses queryExecute(" - DELETE FROM Categories WHERE CategoryBusinessID != :keepID + DELETE FROM Categories WHERE BusinessID != :keepID ", { keepID: keepBusinessID }, { datasource: "payfrit" }); response.steps.append("Deleted categories from other businesses"); // Delete Hours for other businesses queryExecute(" - DELETE FROM Hours WHERE HoursBusinessID != :keepID + DELETE FROM Hours WHERE BusinessID != :keepID ", { keepID: keepBusinessID }, { datasource: "payfrit" }); response.steps.append("Deleted hours from other businesses"); - // Delete Employees for other businesses (skip if table doesn't exist) + // Delete Employees for other businesses try { queryExecute(" - DELETE FROM Employees WHERE EmployeeBusinessID != :keepID + DELETE FROM Employees WHERE BusinessID != :keepID ", { keepID: keepBusinessID }, { datasource: "payfrit" }); response.steps.append("Deleted employees from other businesses"); } catch (any e) { response.steps.append("Skipped employees (table may not exist)"); } - // Delete ServicePoints for other businesses (skip if table doesn't exist) + // Delete ServicePoints for other businesses try { queryExecute(" - DELETE FROM ServicePoints WHERE ServicePointBusinessID != :keepID + DELETE FROM ServicePoints WHERE BusinessID != :keepID ", { keepID: keepBusinessID }, { datasource: "payfrit" }); response.steps.append("Deleted service points from other businesses"); } catch (any e) { response.steps.append("Skipped service points (table may not exist)"); } - // Delete Stations for other businesses (skip if table doesn't exist) + // Delete Stations for other businesses try { queryExecute(" - DELETE FROM Stations WHERE StationBusinessID != :keepID + DELETE FROM Stations WHERE BusinessID != :keepID ", { keepID: keepBusinessID }, { datasource: "payfrit" }); response.steps.append("Deleted stations from other businesses"); } catch (any e) { response.steps.append("Skipped stations (table may not exist)"); } + // Delete beacon-business mappings for other businesses + try { + queryExecute(" + DELETE FROM lt_BeaconsID_BusinessesID WHERE BusinessID != :keepID + ", { keepID: keepBusinessID }, { datasource: "payfrit" }); + response.steps.append("Deleted beacon mappings for other businesses"); + } catch (any e) { + response.steps.append("Skipped beacon mappings (table may not exist)"); + } + // Finally delete the businesses themselves queryExecute(" - DELETE FROM Businesses WHERE BusinessID != :keepID + DELETE FROM Businesses WHERE ID != :keepID ", { keepID: keepBusinessID }, { datasource: "payfrit" }); response.steps.append("Deleted " & arrayLen(deletedBusinesses) & " businesses"); // Get beacon status qBeacons = queryExecute(" - SELECT lt.BeaconID, b.BeaconUUID, lt.BusinessID, biz.BusinessName, lt.ServicePointID - FROM lt_Beacon_Businesses_ServicePoints lt - JOIN Beacons b ON b.BeaconID = lt.BeaconID - JOIN Businesses biz ON biz.BusinessID = lt.BusinessID + SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID, + b.UUID, biz.Name AS BusinessName, sp.Name AS ServicePointName + FROM ServicePoints sp + JOIN Beacons b ON b.ID = sp.BeaconID + JOIN Businesses biz ON biz.ID = sp.BusinessID + WHERE sp.BeaconID IS NOT NULL ", {}, { datasource: "payfrit" }); beacons = []; for (i = 1; i <= qBeacons.recordCount; i++) { arrayAppend(beacons, { "BeaconID": qBeacons.BeaconID[i], - "UUID": qBeacons.BeaconUUID[i], + "UUID": qBeacons.UUID[i], "BusinessID": qBeacons.BusinessID[i], "BusinessName": qBeacons.BusinessName[i], - "ServicePointID": qBeacons.ServicePointID[i] + "ServicePointID": qBeacons.ServicePointID[i], + "ServicePointName": qBeacons.ServicePointName[i] }); } diff --git a/api/admin/cleanupOrphanItem.cfm b/api/admin/cleanupOrphanItem.cfm index 36b3076..4637990 100644 --- a/api/admin/cleanupOrphanItem.cfm +++ b/api/admin/cleanupOrphanItem.cfm @@ -7,9 +7,9 @@ param name="url.action" default="check"; // "check" or "deactivate" // Check the item first qItem = queryExecute(" - SELECT ItemID, ItemName, ItemParentItemID, ItemIsActive, ItemIsCollapsible + SELECT ID, Name, ParentItemID, IsActive, IsCollapsible FROM Items - WHERE ItemID = :itemId + WHERE ID = :itemId ", { itemId: url.itemId }); if (qItem.recordCount == 0) { @@ -19,25 +19,25 @@ if (qItem.recordCount == 0) { // Get all children (direct only for display) qChildren = queryExecute(" - SELECT ItemID, ItemName + SELECT ID, Name FROM Items - WHERE ItemParentItemID = :itemId + WHERE ParentItemID = :itemId ", { itemId: url.itemId }); childList = []; for (row in qChildren) { - arrayAppend(childList, { "ItemID": row.ItemID, "ItemName": row.ItemName }); + arrayAppend(childList, { "ItemID": row.ID, "Name": row.Name }); } result = { "OK": true, "ACTION": url.action, "ITEM": { - "ItemID": qItem.ItemID, - "ItemName": qItem.ItemName, - "ItemParentItemID": qItem.ItemParentItemID, - "ItemIsActive": qItem.ItemIsActive, - "ItemIsCollapsible": qItem.ItemIsCollapsible + "ItemID": qItem.ID, + "Name": qItem.Name, + "ParentItemID": qItem.ParentItemID, + "IsActive": qItem.IsActive, + "IsCollapsible": qItem.IsCollapsible }, "HAS_CHILDREN": qChildren.recordCount > 0, "CHILD_COUNT": qChildren.recordCount, @@ -48,14 +48,14 @@ if (url.action == "deactivate") { // Deactivate children first queryExecute(" UPDATE Items - SET ItemIsActive = 0 - WHERE ItemParentItemID = :itemId + SET IsActive = 0 + WHERE ParentItemID = :itemId ", { itemId: url.itemId }); // Then deactivate the parent queryExecute(" UPDATE Items - SET ItemIsActive = 0 + SET IsActive = 0 WHERE ItemID = :itemId ", { itemId: url.itemId }); diff --git a/api/admin/clearCarts.cfm b/api/admin/clearCarts.cfm index 097b5cc..ba7cd14 100644 --- a/api/admin/clearCarts.cfm +++ b/api/admin/clearCarts.cfm @@ -5,13 +5,13 @@ // Delete cart orders (status 0) to reset for testing result = queryExecute(" DELETE FROM OrderLineItems - WHERE OrderLineItemOrderID IN ( - SELECT OrderID FROM Orders WHERE OrderStatusID = 0 + WHERE OrderID IN ( + SELECT ID FROM Orders WHERE StatusID = 0 ) ", {}, { datasource = "payfrit" }); result2 = queryExecute(" - DELETE FROM Orders WHERE OrderStatusID = 0 + DELETE FROM Orders WHERE StatusID = 0 ", {}, { datasource = "payfrit" }); writeOutput(serializeJSON({ diff --git a/api/admin/clearLocalCoffee.cfm b/api/admin/clearLocalCoffee.cfm index 9f3a021..da77556 100644 --- a/api/admin/clearLocalCoffee.cfm +++ b/api/admin/clearLocalCoffee.cfm @@ -10,27 +10,27 @@ try { businessIDs = [38, 39, 40, 41, 42]; for (bizID in businessIDs) { - // Delete ItemTemplateLinks for items belonging to this business + // Delete lt_ItemID_TemplateItemID for items belonging to this business queryExecute(" - DELETE itl FROM ItemTemplateLinks itl - INNER JOIN Items i ON i.ItemID = itl.ItemID - WHERE i.ItemBusinessID = :bizID + DELETE itl FROM lt_ItemID_TemplateItemID itl + INNER JOIN Items i ON i.ID = itl.ItemID + WHERE i.BusinessID = :bizID ", { bizID: bizID }, { datasource: "payfrit" }); // Delete Items - queryExecute("DELETE FROM Items WHERE ItemBusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" }); + queryExecute("DELETE FROM Items WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" }); // Delete Categories - queryExecute("DELETE FROM Categories WHERE CategoryBusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" }); + queryExecute("DELETE FROM Categories WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" }); // Delete Hours - queryExecute("DELETE FROM Hours WHERE HoursBusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" }); + queryExecute("DELETE FROM Hours WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" }); // Delete Addresses linked to this business - queryExecute("DELETE FROM Addresses WHERE AddressBusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" }); + queryExecute("DELETE FROM Addresses WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" }); // Delete the Business itself - queryExecute("DELETE FROM Businesses WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" }); + queryExecute("DELETE FROM Businesses WHERE ID = :bizID", { bizID: bizID }, { datasource: "payfrit" }); response.steps.append("Deleted business " & bizID & " and all related data"); } diff --git a/api/admin/closeAllChats.cfm b/api/admin/closeAllChats.cfm index 476d4fa..237f710 100644 --- a/api/admin/closeAllChats.cfm +++ b/api/admin/closeAllChats.cfm @@ -5,9 +5,9 @@ try { result = queryExecute(" UPDATE Tasks - SET TaskCompletedOn = NOW() + SET CompletedOn = NOW() WHERE TaskTypeID = 2 - AND TaskCompletedOn IS NULL + AND CompletedOn IS NULL ", {}, { datasource: "payfrit" }); affected = result.recordCount ?: 0; diff --git a/api/admin/copyDrinksToBigDeans.cfm b/api/admin/copyDrinksToBigDeans.cfm index 40bb89d..091d1ff 100644 --- a/api/admin/copyDrinksToBigDeans.cfm +++ b/api/admin/copyDrinksToBigDeans.cfm @@ -15,24 +15,24 @@ try { // First, check if Big Dean's has a Beverages/Drinks category qExistingCat = queryExecute(" - SELECT CategoryID, CategoryName FROM Categories - WHERE CategoryBusinessID = :bizId AND (CategoryName LIKE '%Drink%' OR CategoryName LIKE '%Beverage%') + SELECT ID, Name FROM Categories + WHERE BusinessID = :bizId AND (Name LIKE '%Drink%' OR Name LIKE '%Beverage%') ", { bizId: bigDeansBusinessId }, { datasource: "payfrit" }); if (qExistingCat.recordCount > 0) { drinksCategoryId = qExistingCat.CategoryID; - response["CategoryNote"] = "Using existing category: " & qExistingCat.CategoryName; + response["CategoryNote"] = "Using existing category: " & qExistingCat.Name; } else { // Create a new Beverages category for Big Dean's qMaxCat = queryExecute("SELECT COALESCE(MAX(CategoryID), 0) + 1 as nextId FROM Categories", {}, { datasource: "payfrit" }); drinksCategoryId = qMaxCat.nextId; qMaxSort = queryExecute(" - SELECT COALESCE(MAX(CategorySortOrder), 0) + 1 as nextSort FROM Categories WHERE CategoryBusinessID = :bizId + SELECT COALESCE(MAX(SortOrder), 0) + 1 as nextSort FROM Categories WHERE BusinessID = :bizId ", { bizId: bigDeansBusinessId }, { datasource: "payfrit" }); queryExecute(" - INSERT INTO Categories (CategoryID, CategoryBusinessID, CategoryParentCategoryID, CategoryName, CategorySortOrder, CategoryAddedOn) + INSERT INTO Categories (CategoryID, BusinessID, ParentCategoryID, Name, SortOrder, AddedOn) VALUES (:catId, :bizId, 0, 'Beverages', :sortOrder, NOW()) ", { catId: drinksCategoryId, @@ -61,8 +61,8 @@ try { for (drink in drinks) { // Check if item already exists qExists = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemBusinessID = :bizId AND ItemName = :name AND ItemCategoryID = :catId + SELECT ID FROM Items + WHERE BusinessID = :bizId AND Name = :name AND CategoryID = :catId ", { bizId: bigDeansBusinessId, name: drink.name, catId: drinksCategoryId }, { datasource: "payfrit" }); if (qExists.recordCount == 0) { @@ -72,10 +72,10 @@ try { queryExecute(" INSERT INTO Items ( - ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID, - ItemName, ItemDescription, ItemPrice, ItemIsActive, - ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection, - ItemAddedOn + ItemID, BusinessID, CategoryID, ParentItemID, + Name, Description, Price, IsActive, + SortOrder, IsCollapsible, RequiresChildSelection, + AddedOn ) VALUES ( :itemId, :bizId, :catId, 0, :name, :desc, :price, 1, @@ -103,10 +103,10 @@ try { qMaxOpt = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" }); queryExecute(" INSERT INTO Items ( - ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID, - ItemName, ItemDescription, ItemPrice, ItemIsActive, - ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault, - ItemAddedOn + ItemID, BusinessID, CategoryID, ParentItemID, + Name, Description, Price, IsActive, + SortOrder, IsCollapsible, IsCheckedByDefault, + AddedOn ) VALUES ( :itemId, :bizId, 0, :parentId, :name, '', 0, 1, diff --git a/api/admin/createBeacons.cfm b/api/admin/createBeacons.cfm index 475efd9..bb49b55 100644 --- a/api/admin/createBeacons.cfm +++ b/api/admin/createBeacons.cfm @@ -20,69 +20,74 @@ try { uuid = beaconUUIDs[i]; // Check if beacon exists - qB = queryExecute("SELECT BeaconID FROM Beacons WHERE BeaconUUID = :uuid", { uuid: uuid }, { datasource: "payfrit" }); + qB = queryExecute("SELECT ID FROM Beacons WHERE UUID = :uuid", { uuid: uuid }, { datasource: "payfrit" }); if (qB.recordCount == 0) { - queryExecute("INSERT INTO Beacons (BeaconUUID, BeaconBusinessID) VALUES (:uuid, :bizID)", { uuid: uuid, bizID: lazyDaisyID }, { datasource: "payfrit" }); + queryExecute("INSERT INTO Beacons (UUID, BusinessID) VALUES (:uuid, :bizID)", { uuid: uuid, bizID: lazyDaisyID }, { datasource: "payfrit" }); qNew = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" }); beaconID = qNew.id; response.steps.append("Created beacon " & beaconID & " with UUID: " & uuid); } else { - beaconID = qB.BeaconID; + beaconID = qB.ID; response.steps.append("Beacon exists: " & beaconID & " with UUID: " & uuid); } } // Get service point Table 1 qSP = queryExecute(" - SELECT ServicePointID FROM ServicePoints - WHERE ServicePointBusinessID = :bizID AND ServicePointName = 'Table 1' + SELECT ID FROM ServicePoints + WHERE BusinessID = :bizID AND Name = 'Table 1' ", { bizID: lazyDaisyID }, { datasource: "payfrit" }); if (qSP.recordCount == 0) { queryExecute(" - INSERT INTO ServicePoints (ServicePointBusinessID, ServicePointName, ServicePointTypeID) - VALUES (:bizID, 'Table 1', 1) + INSERT INTO ServicePoints (BusinessID, Name) + VALUES (:bizID, 'Table 1') ", { bizID: lazyDaisyID }, { datasource: "payfrit" }); qSP = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" }); servicePointID = qSP.id; response.steps.append("Created service point 'Table 1' (ID: " & servicePointID & ")"); } else { - servicePointID = qSP.ServicePointID; + servicePointID = qSP.ID; response.steps.append("Found service point 'Table 1' (ID: " & servicePointID & ")"); } - // Get all beacons and map them - qBeacons = queryExecute("SELECT BeaconID, BeaconUUID FROM Beacons", {}, { datasource: "payfrit" }); + // Assign all beacons to the Table 1 service point + qBeacons = queryExecute("SELECT ID, UUID FROM Beacons WHERE BusinessID = :bizID", { bizID: lazyDaisyID }, { datasource: "payfrit" }); for (i = 1; i <= qBeacons.recordCount; i++) { - beaconID = qBeacons.BeaconID[i]; + beaconID = qBeacons.ID[i]; - // Delete old mapping if exists - queryExecute("DELETE FROM lt_Beacon_Businesses_ServicePoints WHERE BeaconID = :beaconID", { beaconID: beaconID }, { datasource: "payfrit" }); - - // Create new mapping + // Unassign this beacon from any existing service point queryExecute(" - INSERT INTO lt_Beacon_Businesses_ServicePoints (BeaconID, BusinessID, ServicePointID) - VALUES (:beaconID, :bizID, :spID) + UPDATE ServicePoints SET BeaconID = NULL, AssignedByUserID = NULL + WHERE BeaconID = :beaconID + ", { beaconID: beaconID }, { datasource: "payfrit" }); + + // Assign beacon to Table 1 service point + queryExecute(" + UPDATE ServicePoints SET BeaconID = :beaconID, AssignedByUserID = 1 + WHERE ID = :spID AND BusinessID = :bizID ", { beaconID: beaconID, bizID: lazyDaisyID, spID: servicePointID }, { datasource: "payfrit" }); - response.steps.append("Mapped beacon " & beaconID & " to Lazy Daisy, Table 1"); + response.steps.append("Assigned beacon " & beaconID & " to Table 1"); } // Get final status qFinal = queryExecute(" - SELECT lt.BeaconID, b.BeaconUUID, lt.BusinessID, biz.BusinessName, lt.ServicePointID, sp.ServicePointName - FROM lt_Beacon_Businesses_ServicePoints lt - JOIN Beacons b ON b.BeaconID = lt.BeaconID - JOIN Businesses biz ON biz.BusinessID = lt.BusinessID - LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID + SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID, + b.Name AS BeaconName, b.UUID, sp.Name AS ServicePointName, + biz.Name AS BusinessName + FROM ServicePoints sp + JOIN Beacons b ON b.ID = sp.BeaconID + JOIN Businesses biz ON biz.ID = sp.BusinessID + WHERE sp.BeaconID IS NOT NULL ", {}, { datasource: "payfrit" }); beacons = []; for (i = 1; i <= qFinal.recordCount; i++) { arrayAppend(beacons, { "BeaconID": qFinal.BeaconID[i], - "UUID": qFinal.BeaconUUID[i], + "UUID": qFinal.UUID[i], "BusinessID": qFinal.BusinessID[i], "BusinessName": qFinal.BusinessName[i], "ServicePointID": qFinal.ServicePointID[i], diff --git a/api/admin/createChatMessagesTable.cfm b/api/admin/createChatMessagesTable.cfm index 7183532..a641e6b 100644 --- a/api/admin/createChatMessagesTable.cfm +++ b/api/admin/createChatMessagesTable.cfm @@ -5,11 +5,11 @@ try { // Create ChatMessages table queryExecute(" CREATE TABLE IF NOT EXISTS ChatMessages ( - MessageID INT AUTO_INCREMENT PRIMARY KEY, + ID INT AUTO_INCREMENT PRIMARY KEY, TaskID INT NOT NULL, SenderUserID INT NOT NULL, SenderType ENUM('customer', 'worker') NOT NULL, - MessageText TEXT NOT NULL, + MessageBody TEXT NOT NULL, IsRead TINYINT(1) DEFAULT 0, CreatedOn DATETIME DEFAULT NOW(), @@ -21,13 +21,13 @@ try { // Also add a "Chat" category if it doesn't exist for business 17 existing = queryExecute(" - SELECT TaskCategoryID FROM TaskCategories - WHERE TaskCategoryBusinessID = 17 AND TaskCategoryName = 'Chat' + SELECT ID FROM TaskCategories + WHERE BusinessID = 17 AND Name = 'Chat' ", {}, { datasource: "payfrit" }); if (existing.recordCount == 0) { queryExecute(" - INSERT INTO TaskCategories (TaskCategoryBusinessID, TaskCategoryName, TaskCategoryColor) + INSERT INTO TaskCategories (BusinessID, Name, Color) VALUES (17, 'Chat', '##2196F3') ", {}, { datasource: "payfrit" }); } diff --git a/api/admin/createMenusTable.cfm b/api/admin/createMenusTable.cfm index c93596e..129302c 100644 --- a/api/admin/createMenusTable.cfm +++ b/api/admin/createMenusTable.cfm @@ -32,47 +32,47 @@ try { queryExecute(" CREATE TABLE Menus ( MenuID INT AUTO_INCREMENT PRIMARY KEY, - MenuBusinessID INT NOT NULL, - MenuName VARCHAR(100) NOT NULL, - MenuDescription VARCHAR(500) NULL, - MenuDaysActive INT NOT NULL DEFAULT 127, - MenuStartTime TIME NULL, - MenuEndTime TIME NULL, - MenuSortOrder INT NOT NULL DEFAULT 0, - MenuIsActive TINYINT NOT NULL DEFAULT 1, - MenuAddedOn DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - INDEX idx_menus_business (MenuBusinessID), - INDEX idx_menus_active (MenuBusinessID, MenuIsActive) + BusinessID INT NOT NULL, + Name VARCHAR(100) NOT NULL, + Description VARCHAR(500) NULL, + DaysActive INT NOT NULL DEFAULT 127, + StartTime TIME NULL, + EndTime TIME NULL, + SortOrder INT NOT NULL DEFAULT 0, + IsActive TINYINT NOT NULL DEFAULT 1, + AddedOn DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_menus_business (BusinessID), + INDEX idx_menus_active (BusinessID, IsActive) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ", {}, { datasource: "payfrit" }); response["OK"] = true; response["MESSAGE"] = "Menus table created successfully"; response["SCHEMA"] = { - "MenuDaysActive": "Bitmask: 1=Sun, 2=Mon, 4=Tue, 8=Wed, 16=Thu, 32=Fri, 64=Sat (127 = all days)" + "DaysActive": "Bitmask: 1=Sun, 2=Mon, 4=Tue, 8=Wed, 16=Thu, 32=Fri, 64=Sat (127 = all days)" }; } - // Check if CategoryMenuID column exists in Categories table + // Check if MenuID column exists in Categories table qCatCol = queryExecute(" SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'payfrit' AND TABLE_NAME = 'Categories' - AND COLUMN_NAME = 'CategoryMenuID' + AND COLUMN_NAME = 'MenuID' ", {}, { datasource: "payfrit" }); if (qCatCol.recordCount == 0) { - // Add CategoryMenuID column to Categories table + // Add MenuID column to Categories table queryExecute(" ALTER TABLE Categories - ADD COLUMN CategoryMenuID INT NULL DEFAULT NULL AFTER CategoryBusinessID, - ADD INDEX idx_categories_menu (CategoryMenuID) + ADD COLUMN MenuID INT NULL DEFAULT NULL AFTER BusinessID, + ADD INDEX idx_categories_menu (MenuID) ", {}, { datasource: "payfrit" }); response["CATEGORIES_UPDATED"] = true; - response["CATEGORIES_MESSAGE"] = "Added CategoryMenuID column to Categories table"; + response["CATEGORIES_MESSAGE"] = "Added MenuID column to Categories table"; } else { response["CATEGORIES_UPDATED"] = false; - response["CATEGORIES_MESSAGE"] = "CategoryMenuID column already exists"; + response["CATEGORIES_MESSAGE"] = "MenuID column already exists"; } } catch (any e) { diff --git a/api/admin/createParentBusiness.cfm b/api/admin/createParentBusiness.cfm index cec0003..a60325d 100644 --- a/api/admin/createParentBusiness.cfm +++ b/api/admin/createParentBusiness.cfm @@ -12,7 +12,7 @@ * * POST body: * { - * "BusinessName": "Century Casino", + * "Name": "Century Casino", * "UserID": 1, * "ChildBusinessIDs": [47, 48] // Optional: link existing businesses as children * } @@ -36,13 +36,13 @@ response = { "OK": false }; try { data = readJsonBody(); - BusinessName = structKeyExists(data, "BusinessName") ? trim(data.BusinessName) : ""; + Name = structKeyExists(data, "Name") ? trim(data.Name) : ""; UserID = structKeyExists(data, "UserID") ? val(data.UserID) : 0; ChildBusinessIDs = structKeyExists(data, "ChildBusinessIDs") && isArray(data.ChildBusinessIDs) ? data.ChildBusinessIDs : []; - if (!len(BusinessName)) { + if (!len(Name)) { response["ERROR"] = "missing_name"; - response["MESSAGE"] = "BusinessName is required"; + response["MESSAGE"] = "Name is required"; writeOutput(serializeJSON(response)); abort; } @@ -56,7 +56,7 @@ try { // Create minimal address record (just a placeholder) queryExecute(" - INSERT INTO Addresses (AddressLine1, AddressUserID, AddressTypeID, AddressAddedOn) + INSERT INTO Addresses (Line1, UserID, AddressTypeID, AddedOn) VALUES ('Parent Business - No Physical Location', :userID, 2, NOW()) ", { userID: UserID @@ -67,10 +67,10 @@ try { // Create parent business (no menu, no hours, just a shell) queryExecute(" - INSERT INTO Businesses (BusinessName, BusinessUserID, BusinessAddressID, BusinessParentBusinessID, BusinessDeliveryZipCodes, BusinessAddedOn) + INSERT INTO Businesses (Name, UserID, AddressID, ParentBusinessID, BusinessDeliveryZipCodes, AddedOn) VALUES (:name, :userId, :addressId, NULL, '', NOW()) ", { - name: BusinessName, + name: Name, userId: UserID, addressId: addressId }, { datasource = "payfrit" }); @@ -80,7 +80,7 @@ try { // Link address back to business queryExecute(" - UPDATE Addresses SET AddressBusinessID = :bizId WHERE AddressID = :addrId + UPDATE Addresses SET BusinessID = :bizId WHERE ID = :addrId ", { bizId: newBusinessID, addrId: addressId @@ -92,7 +92,7 @@ try { childID = val(childID); if (childID > 0) { queryExecute(" - UPDATE Businesses SET BusinessParentBusinessID = :parentId WHERE BusinessID = :childId + UPDATE Businesses SET ParentBusinessID = :parentId WHERE ID = :childId ", { parentId: newBusinessID, childId: childID @@ -103,7 +103,7 @@ try { response["OK"] = true; response["BusinessID"] = newBusinessID; - response["BusinessName"] = BusinessName; + response["Name"] = Name; response["MESSAGE"] = "Parent business created"; if (arrayLen(linkedChildren) > 0) { response["LinkedChildren"] = linkedChildren; diff --git a/api/admin/debugBigDeansDeactivated.cfm b/api/admin/debugBigDeansDeactivated.cfm index 02881ce..f77a444 100644 --- a/api/admin/debugBigDeansDeactivated.cfm +++ b/api/admin/debugBigDeansDeactivated.cfm @@ -9,22 +9,22 @@ bizId = 27; deactivatedIds = [11177, 11180, 11183, 11186, 11190, 11193, 11196, 11199, 11204, 11212, 11220, 11259]; qDeactivated = queryExecute(" - SELECT i.ItemID, i.ItemName, i.ItemParentItemID, i.ItemIsActive, i.ItemIsCollapsible, - (SELECT COUNT(*) FROM Items c WHERE c.ItemParentItemID = i.ItemID) as ChildCount, - (SELECT GROUP_CONCAT(c.ItemName) FROM Items c WHERE c.ItemParentItemID = i.ItemID) as Children + SELECT i.ID, i.Name, i.ParentItemID, i.IsActive, i.IsCollapsible, + (SELECT COUNT(*) FROM Items c WHERE c.ParentItemID = i.ID) as ChildCount, + (SELECT GROUP_CONCAT(c.Name) FROM Items c WHERE c.ParentItemID = i.ID) as Children FROM Items i - WHERE i.ItemID IN (:ids) - ORDER BY i.ItemID + WHERE i.ID IN (:ids) + ORDER BY i.ID ", { ids: { value: arrayToList(deactivatedIds), list: true } }, { datasource: "payfrit" }); items = []; for (row in qDeactivated) { arrayAppend(items, { - "ItemID": row.ItemID, - "ItemName": row.ItemName, - "ParentID": row.ItemParentItemID, - "IsActive": row.ItemIsActive, - "IsCollapsible": row.ItemIsCollapsible, + "ItemID": row.ID, + "Name": row.Name, + "ParentID": row.ParentItemID, + "IsActive": row.IsActive, + "IsCollapsible": row.IsCollapsible, "ChildCount": row.ChildCount, "Children": row.Children }); diff --git a/api/admin/debugBigDeansLinks.cfm b/api/admin/debugBigDeansLinks.cfm index 0ba3294..708d78e 100644 --- a/api/admin/debugBigDeansLinks.cfm +++ b/api/admin/debugBigDeansLinks.cfm @@ -9,24 +9,24 @@ bizId = 27; qLinks = queryExecute(" SELECT tl.ItemID as MenuItemID, - mi.ItemName as MenuItemName, - mi.ItemParentItemID, + mi.Name as MenuName, + mi.ParentItemID, tl.TemplateItemID, - t.ItemName as TemplateName, + t.Name as TemplateName, tl.SortOrder - FROM ItemTemplateLinks tl - JOIN Items mi ON mi.ItemID = tl.ItemID + FROM lt_ItemID_TemplateItemID tl + JOIN Items mi ON mi.ID = tl.ItemID JOIN Items t ON t.ItemID = tl.TemplateItemID - WHERE mi.ItemBusinessID = :bizId - ORDER BY mi.ItemParentItemID, mi.ItemName, tl.SortOrder + WHERE mi.BusinessID = :bizId + ORDER BY mi.ParentItemID, mi.Name, tl.SortOrder ", { bizId: bizId }, { datasource: "payfrit" }); links = []; for (row in qLinks) { arrayAppend(links, { "MenuItemID": row.MenuItemID, - "MenuItemName": row.MenuItemName, - "ParentItemID": row.ItemParentItemID, + "MenuName": row.MenuName, + "ParentItemID": row.ParentItemID, "TemplateItemID": row.TemplateItemID, "TemplateName": row.TemplateName }); @@ -34,20 +34,20 @@ for (row in qLinks) { // Get burgers specifically (parent = 11271) qBurgers = queryExecute(" - SELECT ItemID, ItemName FROM Items - WHERE ItemBusinessID = :bizId AND ItemParentItemID = 11271 AND ItemIsActive = 1 - ORDER BY ItemSortOrder + SELECT ID, Name FROM Items + WHERE BusinessID = :bizId AND ParentItemID = 11271 AND IsActive = 1 + ORDER BY SortOrder ", { bizId: bizId }, { datasource: "payfrit" }); burgers = []; for (row in qBurgers) { // Get templates for this burger qBurgerTemplates = queryExecute(" - SELECT tl.TemplateItemID, t.ItemName as TemplateName - FROM ItemTemplateLinks tl + SELECT tl.TemplateItemID, t.Name as TemplateName + FROM lt_ItemID_TemplateItemID tl JOIN Items t ON t.ItemID = tl.TemplateItemID WHERE tl.ItemID = :itemId - ", { itemId: row.ItemID }, { datasource: "payfrit" }); + ", { itemId: row.ID }, { datasource: "payfrit" }); templates = []; for (t in qBurgerTemplates) { @@ -55,8 +55,8 @@ for (row in qBurgers) { } arrayAppend(burgers, { - "ItemID": row.ItemID, - "ItemName": row.ItemName, + "ItemID": row.ID, + "Name": row.Name, "Templates": templates }); } diff --git a/api/admin/debugBigDeansMenu.cfm b/api/admin/debugBigDeansMenu.cfm index 749cfe2..884353e 100644 --- a/api/admin/debugBigDeansMenu.cfm +++ b/api/admin/debugBigDeansMenu.cfm @@ -9,38 +9,38 @@ businessID = 27; qCategories = queryExecute(" SELECT DISTINCT p.ItemID as CategoryID, - p.ItemName as CategoryName, - p.ItemSortOrder + p.Name as Name, + p.SortOrder FROM Items p - INNER JOIN Items c ON c.ItemParentItemID = p.ItemID - WHERE p.ItemBusinessID = :businessID - AND p.ItemParentItemID = 0 - AND p.ItemIsActive = 1 + INNER JOIN Items c ON c.ParentItemID = p.ItemID + WHERE p.BusinessID = :businessID + AND p.ParentItemID = 0 + AND p.IsActive = 1 AND NOT EXISTS ( - SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = p.ItemID + SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = p.ItemID ) - ORDER BY p.ItemSortOrder, p.ItemName + ORDER BY p.SortOrder, p.Name ", { businessID: businessID }); cats = []; for (c in qCategories) { arrayAppend(cats, { - "CategoryID": c.CategoryID, - "CategoryName": c.CategoryName + "CategoryID": c.ID, + "Name": c.Name }); } // Also check raw counts rawCount = queryExecute(" SELECT COUNT(*) as cnt FROM Items - WHERE ItemBusinessID = :bizId AND ItemParentItemID = 0 AND ItemIsActive = 1 + WHERE BusinessID = :bizId AND ParentItemID = 0 AND IsActive = 1 ", { bizId: businessID }); childrenCount = queryExecute(" - SELECT COUNT(DISTINCT c.ItemParentItemID) as cnt + SELECT COUNT(DISTINCT c.ParentItemID) as cnt FROM Items c - INNER JOIN Items p ON p.ItemID = c.ItemParentItemID - WHERE p.ItemBusinessID = :bizId AND p.ItemParentItemID = 0 + INNER JOIN Items p ON p.ItemID = c.ParentItemID + WHERE p.BusinessID = :bizId AND p.ParentItemID = 0 ", { bizId: businessID }); writeOutput(serializeJSON({ diff --git a/api/admin/debugBigDeansTemplates.cfm b/api/admin/debugBigDeansTemplates.cfm index b7011bb..35c2603 100644 --- a/api/admin/debugBigDeansTemplates.cfm +++ b/api/admin/debugBigDeansTemplates.cfm @@ -9,24 +9,24 @@ bizId = 27; qLinks = queryExecute(" SELECT tl.ItemID as MenuItemID, - mi.ItemName as MenuItemName, - mi.ItemParentItemID as MenuItemParentID, + mi.Name as MenuName, + mi.ParentItemID as MenuItemParentID, tl.TemplateItemID, - t.ItemName as TemplateName, - t.ItemIsActive as TemplateActive, + t.Name as TemplateName, + t.IsActive as TemplateActive, tl.SortOrder - FROM ItemTemplateLinks tl - JOIN Items mi ON mi.ItemID = tl.ItemID + FROM lt_ItemID_TemplateItemID tl + JOIN Items mi ON mi.ID = tl.ItemID JOIN Items t ON t.ItemID = tl.TemplateItemID - WHERE mi.ItemBusinessID = :bizId - ORDER BY mi.ItemName, tl.SortOrder + WHERE mi.BusinessID = :bizId + ORDER BY mi.Name, tl.SortOrder ", { bizId: bizId }, { datasource: "payfrit" }); links = []; for (row in qLinks) { arrayAppend(links, { "MenuItemID": row.MenuItemID, - "MenuItemName": row.MenuItemName, + "MenuName": row.MenuName, "MenuItemParentID": row.MenuItemParentID, "TemplateItemID": row.TemplateItemID, "TemplateName": row.TemplateName, @@ -37,20 +37,20 @@ for (row in qLinks) { // Get all templates that exist for this business qTemplates = queryExecute(" - SELECT ItemID, ItemName, ItemIsActive, ItemParentItemID + SELECT ID, Name, IsActive, ParentItemID FROM Items - WHERE ItemBusinessID = :bizId - AND ItemIsCollapsible = 1 - ORDER BY ItemName + WHERE BusinessID = :bizId + AND IsCollapsible = 1 + ORDER BY Name ", { bizId: bizId }, { datasource: "payfrit" }); templates = []; for (row in qTemplates) { arrayAppend(templates, { - "ItemID": row.ItemID, - "ItemName": row.ItemName, - "IsActive": row.ItemIsActive, - "ParentID": row.ItemParentItemID + "ItemID": row.ID, + "Name": row.Name, + "IsActive": row.IsActive, + "ParentID": row.ParentItemID }); } diff --git a/api/admin/debugBigDeansTemplates2.cfm b/api/admin/debugBigDeansTemplates2.cfm index b40b05e..b61e913 100644 --- a/api/admin/debugBigDeansTemplates2.cfm +++ b/api/admin/debugBigDeansTemplates2.cfm @@ -5,67 +5,67 @@ bizId = 27; -// Check the template items themselves (IDs from ItemTemplateLinks) +// Check the template items themselves (IDs from lt_ItemID_TemplateItemID) templateIds = "11267, 11251, 11246, 11224, 11233, 11230, 11240, 11243, 11237, 11227"; qTemplates = queryExecute(" - SELECT ItemID, ItemName, ItemIsCollapsible, ItemIsActive, ItemParentItemID, ItemBusinessID + SELECT ID, Name, IsCollapsible, IsActive, ParentItemID, BusinessID FROM Items - WHERE ItemID IN (#templateIds#) - ORDER BY ItemName + WHERE ID IN (#templateIds#) + ORDER BY Name ", {}, { datasource: "payfrit" }); templates = []; for (row in qTemplates) { arrayAppend(templates, { - "ItemID": row.ItemID, - "ItemName": row.ItemName, - "IsCollapsible": row.ItemIsCollapsible, - "IsActive": row.ItemIsActive, - "ParentID": row.ItemParentItemID, - "BusinessID": row.ItemBusinessID + "ItemID": row.ID, + "Name": row.Name, + "IsCollapsible": row.IsCollapsible, + "IsActive": row.IsActive, + "ParentID": row.ParentItemID, + "BusinessID": row.BusinessID }); } // Also check what other templates might exist for burgers -// Look for items that are in ItemTemplateLinks but NOT linked to burgers +// Look for items that are in lt_ItemID_TemplateItemID but NOT linked to burgers qMissingTemplates = queryExecute(" - SELECT DISTINCT t.ItemID, t.ItemName, t.ItemIsCollapsible, t.ItemIsActive + SELECT DISTINCT t.ItemID, t.Name, t.IsCollapsible, t.IsActive FROM Items t - WHERE t.ItemBusinessID = :bizId - AND t.ItemParentItemID = 0 + WHERE t.BusinessID = :bizId + AND t.ParentItemID = 0 AND t.ItemID NOT IN ( - SELECT i.ItemID FROM Items i WHERE i.ItemBusinessID = :bizId AND i.ItemCategoryID > 0 + SELECT i.ID FROM Items i WHERE i.BusinessID = :bizId AND i.CategoryID > 0 ) - AND EXISTS (SELECT 1 FROM Items child WHERE child.ItemParentItemID = t.ItemID) - ORDER BY t.ItemName + AND EXISTS (SELECT 1 FROM Items child WHERE child.ParentItemID = t.ItemID) + ORDER BY t.Name ", { bizId: bizId }, { datasource: "payfrit" }); potentialTemplates = []; for (row in qMissingTemplates) { arrayAppend(potentialTemplates, { - "ItemID": row.ItemID, - "ItemName": row.ItemName, - "IsCollapsible": row.ItemIsCollapsible, - "IsActive": row.ItemIsActive + "ItemID": row.ID, + "Name": row.Name, + "IsCollapsible": row.IsCollapsible, + "IsActive": row.IsActive }); } // What templates SHOULD burgers have? Let's see all templates used by ANY item qAllTemplateUsage = queryExecute(" - SELECT t.ItemID, t.ItemName, COUNT(tl.ItemID) as UsageCount - FROM ItemTemplateLinks tl + SELECT t.ItemID, t.Name, COUNT(tl.ItemID) as UsageCount + FROM lt_ItemID_TemplateItemID tl JOIN Items t ON t.ItemID = tl.TemplateItemID - JOIN Items mi ON mi.ItemID = tl.ItemID AND mi.ItemBusinessID = :bizId - GROUP BY t.ItemID, t.ItemName - ORDER BY t.ItemName + JOIN Items mi ON mi.ID = tl.ItemID AND mi.BusinessID = :bizId + GROUP BY t.ItemID, t.Name + ORDER BY t.Name ", { bizId: bizId }, { datasource: "payfrit" }); allTemplates = []; for (row in qAllTemplateUsage) { arrayAppend(allTemplates, { - "TemplateID": row.ItemID, - "TemplateName": row.ItemName, + "TemplateID": row.ID, + "TemplateName": row.Name, "UsageCount": row.UsageCount }); } diff --git a/api/admin/debugBigDeansTemplates3.cfm b/api/admin/debugBigDeansTemplates3.cfm index a5526b0..66b34ca 100644 --- a/api/admin/debugBigDeansTemplates3.cfm +++ b/api/admin/debugBigDeansTemplates3.cfm @@ -7,41 +7,41 @@ bizId = 27; // Get the template items themselves qTemplates = queryExecute(" - SELECT ItemID, ItemName, ItemIsCollapsible, ItemIsActive, ItemParentItemID, ItemBusinessID + SELECT ID, Name, IsCollapsible, IsActive, ParentItemID, BusinessID FROM Items - WHERE ItemID IN (11267, 11251, 11246, 11224, 11233, 11230, 11240, 11243, 11237, 11227) - ORDER BY ItemName + WHERE ID IN (11267, 11251, 11246, 11224, 11233, 11230, 11240, 11243, 11237, 11227) + ORDER BY Name ", {}, { datasource: "payfrit" }); templates = []; for (row in qTemplates) { arrayAppend(templates, { - "ItemID": row.ItemID, - "ItemName": row.ItemName, - "IsCollapsible": row.ItemIsCollapsible, - "IsActive": row.ItemIsActive, - "ParentID": row.ItemParentItemID, - "BusinessID": row.ItemBusinessID + "ItemID": row.ID, + "Name": row.Name, + "IsCollapsible": row.IsCollapsible, + "IsActive": row.IsActive, + "ParentID": row.ParentItemID, + "BusinessID": row.BusinessID }); } // What templates are used by burgers vs all items? qBurgerLinks = queryExecute(" - SELECT mi.ItemID, mi.ItemName, GROUP_CONCAT(t.ItemName ORDER BY tl.SortOrder) as Templates + SELECT mi.ID, mi.Name, GROUP_CONCAT(t.Name ORDER BY tl.SortOrder) as Templates FROM Items mi - JOIN ItemTemplateLinks tl ON tl.ItemID = mi.ItemID + JOIN lt_ItemID_TemplateItemID tl ON tl.ItemID = mi.ID JOIN Items t ON t.ItemID = tl.TemplateItemID - WHERE mi.ItemBusinessID = :bizId - AND mi.ItemParentItemID = 11271 - GROUP BY mi.ItemID, mi.ItemName - ORDER BY mi.ItemName + WHERE mi.BusinessID = :bizId + AND mi.ParentItemID = 11271 + GROUP BY mi.ID, mi.Name + ORDER BY mi.Name ", { bizId: bizId }, { datasource: "payfrit" }); burgerLinks = []; for (row in qBurgerLinks) { arrayAppend(burgerLinks, { - "ItemID": row.ItemID, - "ItemName": row.ItemName, + "ItemID": row.ID, + "Name": row.Name, "Templates": row.Templates }); } @@ -49,20 +49,20 @@ for (row in qBurgerLinks) { // Also check: are there templates that SHOULD be linked to burgers? // (e.g., Add Cheese, etc.) qCheeseTemplate = queryExecute(" - SELECT ItemID, ItemName, ItemParentItemID, ItemIsActive + SELECT ID, Name, ParentItemID, IsActive FROM Items - WHERE ItemBusinessID = :bizId - AND ItemName LIKE '%Cheese%' - ORDER BY ItemName + WHERE BusinessID = :bizId + AND Name LIKE '%Cheese%' + ORDER BY Name ", { bizId: bizId }, { datasource: "payfrit" }); cheeseItems = []; for (row in qCheeseTemplate) { arrayAppend(cheeseItems, { - "ItemID": row.ItemID, - "ItemName": row.ItemName, - "ParentID": row.ItemParentItemID, - "IsActive": row.ItemIsActive + "ItemID": row.ID, + "Name": row.Name, + "ParentID": row.ParentItemID, + "IsActive": row.IsActive }); } diff --git a/api/admin/debugBusinesses.cfm b/api/admin/debugBusinesses.cfm index 7f7e302..e4251ed 100644 --- a/api/admin/debugBusinesses.cfm +++ b/api/admin/debugBusinesses.cfm @@ -26,36 +26,36 @@ + @@ -39,7 +39,7 @@ @@ -47,12 +47,12 @@ -// Switch all beacons from one business to another +// Switch beacon mapping from one business to another via join table. +// Beacons.BusinessID (owner) is NOT touched. fromBiz = 17; // In-N-Out toBiz = 27; // Big Dean's +// Remove mapping for source business queryExecute(" - UPDATE lt_Beacon_Businesses_ServicePoints - SET BusinessID = :toBiz - WHERE BusinessID = :fromBiz + DELETE FROM lt_BeaconsID_BusinessesID + WHERE BusinessID = :fromBiz +", { fromBiz: fromBiz }, { datasource: "payfrit" }); + +// Add mapping for target business (for beacons owned by source) +queryExecute(" + INSERT INTO lt_BeaconsID_BusinessesID (BeaconID, BusinessID) + SELECT ID, :toBiz FROM Beacons WHERE BusinessID = :fromBiz + ON DUPLICATE KEY UPDATE ID = ID ", { toBiz: toBiz, fromBiz: fromBiz }, { datasource: "payfrit" }); +// Clear ServicePoints.BeaconID for source business (no longer valid) +queryExecute(" + UPDATE ServicePoints + SET BeaconID = NULL, AssignedByUserID = NULL + WHERE BusinessID = :fromBiz AND BeaconID IS NOT NULL +", { fromBiz: fromBiz }, { datasource: "payfrit" }); + // Get current state q = queryExecute(" - SELECT lt.*, b.BusinessName - FROM lt_Beacon_Businesses_ServicePoints lt - JOIN Businesses b ON b.BusinessID = lt.BusinessID + SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID, + b.Name AS BeaconName, biz.Name AS BusinessName, + sp.Name AS ServicePointName + FROM ServicePoints sp + JOIN Beacons b ON b.ID = sp.BeaconID + JOIN Businesses biz ON biz.ID = sp.BusinessID + WHERE sp.BeaconID IS NOT NULL ", {}, { datasource: "payfrit" }); rows = []; for (row in q) { - arrayAppend(rows, { - "BeaconID": row.BeaconID, - "BusinessID": row.BusinessID, - "BusinessName": row.BusinessName, - "ServicePointID": row.ServicePointID - }); + arrayAppend(rows, { + "BeaconID": row.BeaconID, + "BeaconName": row.BeaconName, + "BusinessID": row.BusinessID, + "BusinessName": row.BusinessName, + "ServicePointID": row.ServicePointID, + "ServicePointName": row.ServicePointName + }); } writeOutput(serializeJSON({ - "OK": true, - "MESSAGE": "Switched beacons from BusinessID #fromBiz# to #toBiz#", - "MAPPINGS": rows + "OK": true, + "MESSAGE": "Switched beacons from BusinessID #fromBiz# to #toBiz#", + "MAPPINGS": rows })); diff --git a/api/admin/testTaskInsert.cfm b/api/admin/testTaskInsert.cfm index f3ee706..3784189 100644 --- a/api/admin/testTaskInsert.cfm +++ b/api/admin/testTaskInsert.cfm @@ -7,10 +7,10 @@ qTask = queryExecute(" - SELECT TaskID, TaskTypeID, TaskClaimedByUserID, TaskCompletedOn + SELECT ID, TaskTypeID, ClaimedByUserID, CompletedOn FROM Tasks - WHERE TaskID = 57 + WHERE ID = 57 ", [], { datasource: "payfrit" }); writeOutput(serializeJSON({ "OK": true, - "TaskID": qTask.TaskID, + "TaskID": qTask.ID, "TaskTypeID": qTask.TaskTypeID, - "TaskClaimedByUserID": qTask.TaskClaimedByUserID, - "TaskCompletedOn": qTask.TaskCompletedOn + "ClaimedByUserID": qTask.ClaimedByUserID, + "CompletedOn": qTask.CompletedOn })); diff --git a/api/admin/updateBeaconMapping.cfm b/api/admin/updateBeaconMapping.cfm index 6669685..5c5221a 100644 --- a/api/admin/updateBeaconMapping.cfm +++ b/api/admin/updateBeaconMapping.cfm @@ -3,50 +3,65 @@ -// Update Beacon 2 to point to In-N-Out (BusinessID 17) +// Update beacon mapping via join table. Owner (Beacons.BusinessID) is NOT changed. beaconId = 2; +oldBusinessId = 37; // previous mapping newBusinessId = 17; +// Remove old mapping queryExecute(" - UPDATE lt_Beacon_Businesses_ServicePoints - SET BusinessID = :newBizId - WHERE BeaconID = :beaconId -", { newBizId: newBusinessId, beaconId: beaconId }, { datasource: "payfrit" }); + DELETE FROM lt_BeaconsID_BusinessesID + WHERE BeaconID = :beaconId AND BusinessID = :oldBizId +", { beaconId: beaconId, oldBizId: oldBusinessId }, { datasource: "payfrit" }); + +// Add new mapping +queryExecute(" + INSERT INTO lt_BeaconsID_BusinessesID (BeaconID, BusinessID) + VALUES (:beaconId, :newBizId) + ON DUPLICATE KEY UPDATE ID = ID +", { beaconId: beaconId, newBizId: newBusinessId }, { datasource: "payfrit" }); + +// Clear ServicePoints.BeaconID for old business where this beacon was assigned +queryExecute(" + UPDATE ServicePoints + SET BeaconID = NULL, AssignedByUserID = NULL + WHERE BeaconID = :beaconId AND BusinessID = :oldBizId +", { beaconId: beaconId, oldBizId: oldBusinessId }, { datasource: "payfrit" }); // Get current state q = queryExecute(" - SELECT - b.BeaconID, - b.BeaconUUID, - b.BeaconName, - lt.BusinessID, - lt.ServicePointID, - biz.BusinessName, - sp.ServicePointName - FROM Beacons b - LEFT JOIN lt_Beacon_Businesses_ServicePoints lt ON lt.BeaconID = b.BeaconID - LEFT JOIN Businesses biz ON biz.BusinessID = lt.BusinessID - LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID - WHERE b.BeaconIsActive = 1 - ORDER BY b.BeaconID + SELECT + b.ID AS BeaconID, + b.UUID, + b.Name AS BeaconName, + b.BusinessID AS BeaconBusinessID, + sp.ID AS ServicePointID, + sp.Name AS ServicePointName, + sp.BusinessID AS ServicePointBusinessID, + biz.Name AS BusinessName + FROM Beacons b + LEFT JOIN ServicePoints sp ON sp.BeaconID = b.ID + LEFT JOIN Businesses biz ON biz.ID = b.BusinessID + WHERE b.IsActive = 1 + ORDER BY b.ID ", {}, { datasource: "payfrit" }); rows = []; for (row in q) { - arrayAppend(rows, { - "BeaconID": row.BeaconID, - "BeaconUUID": row.BeaconUUID, - "BeaconName": row.BeaconName ?: "", - "BusinessID": row.BusinessID ?: 0, - "BusinessName": row.BusinessName ?: "", - "ServicePointID": row.ServicePointID ?: 0, - "ServicePointName": row.ServicePointName ?: "" - }); + arrayAppend(rows, { + "BeaconID": row.BeaconID, + "UUID": row.UUID, + "BeaconName": row.BeaconName, + "BeaconBusinessID": row.BeaconBusinessID, + "BusinessName": row.BusinessName, + "ServicePointID": row.ServicePointID ?: 0, + "ServicePointName": row.ServicePointName ?: "" + }); } writeOutput(serializeJSON({ - "OK": true, - "MESSAGE": "Updated beacon #beaconId# to BusinessID #newBusinessId#", - "BEACONS": rows + "OK": true, + "MESSAGE": "Updated beacon #beaconId# to BusinessID #newBusinessId#", + "BEACONS": rows })); diff --git a/api/admin/updateBigDeans.cfm b/api/admin/updateBigDeans.cfm index fcb672a..94558bb 100644 --- a/api/admin/updateBigDeans.cfm +++ b/api/admin/updateBigDeans.cfm @@ -6,72 +6,68 @@ // Update Big Dean's business info businessId = 27; -// Big Dean's actual address and hours -address = "1615 Ocean Front Walk, Santa Monica, CA 90401"; +// Big Dean's actual info phone = "(310) 393-2666"; hours = "Mon-Thu: 11am-10pm, Fri-Sat: 11am-11pm, Sun: 11am-10pm"; try { - // First get column names from INFORMATION_SCHEMA - cols = queryExecute(" - SELECT COLUMN_NAME - FROM INFORMATION_SCHEMA.COLUMNS - WHERE TABLE_SCHEMA = 'payfrit' AND TABLE_NAME = 'Businesses' - ORDER BY ORDINAL_POSITION - "); - - colNames = []; - for (c in cols) { - arrayAppend(colNames, c.COLUMN_NAME); - } - - // Check if we have the columns we need - hasAddress = arrayFindNoCase(colNames, "BusinessAddress") > 0; - hasPhone = arrayFindNoCase(colNames, "BusinessPhone") > 0; - hasHours = arrayFindNoCase(colNames, "BusinessHours") > 0; - - // Add columns if missing - if (!hasAddress) { - queryExecute("ALTER TABLE Businesses ADD COLUMN BusinessAddress VARCHAR(255)"); - } - if (!hasPhone) { - queryExecute("ALTER TABLE Businesses ADD COLUMN BusinessPhone VARCHAR(50)"); - } - if (!hasHours) { - queryExecute("ALTER TABLE Businesses ADD COLUMN BusinessHours VARCHAR(255)"); - } - - // Update with new info + // Update phone and hours on Businesses table queryExecute(" UPDATE Businesses - SET BusinessAddress = :address, - BusinessPhone = :phone, - BusinessHours = :hours - WHERE BusinessID = :bizId + SET Phone = :phone, + Hours = :hours + WHERE ID = :bizId ", { - address: address, phone: phone, hours: hours, bizId: businessId - }); + }, { datasource: "payfrit" }); + + // Update or insert address in Addresses table + qAddr = queryExecute(" + SELECT ID FROM Addresses + WHERE BusinessID = :bizId AND IsDeleted = 0 + LIMIT 1 + ", { bizId: businessId }, { datasource: "payfrit" }); + + if (qAddr.recordCount > 0) { + queryExecute(" + UPDATE Addresses + SET Line1 = :line1, City = :city, ZIPCode = :zip + WHERE ID = :addrId + ", { + line1: "1615 Ocean Front Walk", + city: "Santa Monica", + zip: "90401", + addrId: qAddr.ID + }, { datasource: "payfrit" }); + } else { + queryExecute(" + INSERT INTO Addresses (BusinessID, UserID, AddressTypeID, Line1, City, ZIPCode, AddedOn) + VALUES (:bizId, 0, 'business', :line1, :city, :zip, NOW()) + ", { + bizId: businessId, + line1: "1615 Ocean Front Walk", + city: "Santa Monica", + zip: "90401" + }, { datasource: "payfrit" }); + } // Get updated record updated = queryExecute(" - SELECT BusinessID, BusinessName, BusinessAddress, BusinessPhone, BusinessHours + SELECT ID, Name, Phone, Hours FROM Businesses - WHERE BusinessID = :bizId - ", { bizId: businessId }); + WHERE ID = :bizId + ", { bizId: businessId }, { datasource: "payfrit" }); writeOutput(serializeJSON({ "OK": true, "MESSAGE": "Updated Big Dean's info", - "COLUMNS_EXISTED": { "address": hasAddress, "phone": hasPhone, "hours": hasHours }, "BUSINESS": { - "BusinessID": updated.BusinessID, - "BusinessName": updated.BusinessName, - "BusinessAddress": updated.BusinessAddress, - "BusinessPhone": updated.BusinessPhone, - "BusinessHours": updated.BusinessHours + "BusinessID": updated.ID, + "Name": updated.Name, + "Phone": updated.Phone, + "Hours": updated.Hours } })); diff --git a/api/assignments/delete.cfm b/api/assignments/delete.cfm index 2f6d9be..5c75628 100644 --- a/api/assignments/delete.cfm +++ b/api/assignments/delete.cfm @@ -34,28 +34,20 @@ if (!structKeyExists(request,"BusinessID") || !isNumeric(request.BusinessID) || /* ---------- INPUT ---------- */ data = readJsonBody(); -if ( - !structKeyExists(data,"lt_Beacon_Businesses_ServicePointID") - || !isNumeric(data.lt_Beacon_Businesses_ServicePointID) - || int(data.lt_Beacon_Businesses_ServicePointID) LTE 0 -){ - apiAbort({OK=false,ERROR="missing_lt_Beacon_Businesses_ServicePointID"}); +if (!structKeyExists(data,"ServicePointID") || !isNumeric(data.ServicePointID) || int(data.ServicePointID) LTE 0){ + apiAbort({OK=false,ERROR="missing_ServicePointID"}); } -RelID = int(data.lt_Beacon_Businesses_ServicePointID); +ServicePointID = int(data.ServicePointID); - + - SELECT - lt_Beacon_Businesses_ServicePointID, - BeaconID, - ServicePointID - FROM lt_Beacon_Businesses_ServicePoints - WHERE lt_Beacon_Businesses_ServicePointID = - - AND BusinessID = - + SELECT ID, BeaconID + FROM ServicePoints + WHERE ID = + AND BusinessID = + AND BeaconID IS NOT NULL LIMIT 1 @@ -63,28 +55,28 @@ RelID = int(data.lt_Beacon_Businesses_ServicePointID); #serializeJSON({ "OK"=false, "ERROR"="not_found", - "lt_Beacon_Businesses_ServicePointID"=RelID, + "ServicePointID"=ServicePointID, "BusinessID"=(request.BusinessID & "") })# - + + + - DELETE FROM lt_Beacon_Businesses_ServicePoints - WHERE lt_Beacon_Businesses_ServicePointID = - - AND BusinessID = - - LIMIT 1 + UPDATE ServicePoints + SET BeaconID = NULL, + AssignedByUserID = NULL + WHERE ID = + AND BusinessID = #serializeJSON({ "OK"=true, "ERROR"="", - "ACTION"="deleted", - "lt_Beacon_Businesses_ServicePointID"=RelID, - "BeaconID"=qFind.BeaconID, - "ServicePointID"=qFind.ServicePointID, + "ACTION"="unassigned", + "ServicePointID"=ServicePointID, + "BeaconID"=removedBeaconID, "BusinessID"=(request.BusinessID & "") })# diff --git a/api/assignments/list.cfm b/api/assignments/list.cfm index ab2083d..6b3c97a 100644 --- a/api/assignments/list.cfm +++ b/api/assignments/list.cfm @@ -17,32 +17,29 @@ if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || SELECT - lt.lt_Beacon_Businesses_ServicePointID, - lt.BeaconID, - lt.BusinessID, - lt.ServicePointID, - lt.lt_Beacon_Businesses_ServicePointNotes, - b.BeaconName, - b.BeaconUUID, - sp.ServicePointName - FROM lt_Beacon_Businesses_ServicePoints lt - JOIN Beacons b ON b.BeaconID = lt.BeaconID - LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID - WHERE lt.BusinessID = - ORDER BY b.BeaconName, sp.ServicePointName + sp.ID AS ServicePointID, + sp.BeaconID, + sp.BusinessID, + sp.AssignedByUserID, + b.Name AS BeaconName, + b.UUID, + sp.Name AS ServicePointName + FROM ServicePoints sp + JOIN Beacons b ON b.ID = sp.BeaconID + WHERE sp.BusinessID = + AND sp.BeaconID IS NOT NULL + ORDER BY b.Name, sp.Name diff --git a/api/assignments/save.cfm b/api/assignments/save.cfm index 44b58d9..735db83 100644 --- a/api/assignments/save.cfm +++ b/api/assignments/save.cfm @@ -26,11 +26,6 @@ function readJsonBody(){ return parsed; } -function normStr(v){ - if (isNull(v)) return ""; - return trim(toString(v)); -} - /* ---------- AUTH CONTEXT ---------- */ if (!structKeyExists(request,"BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0){ apiAbort({OK=false,ERROR="no_business_selected"}); @@ -48,43 +43,45 @@ if (!structKeyExists(data,"ServicePointID") || !isNumeric(data.ServicePointID) | BeaconID = int(data.BeaconID); ServicePointID = int(data.ServicePointID); -Notes = ""; -if (structKeyExists(data,"Notes")){ - Notes = left(normStr(data.Notes), 255); -} - + - SELECT BusinessID, BusinessParentBusinessID + SELECT ID, ParentBusinessID FROM Businesses - WHERE BusinessID = + WHERE ID = LIMIT 1 - SELECT BeaconID - FROM Beacons - WHERE BeaconID = + SELECT b.ID + FROM Beacons b + WHERE b.ID = AND ( - BeaconBusinessID = - - OR BeaconBusinessID = + b.BusinessID = + + OR b.BusinessID = + OR EXISTS ( + SELECT 1 FROM lt_BeaconsID_BusinessesID lt + WHERE lt.BeaconID = b.ID + AND lt.BusinessID = + ) ) LIMIT 1 - #serializeJSON({OK=false,ERROR="beacon_not_found_for_business"})# + #serializeJSON({OK=false,ERROR="beacon_not_allowed"})# - SELECT ServicePointID + SELECT ID FROM ServicePoints - WHERE ServicePointID = - AND ServicePointBusinessID = + WHERE ID = + AND BusinessID = LIMIT 1 @@ -92,14 +89,12 @@ if (structKeyExists(data,"Notes")){ - - + - SELECT lt_Beacon_Businesses_ServicePointID - FROM lt_Beacon_Businesses_ServicePoints - WHERE BusinessID = + SELECT ID + FROM ServicePoints + WHERE ID = AND BeaconID = - AND ServicePointID = LIMIT 1 @@ -107,31 +102,19 @@ if (structKeyExists(data,"Notes")){ - + - INSERT INTO lt_Beacon_Businesses_ServicePoints - (BusinessID, BeaconID, ServicePointID, - lt_Beacon_Businesses_ServicePointAssignedByUserID, - lt_Beacon_Businesses_ServicePointNotes) - VALUES - ( - , - , - , - , - - ) - - - - SELECT LAST_INSERT_ID() AS NewID + UPDATE ServicePoints + SET BeaconID = , + AssignedByUserID = + WHERE ID = + AND BusinessID = #serializeJSON({ "OK"=true, - "ACTION"="inserted", - "lt_Beacon_Businesses_ServicePointID"=qID.NewID, - "BeaconID"=BeaconID, + "ACTION"="assigned", "ServicePointID"=ServicePointID, + "BeaconID"=BeaconID, "BusinessID"=(request.BusinessID & "") })# diff --git a/api/auth/completeProfile.cfm b/api/auth/completeProfile.cfm index 53221ad..0ab846f 100644 --- a/api/auth/completeProfile.cfm +++ b/api/auth/completeProfile.cfm @@ -71,9 +71,9 @@ try { // Check if email is already used by another verified account qEmailCheck = queryExecute(" - SELECT UserID FROM Users - WHERE UserEmailAddress = :email - AND UserIsEmailVerified = 1 + SELECT ID FROM Users + WHERE EmailAddress = :email + AND IsEmailVerified = 1 AND UserID != :userId LIMIT 1 ", { @@ -87,19 +87,19 @@ try { // Get current user UUID for email confirmation link qUser = queryExecute(" - SELECT UserUUID FROM Users WHERE UserID = :userId + SELECT UUID FROM Users WHERE ID = :userId ", { userId: { value: userId, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); // Update user profile AND mark account as verified/active // This completes the signup process queryExecute(" UPDATE Users - SET UserFirstName = :firstName, - UserLastName = :lastName, - UserEmailAddress = :email, - UserIsEmailVerified = 0, - UserIsContactVerified = 1, - UserIsActive = 1 + SET FirstName = :firstName, + LastName = :lastName, + EmailAddress = :email, + IsEmailVerified = 0, + IsContactVerified = 1, + IsActive = 1 WHERE UserID = :userId ", { firstName: { value: firstName, cfsqltype: "cf_sql_varchar" }, @@ -109,7 +109,7 @@ try { }, { datasource: "payfrit" }); // Send confirmation email (non-blocking - don't fail if mail fails) - confirmLink = "https://biz.payfrit.com/confirm_email.cfm?UUID=" & qUser.UserUUID; + confirmLink = "https://biz.payfrit.com/confirm_email.cfm?UUID=" & qUser.UUID; emailBody = "

Welcome to Payfrit, #firstName#!

Please click the link below to confirm your email address:

diff --git a/api/auth/login.cfm b/api/auth/login.cfm index 63a0fb2..c5c4926 100644 --- a/api/auth/login.cfm +++ b/api/auth/login.cfm @@ -12,7 +12,7 @@ { "username": "...", "password": "..." } OUTPUT (JSON): - { OK:true, ERROR:"", UserID:123, UserFirstName:"...", Token:"..." } + { OK:true, ERROR:"", UserID:123, FirstName:"...", Token:"..." } Uses existing UserTokens table: TokenID (auto), UserID, Token, CreatedAt (DEFAULT CURRENT_TIMESTAMP) @@ -55,16 +55,16 @@ if (!len(username) || !len(password)) { try { q = queryExecute( " - SELECT UserID, UserFirstName + SELECT ID, FirstName FROM Users WHERE ( - (UserEmailAddress = ?) OR - (UserContactNumber = ?) + (EmailAddress = ?) OR + (ContactNumber = ?) ) - AND UserPassword = ? - AND UserIsEmailVerified = 1 - AND UserIsContactVerified > 0 + AND Password = ? + AND IsEmailVerified = 1 + AND IsContactVerified > 0 LIMIT 1 ", [ @@ -84,7 +84,7 @@ try { queryExecute( "INSERT INTO UserTokens (UserID, Token) VALUES (?, ?)", [ - { value = q.UserID, cfsqltype = "cf_sql_integer" }, + { value = q.ID, cfsqltype = "cf_sql_integer" }, { value = token, cfsqltype = "cf_sql_varchar" } ], { datasource = "payfrit" } @@ -92,15 +92,15 @@ try { // Optional: also set session for browser tools lock timeout="15" throwontimeout="yes" type="exclusive" scope="session" { - session.UserID = q.UserID; + session.UserID = q.ID; } - request.UserID = q.UserID; + request.UserID = q.ID; writeOutput(serializeJSON({ "OK": true, "ERROR": "", - "UserID": q.UserID, - "UserFirstName": q.UserFirstName, + "UserID": q.ID, + "FirstName": q.FirstName, "Token": token })); abort; diff --git a/api/auth/loginOTP.cfm b/api/auth/loginOTP.cfm index 0241c56..5151238 100644 --- a/api/auth/loginOTP.cfm +++ b/api/auth/loginOTP.cfm @@ -53,10 +53,10 @@ try { // Find verified account with this phone qUser = queryExecute(" - SELECT UserID, UserUUID + SELECT ID, UUID FROM Users - WHERE UserContactNumber = :phone - AND UserIsContactVerified = 1 + WHERE ContactNumber = :phone + AND IsContactVerified = 1 LIMIT 1 ", { phone: { value: phone, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); @@ -65,14 +65,14 @@ try { } // If user has no UUID (legacy account), generate one - userUUID = qUser.UserUUID; + userUUID = qUser.UUID; if (!len(trim(userUUID))) { userUUID = replace(createUUID(), "-", "", "all"); queryExecute(" - UPDATE Users SET UserUUID = :uuid WHERE UserID = :userId + UPDATE Users SET UUID = :uuid WHERE UserID = :userId ", { uuid: { value: userUUID, cfsqltype: "cf_sql_varchar" }, - userId: { value: qUser.UserID, cfsqltype: "cf_sql_integer" } + userId: { value: qUser.ID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); } @@ -80,11 +80,11 @@ try { otp = generateOTP(); queryExecute(" UPDATE Users - SET UserMobileVerifyCode = :otp + SET MobileVerifyCode = :otp WHERE UserID = :userId ", { otp: { value: otp, cfsqltype: "cf_sql_varchar" }, - userId: { value: qUser.UserID, cfsqltype: "cf_sql_integer" } + userId: { value: qUser.ID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); // Send OTP via Twilio (skip on dev server) diff --git a/api/auth/profile.cfm b/api/auth/profile.cfm index 2c9a6b8..e4fa5cb 100644 --- a/api/auth/profile.cfm +++ b/api/auth/profile.cfm @@ -59,13 +59,13 @@ if (cgi.REQUEST_METHOD == "GET") { try { qUser = queryExecute(" SELECT - UserID, - UserFirstName, - UserLastName, - UserEmailAddress, - UserContactNumber + ID, + FirstName, + LastName, + EmailAddress, + ContactNumber FROM Users - WHERE UserID = :userId + WHERE ID = :userId LIMIT 1 ", { userId: { value = userId, cfsqltype = "cf_sql_integer" } }); @@ -76,11 +76,11 @@ if (cgi.REQUEST_METHOD == "GET") { writeOutput(serializeJSON({ "OK": true, "USER": { - "UserID": qUser.UserID, - "FirstName": qUser.UserFirstName ?: "", - "LastName": qUser.UserLastName ?: "", - "Email": qUser.UserEmailAddress ?: "", - "Phone": qUser.UserContactNumber ?: "" + "UserID": qUser.ID, + "FirstName": qUser.FirstName ?: "", + "LastName": qUser.LastName ?: "", + "Email": qUser.EmailAddress ?: "", + "Phone": qUser.ContactNumber ?: "" } })); abort; @@ -110,12 +110,12 @@ if (cgi.REQUEST_METHOD == "POST") { params = { userId: { value = userId, cfsqltype = "cf_sql_integer" } }; if (structKeyExists(data, "firstName")) { - arrayAppend(updates, "UserFirstName = :firstName"); + arrayAppend(updates, "FirstName = :firstName"); params.firstName = { value = data.firstName, cfsqltype = "cf_sql_varchar" }; } if (structKeyExists(data, "lastName")) { - arrayAppend(updates, "UserLastName = :lastName"); + arrayAppend(updates, "LastName = :lastName"); params.lastName = { value = data.lastName, cfsqltype = "cf_sql_varchar" }; } @@ -133,13 +133,13 @@ if (cgi.REQUEST_METHOD == "POST") { // Return updated profile qUser = queryExecute(" SELECT - UserID, - UserFirstName, - UserLastName, - UserEmailAddress, - UserContactNumber + ID, + FirstName, + LastName, + EmailAddress, + ContactNumber FROM Users - WHERE UserID = :userId + WHERE ID = :userId LIMIT 1 ", { userId: { value = userId, cfsqltype = "cf_sql_integer" } }); @@ -147,11 +147,11 @@ if (cgi.REQUEST_METHOD == "POST") { "OK": true, "MESSAGE": "Profile updated", "USER": { - "UserID": qUser.UserID, - "FirstName": qUser.UserFirstName ?: "", - "LastName": qUser.UserLastName ?: "", - "Email": qUser.UserEmailAddress ?: "", - "Phone": qUser.UserContactNumber ?: "" + "UserID": qUser.ID, + "FirstName": qUser.FirstName ?: "", + "LastName": qUser.LastName ?: "", + "Email": qUser.EmailAddress ?: "", + "Phone": qUser.ContactNumber ?: "" } })); abort; diff --git a/api/auth/sendOTP.cfm b/api/auth/sendOTP.cfm index c558d60..b10e36c 100644 --- a/api/auth/sendOTP.cfm +++ b/api/auth/sendOTP.cfm @@ -57,12 +57,12 @@ try { // Check if phone already has a COMPLETE account (verified AND has profile info) // An account is only "complete" if they have a first name (meaning they finished signup) qExisting = queryExecute(" - SELECT UserID, UserUUID, UserFirstName + SELECT ID, UUID, FirstName FROM Users - WHERE UserContactNumber = :phone - AND UserIsContactVerified > 0 - AND UserFirstName IS NOT NULL - AND LENGTH(TRIM(UserFirstName)) > 0 + WHERE ContactNumber = :phone + AND IsContactVerified > 0 + AND FirstName IS NOT NULL + AND LENGTH(TRIM(FirstName)) > 0 LIMIT 1 ", { phone: { value: phone, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); @@ -73,10 +73,10 @@ try { // Check for incomplete account with this phone (verified but no profile, OR unverified) // These accounts can be reused for signup qIncomplete = queryExecute(" - SELECT UserID, UserUUID + SELECT ID, UUID FROM Users - WHERE UserContactNumber = :phone - AND (UserIsContactVerified = 0 OR UserFirstName IS NULL OR LENGTH(TRIM(UserFirstName)) = 0) + WHERE ContactNumber = :phone + AND (IsContactVerified = 0 OR FirstName IS NULL OR LENGTH(TRIM(FirstName)) = 0) LIMIT 1 ", { phone: { value: phone, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); @@ -85,12 +85,12 @@ try { if (qIncomplete.recordCount > 0) { // Update existing incomplete record with new OTP and reset for re-registration - userUUID = qIncomplete.UserUUID; + userUUID = qIncomplete.UUID; queryExecute(" UPDATE Users - SET UserMobileVerifyCode = :otp, - UserIsContactVerified = 0, - UserIsActive = 0 + SET MobileVerifyCode = :otp, + IsContactVerified = 0, + IsActive = 0 WHERE UserID = :userId ", { otp: { value: otp, cfsqltype: "cf_sql_varchar" }, @@ -101,15 +101,15 @@ try { userUUID = replace(createUUID(), "-", "", "all"); queryExecute(" INSERT INTO Users ( - UserContactNumber, - UserUUID, - UserMobileVerifyCode, - UserIsContactVerified, - UserIsEmailVerified, - UserIsActive, - UserAddedOn, - UserPassword, - UserPromoCode + ContactNumber, + UUID, + MobileVerifyCode, + IsContactVerified, + IsEmailVerified, + IsActive, + AddedOn, + Password, + PromoCode ) VALUES ( :phone, :uuid, diff --git a/api/auth/validateToken.cfm b/api/auth/validateToken.cfm index a6d587e..ca668a7 100644 --- a/api/auth/validateToken.cfm +++ b/api/auth/validateToken.cfm @@ -32,10 +32,10 @@ try { } // Look up the token - qToken = queryTimed(" - SELECT ut.UserID, u.UserFirstName, u.UserLastName + qToken = queryExecute(" + SELECT ut.UserID, u.FirstName, u.LastName FROM UserTokens ut - JOIN Users u ON u.UserID = ut.UserID + JOIN Users u ON u.ID = ut.UserID WHERE ut.Token = :token LIMIT 1 ", { token: { value: token, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); @@ -47,20 +47,19 @@ try { userID = qToken.UserID; // Determine if user is a worker (has any active employment) - qWorker = queryTimed(" + qWorker = queryExecute(" SELECT COUNT(*) as cnt - FROM lt_Users_Businesses_Employees - WHERE UserID = :userID AND EmployeeIsActive = 1 + FROM Employees + WHERE UserID = :userID AND IsActive = 1 ", { userID: { value: userID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); userType = qWorker.cnt > 0 ? "worker" : "customer"; - logPerf(); apiAbort({ "OK": true, "UserID": userID, "UserType": userType, - "UserName": trim(qToken.UserFirstName & " " & qToken.UserLastName) + "UserName": trim(qToken.FirstName & " " & qToken.LastName) }); } catch (any e) { diff --git a/api/auth/verifyLoginOTP.cfm b/api/auth/verifyLoginOTP.cfm index 67f6261..df7082f 100644 --- a/api/auth/verifyLoginOTP.cfm +++ b/api/auth/verifyLoginOTP.cfm @@ -9,7 +9,7 @@ * * POST: { "uuid": "...", "otp": "123456" } * - * Returns: { OK: true, UserID: 123, Token: "...", UserFirstName: "..." } + * Returns: { OK: true, UserID: 123, Token: "...", FirstName: "..." } */ function apiAbort(required struct payload) { @@ -46,21 +46,21 @@ try { // Find verified user with matching UUID and OTP (or magic OTP) if (isMagicOTP) { qUser = queryExecute(" - SELECT UserID, UserFirstName, UserLastName + SELECT ID, FirstName, LastName FROM Users - WHERE UserUUID = :uuid - AND UserIsContactVerified = 1 + WHERE UUID = :uuid + AND IsContactVerified = 1 LIMIT 1 ", { uuid: { value: userUUID, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); } else { qUser = queryExecute(" - SELECT UserID, UserFirstName, UserLastName + SELECT ID, FirstName, LastName FROM Users - WHERE UserUUID = :uuid - AND UserMobileVerifyCode = :otp - AND UserIsContactVerified = 1 + WHERE UUID = :uuid + AND MobileVerifyCode = :otp + AND IsContactVerified = 1 LIMIT 1 ", { uuid: { value: userUUID, cfsqltype: "cf_sql_varchar" }, @@ -71,7 +71,7 @@ try { if (qUser.recordCount == 0) { // Check if UUID exists but OTP is wrong qCheck = queryExecute(" - SELECT UserID FROM Users WHERE UserUUID = :uuid AND UserIsContactVerified = 1 + SELECT ID FROM Users WHERE UUID = :uuid AND IsContactVerified = 1 ", { uuid: { value: userUUID, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); if (qCheck.recordCount > 0) { @@ -84,24 +84,24 @@ try { // Clear the OTP (one-time use) queryExecute(" UPDATE Users - SET UserMobileVerifyCode = '' + SET MobileVerifyCode = '' WHERE UserID = :userId - ", { userId: { value: qUser.UserID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); + ", { userId: { value: qUser.ID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); // Create auth token token = replace(createUUID(), "-", "", "all"); queryExecute(" INSERT INTO UserTokens (UserID, Token) VALUES (:userId, :token) ", { - userId: { value: qUser.UserID, cfsqltype: "cf_sql_integer" }, + userId: { value: qUser.ID, cfsqltype: "cf_sql_integer" }, token: { value: token, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); writeOutput(serializeJSON({ "OK": true, - "UserID": qUser.UserID, + "UserID": qUser.ID, "Token": token, - "UserFirstName": qUser.UserFirstName ?: "" + "FirstName": qUser.FirstName ?: "" })); } catch (any e) { diff --git a/api/auth/verifyOTP.cfm b/api/auth/verifyOTP.cfm index 13bdab1..c9154b8 100644 --- a/api/auth/verifyOTP.cfm +++ b/api/auth/verifyOTP.cfm @@ -49,21 +49,21 @@ try { // Find unverified user with matching UUID and OTP (or magic OTP) if (isMagicOTP) { qUser = queryExecute(" - SELECT UserID, UserFirstName, UserLastName, UserEmailAddress, UserIsEmailVerified + SELECT ID, FirstName, LastName, EmailAddress, IsEmailVerified FROM Users - WHERE UserUUID = :uuid - AND UserIsContactVerified = 0 + WHERE UUID = :uuid + AND IsContactVerified = 0 LIMIT 1 ", { uuid: { value: userUUID, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); } else { qUser = queryExecute(" - SELECT UserID, UserFirstName, UserLastName, UserEmailAddress, UserIsEmailVerified + SELECT ID, FirstName, LastName, EmailAddress, IsEmailVerified FROM Users - WHERE UserUUID = :uuid - AND UserMobileVerifyCode = :otp - AND UserIsContactVerified = 0 + WHERE UUID = :uuid + AND MobileVerifyCode = :otp + AND IsContactVerified = 0 LIMIT 1 ", { uuid: { value: userUUID, cfsqltype: "cf_sql_varchar" }, @@ -74,7 +74,7 @@ try { if (qUser.recordCount == 0) { // Check if UUID exists but OTP is wrong qCheck = queryExecute(" - SELECT UserID FROM Users WHERE UserUUID = :uuid AND UserIsContactVerified = 0 + SELECT ID FROM Users WHERE UUID = :uuid AND IsContactVerified = 0 ", { uuid: { value: userUUID, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); if (qCheck.recordCount > 0) { @@ -88,30 +88,30 @@ try { // Account will be marked verified after profile completion queryExecute(" UPDATE Users - SET UserMobileVerifyCode = '' + SET MobileVerifyCode = '' WHERE UserID = :userId - ", { userId: { value: qUser.UserID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); + ", { userId: { value: qUser.ID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); // Create auth token (needed for completeProfile call) token = replace(createUUID(), "-", "", "all"); queryExecute(" INSERT INTO UserTokens (UserID, Token) VALUES (:userId, :token) ", { - userId: { value: qUser.UserID, cfsqltype: "cf_sql_integer" }, + userId: { value: qUser.ID, cfsqltype: "cf_sql_integer" }, token: { value: token, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); // Check if profile is complete (has first name) // For new signups, this will always be true - needsProfile = !len(trim(qUser.UserFirstName)); + needsProfile = !len(trim(qUser.FirstName)); writeOutput(serializeJSON({ "OK": true, - "UserID": qUser.UserID, + "UserID": qUser.ID, "Token": token, "NeedsProfile": needsProfile, - "UserFirstName": qUser.UserFirstName ?: "", - "IsEmailVerified": qUser.UserIsEmailVerified == 1 + "FirstName": qUser.FirstName ?: "", + "IsEmailVerified": qUser.IsEmailVerified == 1 })); } catch (any e) { diff --git a/api/beacons/delete.cfm b/api/beacons/delete.cfm index eccf40b..52fe7dc 100644 --- a/api/beacons/delete.cfm +++ b/api/beacons/delete.cfm @@ -49,17 +49,31 @@ beaconId = int(data.BeaconID); UPDATE Beacons - SET BeaconIsActive = 0 - WHERE BeaconID = - AND BeaconBusinessID = + SET IsActive = 0 + WHERE ID = + AND ( + BusinessID = + OR ID IN ( + SELECT lt.BeaconID FROM lt_BeaconsID_BusinessesID lt + WHERE lt.BeaconID = + AND lt.BusinessID = + ) + ) - SELECT BeaconID, BeaconIsActive + SELECT ID, IsActive FROM Beacons - WHERE BeaconID = - AND BeaconBusinessID = + WHERE ID = + AND ( + BusinessID = + OR EXISTS ( + SELECT 1 FROM lt_BeaconsID_BusinessesID lt + WHERE lt.BeaconID = + AND lt.BusinessID = + ) + ) LIMIT 1 diff --git a/api/beacons/get.cfm b/api/beacons/get.cfm index 766817d..8111185 100644 --- a/api/beacons/get.cfm +++ b/api/beacons/get.cfm @@ -37,14 +37,21 @@ beaconId = int(data.BeaconID); SELECT - BeaconID, - BeaconBusinessID, - BeaconName, - BeaconUUID, - BeaconIsActive - FROM Beacons - WHERE BeaconID = - AND BeaconBusinessID = + b.ID, + b.BusinessID, + b.Name, + b.UUID, + b.IsActive + FROM Beacons b + WHERE b.ID = + AND ( + b.BusinessID = + OR EXISTS ( + SELECT 1 FROM lt_BeaconsID_BusinessesID lt + WHERE lt.BeaconID = b.ID + AND lt.BusinessID = + ) + ) LIMIT 1 @@ -54,11 +61,11 @@ beaconId = int(data.BeaconID); #serializeJSON({ OK=true, ERROR="", BEACON=beacon })# diff --git a/api/beacons/getBusinessFromBeacon.cfm b/api/beacons/getBusinessFromBeacon.cfm index 4ba78db..25a8b3a 100644 --- a/api/beacons/getBusinessFromBeacon.cfm +++ b/api/beacons/getBusinessFromBeacon.cfm @@ -33,10 +33,10 @@ beaconId = int(data.BeaconID); - SELECT BeaconID, BeaconName, BeaconUUID, BeaconBusinessID + SELECT ID, Name, UUID, BusinessID FROM Beacons - WHERE BeaconID = - AND BeaconIsActive = 1 + WHERE ID = + AND IsActive = 1 LIMIT 1 @@ -45,20 +45,36 @@ beaconId = int(data.BeaconID); - + + SELECT + sp.BusinessID, + sp.ID AS ServicePointID, + biz.Name AS BusinessName, + biz.ParentBusinessID, + sp.Name AS ServicePointName + FROM ServicePoints sp + INNER JOIN Businesses biz ON biz.ID = sp.BusinessID + WHERE sp.BeaconID = + AND sp.IsActive = 1 + + UNION + SELECT lt.BusinessID, - lt.ServicePointID, - biz.BusinessName, - biz.BusinessParentBusinessID, - sp.ServicePointName - FROM lt_Beacon_Businesses_ServicePoints lt - INNER JOIN Businesses biz ON biz.BusinessID = lt.BusinessID - INNER JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID + 0 AS ServicePointID, + biz.Name AS BusinessName, + biz.ParentBusinessID, + '' AS ServicePointName + FROM lt_BeaconsID_BusinessesID lt + INNER JOIN Businesses biz ON biz.ID = lt.BusinessID WHERE lt.BeaconID = - AND sp.ServicePointIsActive = 1 - ORDER BY biz.BusinessParentBusinessID IS NULL DESC, biz.BusinessName ASC + AND lt.BusinessID NOT IN ( + SELECT sp2.BusinessID FROM ServicePoints sp2 + WHERE sp2.BeaconID = AND sp2.IsActive = 1 + ) + + ORDER BY ParentBusinessID IS NULL DESC, BusinessName ASC @@ -67,7 +83,7 @@ beaconId = int(data.BeaconID); SELECT COUNT(*) as cnt FROM Businesses - WHERE BusinessParentBusinessID = + WHERE ParentBusinessID = @@ -82,24 +98,24 @@ beaconId = int(data.BeaconID); - SELECT BusinessName, BusinessHeaderImageExtension + SELECT Name, HeaderImageExtension FROM Businesses - WHERE BusinessID = + WHERE ID = SELECT - BusinessID, - BusinessName, - BusinessParentBusinessID, - BusinessHeaderImageExtension + ID, + Name, + ParentBusinessID, + HeaderImageExtension FROM Businesses - WHERE BusinessParentBusinessID = - ORDER BY BusinessName ASC + WHERE ParentBusinessID = + ORDER BY Name ASC @@ -123,16 +139,16 @@ beaconId = int(data.BeaconID); "OK" = true, "ERROR" = "", "BEACON" = { - "BeaconID" = qBeacon.BeaconID, - "BeaconName" = qBeacon.BeaconName, - "UUID" = qBeacon.BeaconUUID + "BeaconID" = qBeacon.ID, + "Name" = qBeacon.Name, + "UUID" = qBeacon.UUID }, "BUSINESSES" = businesses, "BUSINESS" = arrayLen(businesses) GT 0 ? businesses[1] : {}, "SERVICEPOINT" = arrayLen(businesses) GT 0 ? { "ServicePointID" = businesses[1].ServicePointID, - "ServicePointName" = businesses[1].ServicePointName, - "ServicePointIsActive" = true + "Name" = businesses[1].ServicePointName, + "IsActive" = true } : {} }> @@ -140,8 +156,8 @@ beaconId = int(data.BeaconID); diff --git a/api/beacons/list.cfm b/api/beacons/list.cfm index 2aaf6a9..22a1623 100644 --- a/api/beacons/list.cfm +++ b/api/beacons/list.cfm @@ -56,30 +56,35 @@ if (structKeyExists(data, "onlyActive")) {
- SELECT - BeaconID, - BeaconBusinessID, - BeaconName, - BeaconUUID, - BeaconIsActive - FROM Beacons - WHERE BeaconBusinessID = + SELECT DISTINCT + b.ID, + b.BusinessID, + b.Name, + b.UUID, + b.IsActive + FROM Beacons b + WHERE ( + b.BusinessID = + OR b.ID IN ( + SELECT lt.BeaconID FROM lt_BeaconsID_BusinessesID lt + WHERE lt.BusinessID = + ) + ) - AND BeaconIsActive = 1 + AND b.IsActive = 1 - ORDER BY BeaconName, BeaconID + ORDER BY b.Name, b.ID - #serializeJSON({ OK=true, ERROR="", BusinessID=bizId, COUNT=arrayLen(beacons), BEACONS=beacons })# diff --git a/api/beacons/list_all.cfm b/api/beacons/list_all.cfm index 0d01104..54308ef 100644 --- a/api/beacons/list_all.cfm +++ b/api/beacons/list_all.cfm @@ -15,18 +15,18 @@ function apiAbort(obj) { SELECT - BeaconID, - BeaconUUID + ID, + UUID FROM Beacons - WHERE BeaconIsActive = 1 - ORDER BY BeaconID + WHERE IsActive = 1 + ORDER BY ID diff --git a/api/beacons/lookup.cfm b/api/beacons/lookup.cfm index 515cc98..3a41d7a 100644 --- a/api/beacons/lookup.cfm +++ b/api/beacons/lookup.cfm @@ -16,13 +16,13 @@ * { * UUID: "...", * BeaconID: int, - * BeaconName: string, + * Name: string, * BusinessID: int, - * BusinessName: string, + * Name: string, * ServicePointID: int, - * ServicePointName: string, + * Name: string, * ParentBusinessID: int (if applicable), - * ParentBusinessName: string (if applicable), + * ParentName: string (if applicable), * HasChildren: boolean * } * ] @@ -60,28 +60,28 @@ try { } // Query for matching beacons with business info - // Beacons link to ServicePoints via lt_Beacon_Businesses_ServicePoints + // Beacons resolve to businesses via: ServicePoints, join table, or owner qBeacons = queryExecute(" SELECT - b.BeaconID, - b.BeaconName, - b.BeaconUUID, - COALESCE(link.ServicePointID, 0) AS ServicePointID, - COALESCE(sp.ServicePointName, '') AS ServicePointName, - COALESCE(link.BusinessID, b.BeaconBusinessID) AS BusinessID, - biz.BusinessName, - biz.BusinessParentBusinessID, - parent.BusinessName AS ParentBusinessName, - (SELECT COUNT(*) FROM Businesses WHERE BusinessParentBusinessID = biz.BusinessID) AS ChildCount + b.ID, + b.Name, + b.UUID, + COALESCE(sp.ID, 0) AS ServicePointID, + COALESCE(sp.Name, '') AS Name, + COALESCE(sp.BusinessID, lt.BusinessID, b.BusinessID) AS BusinessID, + biz.Name, + biz.ParentBusinessID, + parent.Name AS ParentName, + (SELECT COUNT(*) FROM Businesses WHERE ParentBusinessID = biz.ID) AS ChildCount FROM Beacons b - LEFT JOIN lt_Beacon_Businesses_ServicePoints link ON b.BeaconID = link.BeaconID - LEFT JOIN ServicePoints sp ON link.ServicePointID = sp.ServicePointID - INNER JOIN Businesses biz ON COALESCE(link.BusinessID, b.BeaconBusinessID) = biz.BusinessID - LEFT JOIN Businesses parent ON biz.BusinessParentBusinessID = parent.BusinessID - WHERE b.BeaconUUID IN (:uuids) - AND b.BeaconIsActive = 1 - AND biz.BusinessIsDemo = 0 - AND biz.BusinessIsPrivate = 0 + LEFT JOIN ServicePoints sp ON sp.BeaconID = b.ID + LEFT JOIN lt_BeaconsID_BusinessesID lt ON lt.BeaconID = b.ID + INNER JOIN Businesses biz ON COALESCE(sp.BusinessID, lt.BusinessID, b.BusinessID) = biz.ID + LEFT JOIN Businesses parent ON biz.ParentBusinessID = parent.ID + WHERE b.UUID IN (:uuids) + AND b.IsActive = 1 + AND biz.IsDemo = 0 + AND biz.IsPrivate = 0 ", { uuids: { value: arrayToList(cleanUUIDs), cfsqltype: "cf_sql_varchar", list: true } }, { datasource: "payfrit" }); @@ -89,15 +89,15 @@ try { beacons = []; for (row in qBeacons) { arrayAppend(beacons, { - "UUID": row.BeaconUUID, - "BeaconID": row.BeaconID, - "BeaconName": row.BeaconName, + "UUID": row.UUID, + "BeaconID": row.ID, + "Name": row.Name, "BusinessID": row.BusinessID, - "BusinessName": row.BusinessName, + "Name": row.Name, "ServicePointID": row.ServicePointID, - "ServicePointName": row.ServicePointName, - "ParentBusinessID": val(row.BusinessParentBusinessID), - "ParentBusinessName": row.ParentBusinessName ?: "", + "Name": row.Name, + "ParentBusinessID": val(row.ParentBusinessID), + "ParentName": row.ParentName ?: "", "HasChildren": row.ChildCount > 0 }); } diff --git a/api/beacons/reassign_all.cfm b/api/beacons/reassign_all.cfm index e9e2b09..46d26cf 100644 --- a/api/beacons/reassign_all.cfm +++ b/api/beacons/reassign_all.cfm @@ -7,11 +7,11 @@ UPDATE Beacons - SET BeaconBusinessID = + SET BusinessID = - SELECT COUNT(*) AS cnt FROM Beacons WHERE BeaconBusinessID = + SELECT COUNT(*) AS cnt FROM Beacons WHERE BusinessID = #serializeJSON({ "OK": true, "MESSAGE": "All beacons reassigned to BusinessID #targetBusinessID#", "COUNT": qCount.cnt })# diff --git a/api/beacons/save.cfm b/api/beacons/save.cfm index 615f2e5..6083941 100644 --- a/api/beacons/save.cfm +++ b/api/beacons/save.cfm @@ -36,7 +36,7 @@ if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || // Verify the business exists qBiz = queryExecute( - "SELECT BusinessID FROM Businesses WHERE BusinessID = ? LIMIT 1", + "SELECT ID FROM Businesses WHERE ID = ? LIMIT 1", [ { value=request.BusinessID, cfsqltype="cf_sql_integer" } ], { datasource="payfrit" } ); @@ -44,8 +44,8 @@ if (qBiz.recordCount EQ 0) { apiAbort({ OK=false, ERROR="invalid_business", MESSAGE="Business ID #request.BusinessID# does not exist. Please log out and log back in." }); } -if (!structKeyExists(data, "BeaconName") || len(normStr(data.BeaconName)) EQ 0) { - apiAbort({ OK=false, ERROR="missing_beacon_name", MESSAGE="BeaconName is required" }); +if (!structKeyExists(data, "Name") || len(normStr(data.Name)) EQ 0) { + apiAbort({ OK=false, ERROR="missing_beacon_name", MESSAGE="Name is required" }); } beaconId = 0; @@ -53,7 +53,7 @@ if (structKeyExists(data, "BeaconID") && isNumeric(data.BeaconID) && int(data.Be beaconId = int(data.BeaconID); } -beaconName = normStr(data.BeaconName); +beaconName = normStr(data.Name); uuid = structKeyExists(data, "UUID") ? normStr(data.UUID) : ""; isActive = 1; @@ -66,12 +66,12 @@ if (structKeyExists(data, "IsActive")) { // App is authoritative: if UUID exists, treat as update (overwrite) if (beaconId EQ 0 && len(uuid) GT 0) { qExisting = queryExecute( - "SELECT BeaconID FROM Beacons WHERE BeaconUUID = ? LIMIT 1", + "SELECT ID FROM Beacons WHERE UUID = ? LIMIT 1", [ { value=uuid, cfsqltype="cf_sql_varchar" } ], { datasource="payfrit" } ); if (qExisting.recordCount GT 0) { - beaconId = qExisting.BeaconID; + beaconId = qExisting.ID; } }
@@ -81,59 +81,41 @@ if (beaconId EQ 0 && len(uuid) GT 0) { UPDATE Beacons SET - BeaconBusinessID = , - BeaconName = , - BeaconUUID = , - BeaconIsActive = - WHERE BeaconID = + BusinessID = , + Name = , + UUID = , + IsActive = + WHERE ID = - SELECT ServicePointID FROM lt_Beacon_Businesses_ServicePoints + SELECT ID FROM ServicePoints WHERE BeaconID = LIMIT 1 UPDATE ServicePoints - SET ServicePointName = , - ServicePointBusinessID = - WHERE ServicePointID = - - - - UPDATE lt_Beacon_Businesses_ServicePoints - SET BusinessID = + SET Name = , + BusinessID = WHERE BeaconID = - + INSERT INTO ServicePoints ( - ServicePointBusinessID, - ServicePointName, - ServicePointTypeID, - ServicePointIsActive + BusinessID, + Name, + TypeID, + IsActive, + BeaconID ) VALUES ( , , 1, - 1 - ) - - - SELECT LAST_INSERT_ID() AS ServicePointID - - - INSERT INTO lt_Beacon_Businesses_ServicePoints ( - BusinessID, - BeaconID, - ServicePointID - ) VALUES ( - , - , - + 1, + ) @@ -142,10 +124,10 @@ if (beaconId EQ 0 && len(uuid) GT 0) { INSERT INTO Beacons ( - BeaconBusinessID, - BeaconName, - BeaconUUID, - BeaconIsActive + BusinessID, + Name, + UUID, + IsActive ) VALUES ( , , @@ -155,40 +137,24 @@ if (beaconId EQ 0 && len(uuid) GT 0) { - SELECT LAST_INSERT_ID() AS BeaconID + SELECT LAST_INSERT_ID() AS ID - + - + INSERT INTO ServicePoints ( - ServicePointBusinessID, - ServicePointName, - ServicePointTypeID, - ServicePointIsActive + BusinessID, + Name, + TypeID, + IsActive, + BeaconID ) VALUES ( , , 1, - 1 - ) - - - - SELECT LAST_INSERT_ID() AS ServicePointID - - - - - - INSERT INTO lt_Beacon_Businesses_ServicePoints ( - BusinessID, - BeaconID, - ServicePointID - ) VALUES ( - , - , - + 1, + ) @@ -196,23 +162,23 @@ if (beaconId EQ 0 && len(uuid) GT 0) { SELECT - BeaconID, - BeaconBusinessID, - BeaconName, - BeaconUUID, - BeaconIsActive + ID, + BusinessID, + Name, + UUID, + IsActive FROM Beacons - WHERE BeaconID = - AND BeaconBusinessID = + WHERE ID = + AND BusinessID = LIMIT 1 #serializeJSON({ OK=true, ERROR="", BEACON=beacon })# diff --git a/api/businesses/get.cfm b/api/businesses/get.cfm index c142359..7bc4e08 100644 --- a/api/businesses/get.cfm +++ b/api/businesses/get.cfm @@ -32,28 +32,20 @@ try { abort; } - // Check cache (5 minute TTL) - cached = appCacheGet("biz_" & businessID, 300); - if (!isNull(cached)) { - logPerf(); - writeOutput(cached); - abort; - } - // Get business details - q = queryTimed(" + q = queryExecute(" SELECT - BusinessID, - BusinessName, - BusinessPhone, - BusinessStripeAccountID, - BusinessStripeOnboardingComplete, - BusinessIsHiring, - BusinessHeaderImageExtension, - BusinessTaxRate, - BusinessBrandColor + ID, + Name, + Phone, + StripeAccountID, + StripeOnboardingComplete, + IsHiring, + HeaderImageExtension, + TaxRate, + BrandColor FROM Businesses - WHERE BusinessID = :businessID + WHERE ID = :businessID ", { businessID: businessID }, { datasource: "payfrit" }); if (q.recordCount == 0) { @@ -62,13 +54,13 @@ try { abort; } - // Get address from Addresses table (either linked via AddressBusinessID or via Businesses.BusinessAddressID) - qAddr = queryTimed(" - SELECT a.AddressLine1, a.AddressLine2, a.AddressCity, a.AddressZIPCode, s.tt_StateAbbreviation + // Get address from Addresses table (either linked via BusinessID or via Businesses.AddressID) + qAddr = queryExecute(" + SELECT a.Line1, a.Line2, a.City, a.ZIPCode, s.Abbreviation FROM Addresses a - LEFT JOIN tt_States s ON s.tt_StateID = a.AddressStateID - WHERE (a.AddressBusinessID = :businessID OR a.AddressID = (SELECT BusinessAddressID FROM Businesses WHERE BusinessID = :businessID)) - AND a.AddressIsDeleted = 0 + LEFT JOIN tt_States s ON s.ID = a.StateID + WHERE (a.BusinessID = :businessID OR a.ID = (SELECT AddressID FROM Businesses WHERE ID = :businessID)) + AND a.IsDeleted = 0 LIMIT 1 ", { businessID: businessID }, { datasource: "payfrit" }); @@ -78,29 +70,29 @@ try { addressState = ""; addressZip = ""; if (qAddr.recordCount > 0) { - addressLine1 = qAddr.AddressLine1; - addressCity = qAddr.AddressCity; - addressState = qAddr.tt_StateAbbreviation; - addressZip = qAddr.AddressZIPCode; + addressLine1 = qAddr.Line1; + addressCity = qAddr.City; + addressState = qAddr.Abbreviation; + addressZip = qAddr.ZIPCode; addressParts = []; - if (len(qAddr.AddressLine1)) arrayAppend(addressParts, qAddr.AddressLine1); - if (len(qAddr.AddressLine2)) arrayAppend(addressParts, qAddr.AddressLine2); + if (len(qAddr.Line1)) arrayAppend(addressParts, qAddr.Line1); + if (len(qAddr.Line2)) arrayAppend(addressParts, qAddr.Line2); cityStateZip = []; - if (len(qAddr.AddressCity)) arrayAppend(cityStateZip, qAddr.AddressCity); - if (len(qAddr.tt_StateAbbreviation)) arrayAppend(cityStateZip, qAddr.tt_StateAbbreviation); - if (len(qAddr.AddressZIPCode)) arrayAppend(cityStateZip, qAddr.AddressZIPCode); + if (len(qAddr.City)) arrayAppend(cityStateZip, qAddr.City); + if (len(qAddr.Abbreviation)) arrayAppend(cityStateZip, qAddr.Abbreviation); + if (len(qAddr.ZIPCode)) arrayAppend(cityStateZip, qAddr.ZIPCode); if (arrayLen(cityStateZip) > 0) arrayAppend(addressParts, arrayToList(cityStateZip, ", ")); addressStr = arrayToList(addressParts, ", "); } // Get hours from Hours table - qHours = queryTimed(" - SELECT h.HoursDayID, h.HoursOpenTime, h.HoursClosingTime, d.tt_DayAbbrev + qHours = queryExecute(" + SELECT h.DayID, h.OpenTime, h.ClosingTime, d.Abbrev FROM Hours h - JOIN tt_Days d ON d.tt_DayID = h.HoursDayID - WHERE h.HoursBusinessID = :businessID - ORDER BY h.HoursDayID + JOIN tt_Days d ON d.ID = h.DayID + WHERE h.BusinessID = :businessID + ORDER BY h.DayID ", { businessID: businessID }, { datasource: "payfrit" }); hoursArr = []; @@ -108,10 +100,10 @@ try { if (qHours.recordCount > 0) { for (h in qHours) { arrayAppend(hoursArr, { - "day": h.tt_DayAbbrev, - "dayId": h.HoursDayID, - "open": timeFormat(h.HoursOpenTime, "h:mm tt"), - "close": timeFormat(h.HoursClosingTime, "h:mm tt") + "day": h.Abbrev, + "dayId": h.DayID, + "open": timeFormat(h.OpenTime, "h:mm tt"), + "close": timeFormat(h.ClosingTime, "h:mm tt") }); } // Build readable hours string (group similar days) @@ -133,44 +125,36 @@ try { } // Build business object - taxRate = isNumeric(q.BusinessTaxRate) ? q.BusinessTaxRate : 0; + taxRate = isNumeric(q.TaxRate) ? q.TaxRate : 0; business = { - "BusinessID": q.BusinessID, - "BusinessName": q.BusinessName, - "BusinessAddress": addressStr, - "AddressLine1": addressLine1, - "AddressCity": addressCity, + "BusinessID": q.ID, + "Name": q.Name, + "Address": addressStr, + "Line1": addressLine1, + "City": addressCity, "AddressState": addressState, "AddressZip": addressZip, - "BusinessPhone": q.BusinessPhone, - "BusinessHours": hoursStr, - "BusinessHoursDetail": hoursArr, - "StripeConnected": (len(q.BusinessStripeAccountID) > 0 && q.BusinessStripeOnboardingComplete == 1), - "IsHiring": q.BusinessIsHiring == 1, + "Phone": q.Phone, + "Hours": hoursStr, + "HoursDetail": hoursArr, + "StripeConnected": (len(q.StripeAccountID) > 0 && q.StripeOnboardingComplete == 1), + "IsHiring": q.IsHiring == 1, "TaxRate": taxRate, "TaxRatePercent": taxRate * 100, - "BrandColor": len(q.BusinessBrandColor) ? (left(q.BusinessBrandColor, 1) == chr(35) ? q.BusinessBrandColor : chr(35) & q.BusinessBrandColor) : "" + "BrandColor": len(q.BrandColor) ? (left(q.BrandColor, 1) == chr(35) ? q.BrandColor : chr(35) & q.BrandColor) : "" }; // Add header image URL if extension exists - if (len(q.BusinessHeaderImageExtension)) { - business["HeaderImageURL"] = "https://biz.payfrit.com/uploads/headers/" & q.BusinessID & "." & q.BusinessHeaderImageExtension; + if (len(q.HeaderImageExtension)) { + business["HeaderImageURL"] = "https://biz.payfrit.com/uploads/headers/" & q.ID & "." & q.HeaderImageExtension; } response["OK"] = true; response["BUSINESS"] = business; - // Cache successful response - jsonResponse = serializeJSON(response); - appCachePut("biz_" & businessID, jsonResponse); - logPerf(); - writeOutput(jsonResponse); - abort; - } catch (any e) { response["ERROR"] = e.message; } -logPerf(); writeOutput(serializeJSON(response));
diff --git a/api/businesses/getChildren.cfm b/api/businesses/getChildren.cfm index cbf0b8a..4e11011 100644 --- a/api/businesses/getChildren.cfm +++ b/api/businesses/getChildren.cfm @@ -41,11 +41,11 @@ try { q = queryExecute( " SELECT - BusinessID, - BusinessName + ID, + Name FROM Businesses - WHERE BusinessParentBusinessID = :parentId - ORDER BY BusinessName + WHERE ParentBusinessID = :parentId + ORDER BY Name ", { parentId = { value = parentBusinessId, cfsqltype = "cf_sql_integer" } }, { datasource = "payfrit" } @@ -54,8 +54,8 @@ try { rows = []; for (i = 1; i <= q.recordCount; i++) { arrayAppend(rows, { - "BusinessID": q.BusinessID[i], - "BusinessName": q.BusinessName[i] + "BusinessID": q.ID[i], + "Name": q.Name[i] }); } diff --git a/api/businesses/list.cfm b/api/businesses/list.cfm index e3f263e..86d2ca3 100644 --- a/api/businesses/list.cfm +++ b/api/businesses/list.cfm @@ -48,17 +48,17 @@ try { q = queryExecute( " SELECT - b.BusinessID, - b.BusinessName, - a.AddressLat, - a.AddressLng, - a.AddressCity, - a.AddressLine1 + b.ID, + b.Name, + a.Latitude, + a.Longitude, + a.City, + a.Line1 FROM Businesses b - LEFT JOIN Addresses a ON b.BusinessAddressID = a.AddressID - WHERE (b.BusinessIsDemo = 0 OR b.BusinessIsDemo IS NULL) - AND (b.BusinessIsPrivate = 0 OR b.BusinessIsPrivate IS NULL) - ORDER BY b.BusinessName + LEFT JOIN Addresses a ON b.AddressID = a.ID + WHERE (b.IsDemo = 0 OR b.IsDemo IS NULL) + AND (b.IsPrivate = 0 OR b.IsPrivate IS NULL) + ORDER BY b.Name ", [], { datasource = "payfrit" } @@ -68,15 +68,15 @@ try { rows = []; for (i = 1; i <= q.recordCount; i++) { row = { - "BusinessID": q.BusinessID[i], - "BusinessName": q.BusinessName[i], - "AddressCity": isNull(q.AddressCity[i]) ? "" : q.AddressCity[i], - "AddressLine1": isNull(q.AddressLine1[i]) ? "" : q.AddressLine1[i] + "BusinessID": q.ID[i], + "Name": q.Name[i], + "City": isNull(q.City[i]) ? "" : q.City[i], + "Line1": isNull(q.Line1[i]) ? "" : q.Line1[i] }; // Calculate distance if we have both user location and business location - bizLat = isNull(q.AddressLat[i]) ? 0 : val(q.AddressLat[i]); - bizLng = isNull(q.AddressLng[i]) ? 0 : val(q.AddressLng[i]); + bizLat = isNull(q.Latitude[i]) ? 0 : val(q.Latitude[i]); + bizLng = isNull(q.Longitude[i]) ? 0 : val(q.Longitude[i]); if (hasUserLocation AND bizLat != 0 AND bizLng != 0) { row["DistanceMiles"] = haversineDistance(userLat, userLng, bizLat, bizLng); diff --git a/api/businesses/saveBrandColor.cfm b/api/businesses/saveBrandColor.cfm index 92503d3..12b278c 100644 --- a/api/businesses/saveBrandColor.cfm +++ b/api/businesses/saveBrandColor.cfm @@ -54,14 +54,13 @@ if (len(brandColor) GT 0) { // Update the database queryExecute(" UPDATE Businesses - SET BusinessBrandColor = :color + SET BrandColor = :color WHERE BusinessID = :bizId ", { color: { value: brandColor, cfsqltype: "cf_sql_varchar" }, bizId: { value: bizId, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); -appCacheInvalidate("biz_" & bizId); writeOutput(serializeJSON({ "OK": true, "ERROR": "", diff --git a/api/businesses/setHiring.cfm b/api/businesses/setHiring.cfm index b204cb6..8447ed1 100644 --- a/api/businesses/setHiring.cfm +++ b/api/businesses/setHiring.cfm @@ -45,7 +45,7 @@ if (isHiring == -1) { try { queryExecute(" UPDATE Businesses - SET BusinessIsHiring = ? + SET IsHiring = ? WHERE BusinessID = ? ", [ { value: isHiring, cfsqltype: "cf_sql_tinyint" }, diff --git a/api/businesses/update.cfm b/api/businesses/update.cfm index cc5ef55..e60a7d7 100644 --- a/api/businesses/update.cfm +++ b/api/businesses/update.cfm @@ -9,9 +9,9 @@ * POST JSON: * { * "BusinessID": 37, - * "BusinessName": "My Business", - * "BusinessPhone": "(555) 123-4567", - * "AddressLine1": "123 Main St", + * "Name": "My Business", + * "Phone": "(555) 123-4567", + * "Line1": "123 Main St", * "City": "Los Angeles", * "State": "CA", * "Zip": "90001" @@ -34,8 +34,8 @@ try { } // Update business name, phone, and tax rate - bizName = structKeyExists(data, "BusinessName") && isSimpleValue(data.BusinessName) ? trim(data.BusinessName) : ""; - bizPhone = structKeyExists(data, "BusinessPhone") && isSimpleValue(data.BusinessPhone) ? trim(data.BusinessPhone) : ""; + bizName = structKeyExists(data, "Name") && isSimpleValue(data.Name) ? trim(data.Name) : ""; + bizPhone = structKeyExists(data, "Phone") && isSimpleValue(data.Phone) ? trim(data.Phone) : ""; // Handle tax rate (accept either TaxRatePercent like 8.25, or TaxRate like 0.0825) taxRate = ""; @@ -48,7 +48,7 @@ try { if (len(bizName)) { if (isNumeric(taxRate)) { queryExecute(" - UPDATE Businesses SET BusinessName = :name, BusinessPhone = :phone, BusinessTaxRate = :taxRate + UPDATE Businesses SET Name = :name, Phone = :phone, TaxRate = :taxRate WHERE BusinessID = :id ", { name: bizName, @@ -58,7 +58,7 @@ try { }, { datasource: "payfrit" }); } else { queryExecute(" - UPDATE Businesses SET BusinessName = :name, BusinessPhone = :phone + UPDATE Businesses SET Name = :name, Phone = :phone WHERE BusinessID = :id ", { name: bizName, @@ -69,7 +69,7 @@ try { } // Update or create address - addressLine1 = structKeyExists(data, "AddressLine1") && isSimpleValue(data.AddressLine1) ? trim(data.AddressLine1) : ""; + addressLine1 = structKeyExists(data, "Line1") && isSimpleValue(data.Line1) ? trim(data.Line1) : ""; city = structKeyExists(data, "City") && isSimpleValue(data.City) ? trim(data.City) : ""; state = structKeyExists(data, "State") && isSimpleValue(data.State) ? trim(data.State) : ""; zip = structKeyExists(data, "Zip") && isSimpleValue(data.Zip) ? trim(data.Zip) : ""; @@ -81,7 +81,7 @@ try { stateID = 0; if (len(state)) { qState = queryExecute(" - SELECT tt_StateID FROM tt_States WHERE tt_StateAbbreviation = :abbr + SELECT tt_StateID FROM tt_States WHERE Abbreviation = :abbr ", { abbr: uCase(state) }, { datasource: "payfrit" }); if (qState.recordCount > 0) { stateID = qState.tt_StateID; @@ -90,8 +90,8 @@ try { // Check if business has an address qAddr = queryExecute(" - SELECT AddressID FROM Addresses - WHERE AddressBusinessID = :bizID AND AddressUserID = 0 AND AddressIsDeleted = 0 + SELECT ID FROM Addresses + WHERE BusinessID = :bizID AND UserID = 0 AND IsDeleted = 0 LIMIT 1 ", { bizID: businessId }, { datasource: "payfrit" }); @@ -99,11 +99,11 @@ try { // Update existing address queryExecute(" UPDATE Addresses SET - AddressLine1 = :line1, - AddressCity = :city, - AddressStateID = :stateID, - AddressZIPCode = :zip - WHERE AddressID = :addrID + Line1 = :line1, + City = :city, + StateID = :stateID, + ZIPCode = :zip + WHERE ID = :addrID ", { line1: addressLine1, city: city, @@ -114,7 +114,7 @@ try { } else { // Create new address queryExecute(" - INSERT INTO Addresses (AddressLine1, AddressCity, AddressStateID, AddressZIPCode, AddressBusinessID, AddressUserID, AddressTypeID, AddressAddedOn) + INSERT INTO Addresses (Line1, City, StateID, ZIPCode, BusinessID, UserID, AddressTypeID, AddedOn) VALUES (:line1, :city, :stateID, :zip, :bizID, 0, 2, NOW()) ", { line1: addressLine1, @@ -126,7 +126,6 @@ try { } response.OK = true; - appCacheInvalidate("biz_" & businessId); } catch (any e) { response.ERROR = e.message; diff --git a/api/businesses/updateHours.cfm b/api/businesses/updateHours.cfm index b3411ce..ffb6fcc 100644 --- a/api/businesses/updateHours.cfm +++ b/api/businesses/updateHours.cfm @@ -38,7 +38,7 @@ try { // Delete all existing hours for this business queryExecute(" - DELETE FROM Hours WHERE HoursBusinessID = :bizID + DELETE FROM Hours WHERE BusinessID = :bizID ", { bizID: businessId }, { datasource: "payfrit" }); // Insert new hours @@ -55,7 +55,7 @@ try { if (len(closeTime) == 5) closeTime = closeTime & ":00"; queryExecute(" - INSERT INTO Hours (HoursBusinessID, HoursDayID, HoursOpenTime, HoursClosingTime) + INSERT INTO Hours (BusinessID, DayID, OpenTime, ClosingTime) VALUES (:bizID, :dayID, :openTime, :closeTime) ", { bizID: businessId, @@ -68,7 +68,6 @@ try { response.OK = true; response.hoursUpdated = arrayLen(hours); - appCacheInvalidate("biz_" & businessId); } catch (any e) { response.ERROR = e.message; diff --git a/api/chat/closeChat.cfm b/api/chat/closeChat.cfm index ef56fb9..d5012d0 100644 --- a/api/chat/closeChat.cfm +++ b/api/chat/closeChat.cfm @@ -34,10 +34,10 @@ try { // Mark the task as completed queryExecute(" UPDATE Tasks - SET TaskCompletedOn = NOW() + SET CompletedOn = NOW() WHERE TaskID = :taskID AND TaskTypeID = 2 - AND TaskCompletedOn IS NULL + AND CompletedOn IS NULL ", { taskID: { value: taskID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); diff --git a/api/chat/getActiveChat.cfm b/api/chat/getActiveChat.cfm index 23e0c9c..54d2302 100644 --- a/api/chat/getActiveChat.cfm +++ b/api/chat/getActiveChat.cfm @@ -45,17 +45,17 @@ try { // Look for any active chat task at this service point // TaskTypeID = 2 (Chat), not completed, at this service point qChat = queryExecute(" - SELECT t.TaskID, t.TaskTitle, - (SELECT MAX(cm.CreatedOn) FROM ChatMessages cm WHERE cm.TaskID = t.TaskID) as LastMessageTime + SELECT t.ID, t.Title, + (SELECT MAX(cm.CreatedOn) FROM ChatMessages cm WHERE cm.TaskID = t.ID) as LastMessageTime FROM Tasks t - WHERE t.TaskBusinessID = :businessID + WHERE t.BusinessID = :businessID AND t.TaskTypeID = 2 - AND t.TaskCompletedOn IS NULL - AND t.TaskSourceType = 'servicepoint' - AND t.TaskSourceID = :servicePointID + AND t.CompletedOn IS NULL + AND t.SourceType = 'servicepoint' + AND t.SourceID = :servicePointID ORDER BY - CASE WHEN t.TaskClaimedByUserID > 0 THEN 0 ELSE 1 END, - t.TaskAddedOn DESC + CASE WHEN t.ClaimedByUserID > 0 THEN 0 ELSE 1 END, + t.CreatedOn DESC LIMIT 1 ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" }, @@ -67,7 +67,7 @@ try { "OK": true, "HAS_ACTIVE_CHAT": true, "TASK_ID": qChat.TaskID, - "TASK_TITLE": qChat.TaskTitle + "TASK_TITLE": qChat.Title }); } else { apiAbort({ diff --git a/api/chat/getMessages.cfm b/api/chat/getMessages.cfm index 90aea84..10f6ce4 100644 --- a/api/chat/getMessages.cfm +++ b/api/chat/getMessages.cfm @@ -36,17 +36,17 @@ try { if (afterMessageID > 0) { qMessages = queryExecute(" SELECT - m.MessageID, + m.ID, m.TaskID, m.SenderUserID, m.SenderType, - m.MessageText, + m.MessageBody, m.IsRead, m.CreatedOn, - u.UserFirstName as SenderName + u.FirstName as SenderName FROM ChatMessages m - LEFT JOIN Users u ON u.UserID = m.SenderUserID - WHERE m.TaskID = :taskID AND m.MessageID > :afterID + LEFT JOIN Users u ON u.ID = m.SenderUserID + WHERE m.TaskID = :taskID AND m.ID > :afterID ORDER BY m.CreatedOn ASC ", { taskID: { value: taskID, cfsqltype: "cf_sql_integer" }, @@ -55,16 +55,16 @@ try { } else { qMessages = queryExecute(" SELECT - m.MessageID, + m.ID, m.TaskID, m.SenderUserID, m.SenderType, - m.MessageText, + m.MessageBody, m.IsRead, m.CreatedOn, - u.UserFirstName as SenderName + u.FirstName as SenderName FROM ChatMessages m - LEFT JOIN Users u ON u.UserID = m.SenderUserID + LEFT JOIN Users u ON u.ID = m.SenderUserID WHERE m.TaskID = :taskID ORDER BY m.CreatedOn ASC ", { @@ -75,12 +75,12 @@ try { messages = []; for (msg in qMessages) { arrayAppend(messages, { - "MessageID": msg.MessageID, + "MessageID": msg.ID, "TaskID": msg.TaskID, "SenderUserID": msg.SenderUserID, "SenderType": msg.SenderType, "SenderName": len(trim(msg.SenderName)) ? msg.SenderName : (msg.SenderType == "customer" ? "Customer" : "Staff"), - "Text": msg.MessageText, + "Text": msg.MessageBody, "IsRead": msg.IsRead == 1, "CreatedOn": dateFormat(msg.CreatedOn, "yyyy-mm-dd") & "T" & timeFormat(msg.CreatedOn, "HH:mm:ss") }); @@ -88,11 +88,11 @@ try { // Check if chat/task is closed (completed) qTask = queryExecute(" - SELECT TaskCompletedOn FROM Tasks WHERE TaskID = :taskID + SELECT CompletedOn FROM Tasks WHERE ID = :taskID ", { taskID: { value: taskID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); chatClosed = false; - if (qTask.recordCount > 0 && len(trim(qTask.TaskCompletedOn)) > 0) { + if (qTask.recordCount > 0 && len(trim(qTask.CompletedOn)) > 0) { chatClosed = true; } diff --git a/api/chat/sendMessage.cfm b/api/chat/sendMessage.cfm index db3acca..c4cf327 100644 --- a/api/chat/sendMessage.cfm +++ b/api/chat/sendMessage.cfm @@ -54,7 +54,7 @@ try { // Verify task exists and is still open taskQuery = queryExecute(" - SELECT TaskID, TaskClaimedByUserID, TaskCompletedOn FROM Tasks WHERE TaskID = :taskID + SELECT ID, ClaimedByUserID, CompletedOn FROM Tasks WHERE ID = :taskID ", { taskID: { value: taskID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); if (taskQuery.recordCount == 0) { @@ -62,13 +62,13 @@ try { } // Check if chat has been closed - if (len(trim(taskQuery.TaskCompletedOn)) > 0) { + if (len(trim(taskQuery.CompletedOn)) > 0) { apiAbort({ "OK": false, "ERROR": "chat_closed", "MESSAGE": "This chat has ended" }); } // Insert message queryExecute(" - INSERT INTO ChatMessages (TaskID, SenderUserID, SenderType, MessageText) + INSERT INTO ChatMessages (TaskID, SenderUserID, SenderType, MessageBody) VALUES (:taskID, :userID, :senderType, :message) ", { taskID: { value: taskID, cfsqltype: "cf_sql_integer" }, diff --git a/api/config/environment.cfm b/api/config/environment.cfm index 8451937..c9c325d 100644 --- a/api/config/environment.cfm +++ b/api/config/environment.cfm @@ -116,142 +116,6 @@ function apiError(message, detail = "", statusCode = 500) { return response; } -// ============================================ -// PERFORMANCE PROFILING -// ============================================ -application.perfEnabled = true; // Toggle profiling on/off - -// Initialize perf buffer (once per application start) -if (!structKeyExists(application, "perfBuffer")) { - application.perfBuffer = []; -} - -/** - * Drop-in replacement for queryExecute that tracks query count and time. - * Usage: queryTimed("SELECT ...", [...], { datasource: "payfrit" }) - */ -function queryTimed(required string sql, any params = [], struct options = {}) { - var t = getTickCount(); - var result = queryExecute(arguments.sql, arguments.params, arguments.options); - var elapsed = getTickCount() - t; - request._perf_queryCount++; - request._perf_queryTimeMs += elapsed; - return result; -} - -/** - * Flush the in-memory perf buffer to the api_perf_log MySQL table. - * Called automatically when buffer reaches 100 entries. - */ -function flushPerfBuffer() { - var batch = []; - lock name="payfrit_perfBuffer" timeout="2" type="exclusive" { - batch = duplicate(application.perfBuffer); - application.perfBuffer = []; - } - if (arrayLen(batch) == 0) return; - - try { - var sql = "INSERT INTO api_perf_log (Endpoint, TotalMs, DbMs, AppMs, QueryCount, ResponseBytes, BusinessID, UserID, LoggedAt) VALUES "; - var rows = []; - for (var m in batch) { - arrayAppend(rows, - "('" & replace(m.endpoint, "'", "''", "all") & "'," - & m.totalMs & "," & m.dbMs & "," & m.appMs & "," - & m.queryCount & "," & m.responseBytes & "," - & m.businessId & "," & m.userId & ",'" - & m.loggedAt & "')" - ); - } - sql &= arrayToList(rows, ","); - queryExecute(sql, {}, { datasource: "payfrit" }); - - // Cleanup: delete rows older than 30 days (run occasionally) - if (randRange(1, 100) == 1) { - queryExecute( - "DELETE FROM api_perf_log WHERE LoggedAt < DATE_SUB(NOW(), INTERVAL 30 DAY)", - {}, { datasource: "payfrit" } - ); - } - } catch (any e) { - // Silent fail - never break the app for profiling - } -} - -/** - * Log performance metrics for the current request. - * Call this at the end of any instrumented endpoint, before the final writeOutput/abort. - */ -function logPerf(numeric responseBytes = 0) { - if (!structKeyExists(application, "perfEnabled") || !application.perfEnabled) return; - - var totalMs = getTickCount() - request._perf_start; - var dbMs = request._perf_queryTimeMs; - - var metric = { - endpoint: structKeyExists(request, "_api_path") ? request._api_path : "unknown", - totalMs: totalMs, - dbMs: dbMs, - appMs: totalMs - dbMs, - queryCount: request._perf_queryCount, - responseBytes: arguments.responseBytes, - businessId: structKeyExists(request, "BusinessID") ? val(request.BusinessID) : 0, - userId: structKeyExists(request, "UserID") ? val(request.UserID) : 0, - loggedAt: dateTimeFormat(now(), "yyyy-mm-dd HH:nn:ss") - }; - - lock name="payfrit_perfBuffer" timeout="1" type="exclusive" { - arrayAppend(application.perfBuffer, metric); - if (arrayLen(application.perfBuffer) >= 100) { - thread name="perfFlush_#createUUID()#" { - flushPerfBuffer(); - } - } - } -} - -// ============================================ -// APPLICATION-SCOPE CACHE -// ============================================ -if (!structKeyExists(application, "cache")) { - application.cache = {}; -} - -/** - * Get a cached value. Returns null if not found or expired. - * Usage: cached = cacheGet("menu_123", 120); - * if (!isNull(cached)) { use it } else { query and cachePut } - */ -function appCacheGet(required string key, numeric ttlSeconds = 300) { - if (structKeyExists(application.cache, arguments.key)) { - var entry = application.cache[arguments.key]; - if (dateDiff("s", entry.cachedAt, now()) < arguments.ttlSeconds) { - return entry.data; - } - structDelete(application.cache, arguments.key); - } - return javaCast("null", ""); -} - -/** - * Store a value in cache. - */ -function appCachePut(required string key, required any data) { - application.cache[arguments.key] = { data: arguments.data, cachedAt: now() }; -} - -/** - * Invalidate all cache keys starting with the given prefix. - */ -function appCacheInvalidate(required string keyPrefix) { - var keys = structKeyArray(application.cache); - for (var k in keys) { - if (findNoCase(arguments.keyPrefix, k) == 1) { - structDelete(application.cache, k); - } - } -} - // Store in application scope application.isDevEnvironment = isDevEnvironment; application.isDev = isDev; diff --git a/api/config/stripe.cfm b/api/config/stripe.cfm index 87dbd09..057daf1 100644 --- a/api/config/stripe.cfm +++ b/api/config/stripe.cfm @@ -41,4 +41,8 @@ application.payfritCustomerFeePercent = 0.05; // 5% customer pays to Payfrit application.payfritBusinessFeePercent = 0.05; // 5% business pays to Payfrit application.cardFeePercent = 0.029; // 2.9% Stripe fee application.cardFeeFixed = 0.30; // $0.30 Stripe fixed fee + +// Activation (Cost Recovery) Configuration +application.activationCapCentsDefault = 2500; // $25.00 +application.activationWithholdIncrementCents = 100; // $1.00 per payout
diff --git a/api/debug/checkTask.cfm b/api/debug/checkTask.cfm index 43afad8..bea65ab 100644 --- a/api/debug/checkTask.cfm +++ b/api/debug/checkTask.cfm @@ -16,11 +16,11 @@ @@ -30,18 +30,18 @@ diff --git a/api/debug/checkToken.cfm b/api/debug/checkToken.cfm index 8531314..ca2591a 100644 --- a/api/debug/checkToken.cfm +++ b/api/debug/checkToken.cfm @@ -28,18 +28,18 @@ result = { if (len(userToken)) { try { qTok = queryExecute( - "SELECT UserID, Token FROM UserTokens WHERE Token = ? LIMIT 1", + "SELECT ID, Token FROM UserTokens WHERE Token = ? LIMIT 1", [ { value = userToken, cfsqltype = "cf_sql_varchar" } ], { datasource = "payfrit" } ); result.dbLookupRecords = qTok.recordCount; if (qTok.recordCount > 0) { - result.foundUserId = qTok.UserID; + result.foundUserId = qTok.ID; } // Also check with LIKE to see if partial match exists qPartial = queryExecute( - "SELECT UserID, Token FROM UserTokens WHERE Token LIKE ? LIMIT 5", + "SELECT ID, Token FROM UserTokens WHERE Token LIKE ? LIMIT 5", [ { value = left(userToken, 8) & "%", cfsqltype = "cf_sql_varchar" } ], { datasource = "payfrit" } ); @@ -53,14 +53,14 @@ if (len(userToken)) { // Also list recent tokens try { qRecent = queryExecute( - "SELECT UserID, LEFT(Token, 8) as TokenPrefix, LENGTH(Token) as TokenLen FROM UserTokens ORDER BY UserID DESC LIMIT 5", + "SELECT ID, LEFT(Token, 8) as TokenPrefix, LENGTH(Token) as TokenLen FROM UserTokens ORDER BY ID DESC LIMIT 5", [], { datasource = "payfrit" } ); result.recentTokens = []; for (row in qRecent) { arrayAppend(result.recentTokens, { - "userId": row.UserID, + "userId": row.ID, "prefix": row.TokenPrefix, "length": row.TokenLen }); diff --git a/api/dev/seedData.cfm b/api/dev/seedData.cfm index df1c7e7..47125d7 100644 --- a/api/dev/seedData.cfm +++ b/api/dev/seedData.cfm @@ -44,17 +44,17 @@ function createTestUser(phone, firstName, lastName, isVerified = true) { queryExecute(" INSERT INTO Users ( - UserContactNumber, - UserUUID, - UserFirstName, - UserLastName, - UserIsContactVerified, - UserIsEmailVerified, - UserIsActive, - UserAddedOn, - UserPassword, - UserPromoCode, - UserMobileVerifyCode + ContactNumber, + UUID, + FirstName, + LastName, + IsContactVerified, + IsEmailVerified, + IsActive, + AddedOn, + Password, + PromoCode, + MobileVerifyCode ) VALUES ( :phone, :uuid, @@ -127,7 +127,7 @@ function resetTestData() { // Delete test users (by phone prefix 555) queryExecute(" DELETE FROM Users - WHERE UserContactNumber LIKE '555%' + WHERE ContactNumber LIKE '555%' ", {}, { datasource: "payfrit" }); return seedTestData(); @@ -135,20 +135,20 @@ function resetTestData() { function getTestDataInfo() { var qUsers = queryExecute(" - SELECT UserID, UserContactNumber, UserFirstName, UserLastName, - UserIsContactVerified, UserUUID + SELECT ID, ContactNumber, FirstName, LastName, + IsContactVerified, UUID FROM Users - WHERE UserContactNumber LIKE '555%' - ORDER BY UserContactNumber + WHERE ContactNumber LIKE '555%' + ORDER BY ContactNumber ", {}, { datasource: "payfrit" }); var users = []; for (var row in qUsers) { arrayAppend(users, { - "phone": row.UserContactNumber, - "name": trim(row.UserFirstName & " " & row.UserLastName), - "verified": row.UserIsContactVerified == 1, - "uuid": row.UserUUID + "phone": row.ContactNumber, + "name": trim(row.FirstName & " " & row.LastName), + "verified": row.IsContactVerified == 1, + "uuid": row.UUID }); } diff --git a/api/dev/timeTravel.cfm b/api/dev/timeTravel.cfm index 12c728a..b41652c 100644 --- a/api/dev/timeTravel.cfm +++ b/api/dev/timeTravel.cfm @@ -79,7 +79,7 @@ try { queryExecute(" UPDATE Users - SET UserAddedOn = DATE_SUB(NOW(), INTERVAL :days DAY) + SET AddedOn = DATE_SUB(NOW(), INTERVAL :days DAY) WHERE UserID = :userId ", { userId: { value: data.userId, cfsqltype: "cf_sql_integer" }, @@ -95,7 +95,7 @@ try { case "clearotps": // Clear all OTPs (force re-request) queryExecute(" - UPDATE Users SET UserMobileVerifyCode = '' + UPDATE Users SET MobileVerifyCode = '' ", {}, { datasource: "payfrit" }); writeOutput(serializeJSON({ @@ -112,12 +112,12 @@ try { queryExecute(" UPDATE Users - SET UserIsContactVerified = 0, - UserIsActive = 0, - UserFirstName = NULL, - UserLastName = NULL, - UserMobileVerifyCode = '123456' - WHERE UserContactNumber = :phone + SET IsContactVerified = 0, + IsActive = 0, + FirstName = NULL, + LastName = NULL, + MobileVerifyCode = '123456' + WHERE ContactNumber = :phone ", { phone: { value: data.phone, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); diff --git a/api/import/crimson_menu.cfm b/api/import/crimson_menu.cfm index 8812b63..ef08c60 100644 --- a/api/import/crimson_menu.cfm +++ b/api/import/crimson_menu.cfm @@ -14,7 +14,7 @@ try { // Check if business already exists by name qCheck = queryExecute(" - SELECT BusinessID FROM Businesses WHERE BusinessName = :name + SELECT ID FROM Businesses WHERE Name = :name ", { name: "Crimson Mediterranean Cookhouse" }, { datasource: "payfrit" }); if (qCheck.recordCount > 0) { @@ -22,7 +22,7 @@ try { response.steps.append("Business already exists with ID: " & BusinessID); } else { queryExecute(" - INSERT INTO Businesses (BusinessName, BusinessOwnerUserID) + INSERT INTO Businesses (Name, BusinessOwnerUserID) VALUES (:name, :ownerID) ", { name: "Crimson Mediterranean Cookhouse", @@ -54,15 +54,15 @@ try { for (cat in categories) { // Check if exists qCat = queryExecute(" - SELECT CategoryID FROM Categories - WHERE CategoryBusinessID = :bizID AND CategoryName = :name + SELECT ID FROM Categories + WHERE BusinessID = :bizID AND Name = :name ", { bizID: BusinessID, name: cat.name }, { datasource: "payfrit" }); if (qCat.recordCount > 0) { categoryMap[cat.id] = qCat.CategoryID; } else { queryExecute(" - INSERT INTO Categories (CategoryBusinessID, CategoryName, CategorySortOrder) + INSERT INTO Categories (BusinessID, Name, SortOrder) VALUES (:bizID, :name, :sortOrder) ", { bizID: BusinessID, @@ -87,8 +87,8 @@ try { function createModifierGroup(categoryID, parentItemID, groupName, groupID, options, required, maxSelect) { // Check if group exists var qMod = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = :parentID + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = :parentID ", { catID: categoryID, name: groupName, parentID: parentItemID }, { datasource: "payfrit" }); var groupItemID = 0; @@ -96,8 +96,8 @@ try { groupItemID = qMod.ItemID; } else { queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemParentItemID, ItemPrice, ItemIsActive, - ItemRequiresChildSelection, ItemMaxNumSelectionReq, ItemIsCollapsible, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, ParentItemID, Price, IsActive, + RequiresChildSelection, MaxNumSelectionReq, IsCollapsible, SortOrder) VALUES (:catID, :name, :parentID, 0, 1, :required, :maxSelect, 1, :sortOrder) ", { catID: categoryID, @@ -116,15 +116,15 @@ try { var optionOrder = 1; for (var opt in options) { var qOpt = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = :parentID + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = :parentID ", { catID: categoryID, name: opt.name, parentID: groupItemID }, { datasource: "payfrit" }); if (qOpt.recordCount == 0) { var isDefault = (optionOrder == 1 && required) ? 1 : 0; queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemParentItemID, ItemPrice, ItemIsActive, - ItemIsCheckedByDefault, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, ParentItemID, Price, IsActive, + IsCheckedByDefault, SortOrder) VALUES (:catID, :name, :parentID, :price, 1, :isDefault, :sortOrder) ", { catID: categoryID, @@ -159,14 +159,14 @@ try { itemOrder = 1; for (item in grillItems) { qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = 0 + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = 0 ", { catID: grillCatID, name: item.name }, { datasource: "payfrit" }); if (qItem.recordCount == 0) { queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemDescription, ItemParentItemID, ItemPrice, - ItemIsActive, ItemRequiresChildSelection, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, Description, ParentItemID, Price, + IsActive, RequiresChildSelection, SortOrder) VALUES (:catID, :name, :desc, 0, :price, 1, :reqChild, :sortOrder) ", { catID: grillCatID, @@ -199,14 +199,14 @@ try { itemOrder = 1; for (item in wrapItems) { qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = 0 + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = 0 ", { catID: wrapsCatID, name: item.name }, { datasource: "payfrit" }); if (qItem.recordCount == 0) { queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemDescription, ItemParentItemID, ItemPrice, - ItemIsActive, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, Description, ParentItemID, Price, + IsActive, SortOrder) VALUES (:catID, :name, :desc, 0, :price, 1, :sortOrder) ", { catID: wrapsCatID, @@ -235,14 +235,14 @@ try { itemOrder = 1; for (item in saladItems) { qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = 0 + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = 0 ", { catID: saladsCatID, name: item.name }, { datasource: "payfrit" }); if (qItem.recordCount == 0) { queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemDescription, ItemParentItemID, ItemPrice, - ItemIsActive, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, Description, ParentItemID, Price, + IsActive, SortOrder) VALUES (:catID, :name, :desc, 0, :price, 1, :sortOrder) ", { catID: saladsCatID, @@ -277,14 +277,14 @@ try { itemOrder = 1; for (item in sideItems) { qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = 0 + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = 0 ", { catID: sidesCatID, name: item.name }, { datasource: "payfrit" }); if (qItem.recordCount == 0) { queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemDescription, ItemParentItemID, ItemPrice, - ItemIsActive, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, Description, ParentItemID, Price, + IsActive, SortOrder) VALUES (:catID, :name, :desc, 0, :price, 1, :sortOrder) ", { catID: sidesCatID, @@ -318,14 +318,14 @@ try { itemOrder = 1; for (item in hotCoffeeItems) { qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = 0 + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = 0 ", { catID: hotCoffeeCatID, name: item.name }, { datasource: "payfrit" }); if (qItem.recordCount == 0) { queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemDescription, ItemParentItemID, ItemPrice, - ItemIsActive, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, Description, ParentItemID, Price, + IsActive, SortOrder) VALUES (:catID, :name, :desc, 0, :price, 1, :sortOrder) ", { catID: hotCoffeeCatID, @@ -356,14 +356,14 @@ try { itemOrder = 1; for (item in icedCoffeeItems) { qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = 0 + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = 0 ", { catID: icedCoffeeCatID, name: item.name }, { datasource: "payfrit" }); if (qItem.recordCount == 0) { queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemDescription, ItemParentItemID, ItemPrice, - ItemIsActive, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, Description, ParentItemID, Price, + IsActive, SortOrder) VALUES (:catID, :name, :desc, 0, :price, 1, :sortOrder) ", { catID: icedCoffeeCatID, @@ -392,14 +392,14 @@ try { itemOrder = 1; for (item in hotTeaItems) { qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = 0 + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = 0 ", { catID: hotTeaCatID, name: item.name }, { datasource: "payfrit" }); if (qItem.recordCount == 0) { queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemDescription, ItemParentItemID, ItemPrice, - ItemIsActive, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, Description, ParentItemID, Price, + IsActive, SortOrder) VALUES (:catID, :name, :desc, 0, :price, 1, :sortOrder) ", { catID: hotTeaCatID, @@ -429,14 +429,14 @@ try { itemOrder = 1; for (item in icedTeaItems) { qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = 0 + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = 0 ", { catID: icedTeaCatID, name: item.name }, { datasource: "payfrit" }); if (qItem.recordCount == 0) { queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemDescription, ItemParentItemID, ItemPrice, - ItemIsActive, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, Description, ParentItemID, Price, + IsActive, SortOrder) VALUES (:catID, :name, :desc, 0, :price, 1, :sortOrder) ", { catID: icedTeaCatID, @@ -467,14 +467,14 @@ try { itemOrder = 1; for (item in bevItems) { qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemCategoryID = :catID AND ItemName = :name AND ItemParentItemID = 0 + SELECT ID FROM Items + WHERE CategoryID = :catID AND Name = :name AND ParentItemID = 0 ", { catID: bevCatID, name: item.name }, { datasource: "payfrit" }); if (qItem.recordCount == 0) { queryExecute(" - INSERT INTO Items (ItemCategoryID, ItemName, ItemDescription, ItemParentItemID, ItemPrice, - ItemIsActive, ItemSortOrder) + INSERT INTO Items (CategoryID, Name, Description, ParentItemID, Price, + IsActive, SortOrder) VALUES (:catID, :name, :desc, 0, :price, 1, :sortOrder) ", { catID: bevCatID, @@ -490,8 +490,8 @@ try { // Count total items qCount = queryExecute(" SELECT COUNT(*) as cnt FROM Items i - INNER JOIN Categories c ON c.CategoryID = i.ItemCategoryID - WHERE c.CategoryBusinessID = :bizID + INNER JOIN Categories c ON c.ID = i.CategoryID + WHERE c.BusinessID = :bizID ", { bizID: BusinessID }, { datasource: "payfrit" }); response.OK = true; diff --git a/api/menu/clearAllData.cfm b/api/menu/clearAllData.cfm index 22649f1..654593e 100644 --- a/api/menu/clearAllData.cfm +++ b/api/menu/clearAllData.cfm @@ -22,10 +22,10 @@ try { // Get counts before deletion qItemCount = queryExecute("SELECT COUNT(*) as cnt FROM Items", {}, { datasource: "payfrit" }); qCatCount = queryExecute("SELECT COUNT(*) as cnt FROM Categories", {}, { datasource: "payfrit" }); - qLinkCount = queryExecute("SELECT COUNT(*) as cnt FROM ItemTemplateLinks", {}, { datasource: "payfrit" }); + qLinkCount = queryExecute("SELECT COUNT(*) as cnt FROM lt_ItemID_TemplateItemID", {}, { datasource: "payfrit" }); // Delete in correct order (foreign key constraints) - queryExecute("DELETE FROM ItemTemplateLinks", {}, { datasource: "payfrit" }); + queryExecute("DELETE FROM lt_ItemID_TemplateItemID", {}, { datasource: "payfrit" }); queryExecute("DELETE FROM Items", {}, { datasource: "payfrit" }); queryExecute("DELETE FROM Categories", {}, { datasource: "payfrit" }); diff --git a/api/menu/clearBusinessData.cfm b/api/menu/clearBusinessData.cfm index c06ac03..8e1bc98 100644 --- a/api/menu/clearBusinessData.cfm +++ b/api/menu/clearBusinessData.cfm @@ -24,30 +24,30 @@ try { } // Get counts before deletion - qItemCount = queryExecute("SELECT COUNT(*) as cnt FROM Items WHERE ItemBusinessID = :bid", { bid: businessID }, { datasource: "payfrit" }); - qCatCount = queryExecute("SELECT COUNT(*) as cnt FROM Categories WHERE CategoryBusinessID = :bid", { bid: businessID }, { datasource: "payfrit" }); + qItemCount = queryExecute("SELECT COUNT(*) as cnt FROM Items WHERE BusinessID = :bid", { bid: businessID }, { datasource: "payfrit" }); + qCatCount = queryExecute("SELECT COUNT(*) as cnt FROM Categories WHERE BusinessID = :bid", { bid: businessID }, { datasource: "payfrit" }); // Get item IDs for this business to delete template links - qItemIds = queryExecute("SELECT ItemID FROM Items WHERE ItemBusinessID = :bid", { bid: businessID }, { datasource: "payfrit" }); + qItemIds = queryExecute("SELECT ID FROM Items WHERE BusinessID = :bid", { bid: businessID }, { datasource: "payfrit" }); itemIds = []; for (row in qItemIds) { - arrayAppend(itemIds, row.ItemID); + arrayAppend(itemIds, row.ID); } deletedLinks = 0; if (arrayLen(itemIds) > 0) { // Delete template links for these items - queryExecute("DELETE FROM ItemTemplateLinks WHERE ItemID IN (:ids) OR TemplateItemID IN (:ids)", + queryExecute("DELETE FROM lt_ItemID_TemplateItemID WHERE ItemID IN (:ids) OR TemplateItemID IN (:ids)", { ids: { value: arrayToList(itemIds), cfsqltype: "cf_sql_varchar", list: true } }, { datasource: "payfrit" }); deletedLinks = arrayLen(itemIds); } // Delete all items for this business - queryExecute("DELETE FROM Items WHERE ItemBusinessID = :bid", { bid: businessID }, { datasource: "payfrit" }); + queryExecute("DELETE FROM Items WHERE BusinessID = :bid", { bid: businessID }, { datasource: "payfrit" }); // Delete all categories for this business - queryExecute("DELETE FROM Categories WHERE CategoryBusinessID = :bid", { bid: businessID }, { datasource: "payfrit" }); + queryExecute("DELETE FROM Categories WHERE BusinessID = :bid", { bid: businessID }, { datasource: "payfrit" }); response = { "OK": true, diff --git a/api/menu/debug.cfm b/api/menu/debug.cfm index 0d3b10c..0eb535a 100644 --- a/api/menu/debug.cfm +++ b/api/menu/debug.cfm @@ -8,58 +8,58 @@ response = {}; try { // Get all businesses with items qBusinesses = queryExecute(" - SELECT DISTINCT i.ItemBusinessID, COUNT(*) as ItemCount + SELECT DISTINCT i.BusinessID, COUNT(*) as ItemCount FROM Items i - WHERE i.ItemBusinessID > 0 - GROUP BY i.ItemBusinessID + WHERE i.BusinessID > 0 + GROUP BY i.BusinessID ", {}, { datasource: "payfrit" }); response["businesses_with_items"] = []; for (b in qBusinesses) { arrayAppend(response["businesses_with_items"], { - "businessID": b.ItemBusinessID, + "businessID": b.ID, "itemCount": b.ItemCount }); } // Get categories qCategories = queryExecute(" - SELECT CategoryBusinessID, COUNT(*) as cnt + SELECT ID, COUNT(*) as cnt FROM Categories - GROUP BY CategoryBusinessID + GROUP BY BusinessID ", {}, { datasource: "payfrit" }); response["categories_by_business"] = []; for (c in qCategories) { arrayAppend(response["categories_by_business"], { - "businessID": c.CategoryBusinessID, + "businessID": c.BusinessID, "count": c.cnt }); } // Get sample items qItems = queryExecute(" - SELECT ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID, ItemName, ItemIsActive + SELECT ID, BusinessID, CategoryID, ParentItemID, Name, IsActive FROM Items - WHERE ItemIsActive = 1 + WHERE IsActive = 1 LIMIT 20 ", {}, { datasource: "payfrit" }); response["sample_items"] = []; for (i in qItems) { arrayAppend(response["sample_items"], { - "id": i.ItemID, - "businessID": i.ItemBusinessID, - "categoryID": i.ItemCategoryID, - "parentID": i.ItemParentItemID, - "name": i.ItemName, - "active": i.ItemIsActive + "id": i.ID, + "businessID": i.BusinessID, + "categoryID": i.CategoryID, + "parentID": i.ParentItemID, + "name": i.Name, + "active": i.IsActive }); } // Get template links qLinks = queryExecute(" - SELECT COUNT(*) as cnt FROM ItemTemplateLinks + SELECT COUNT(*) as cnt FROM lt_ItemID_TemplateItemID ", {}, { datasource: "payfrit" }); response["template_link_count"] = qLinks.cnt; diff --git a/api/menu/getForBuilder.cfm b/api/menu/getForBuilder.cfm index 1d0271c..83e84ec 100644 --- a/api/menu/getForBuilder.cfm +++ b/api/menu/getForBuilder.cfm @@ -11,34 +11,24 @@ response = { "OK": false }; -// Pre-index query rows by parentId for O(1) lookup instead of O(n) scan per level -function buildParentIndex(allOptions) { - var byParent = {}; - for (var i = 1; i <= allOptions.recordCount; i++) { - var pid = allOptions.ParentItemID[i]; - if (!structKeyExists(byParent, pid)) byParent[pid] = []; - arrayAppend(byParent[pid], i); - } - return byParent; -} - -// Recursive function to build nested options (uses pre-built index) -function buildOptionsTree(allOptions, parentId, byParent) { - if (!structKeyExists(byParent, parentId)) return []; +// Recursive function to build nested options +function buildOptionsTree(allOptions, parentId) { var result = []; - for (var idx in byParent[parentId]) { - var children = buildOptionsTree(allOptions, allOptions.ItemID[idx], byParent); - arrayAppend(result, { - "id": "opt_" & allOptions.ItemID[idx], - "dbId": allOptions.ItemID[idx], - "name": allOptions.ItemName[idx], - "price": allOptions.ItemPrice[idx], - "isDefault": allOptions.IsDefault[idx] == 1 ? true : false, - "sortOrder": allOptions.ItemSortOrder[idx], - "requiresSelection": isNull(allOptions.RequiresSelection[idx]) ? false : (allOptions.RequiresSelection[idx] == 1), - "maxSelections": isNull(allOptions.MaxSelections[idx]) ? 0 : allOptions.MaxSelections[idx], - "options": children - }); + for (var i = 1; i <= allOptions.recordCount; i++) { + if (allOptions.ParentItemID[i] == parentId) { + var children = buildOptionsTree(allOptions, allOptions.ItemID[i]); + arrayAppend(result, { + "id": "opt_" & allOptions.ItemID[i], + "dbId": allOptions.ItemID[i], + "name": allOptions.Name[i], + "price": allOptions.Price[i], + "isDefault": allOptions.IsDefault[i] == 1 ? true : false, + "sortOrder": allOptions.SortOrder[i], + "requiresSelection": isNull(allOptions.RequiresSelection[i]) ? false : (allOptions.RequiresSelection[i] == 1), + "maxSelections": isNull(allOptions.MaxSelections[i]) ? 0 : allOptions.MaxSelections[i], + "options": children + }); + } } if (arrayLen(result) > 1) { arraySort(result, function(a, b) { @@ -73,23 +63,23 @@ try { // Get all menus for this business allMenus = []; try { - qMenus = queryTimed(" - SELECT MenuID, MenuName, MenuDescription, MenuDaysActive, - MenuStartTime, MenuEndTime, MenuSortOrder + qMenus = queryExecute(" + SELECT ID, Name, Description, DaysActive, + StartTime, EndTime, SortOrder FROM Menus - WHERE MenuBusinessID = :businessID AND MenuIsActive = 1 - ORDER BY MenuSortOrder, MenuName + WHERE BusinessID = :businessID AND IsActive = 1 + ORDER BY SortOrder, Name ", { businessID: businessID }, { datasource: "payfrit" }); for (m = 1; m <= qMenus.recordCount; m++) { arrayAppend(allMenus, { - "MenuID": qMenus.MenuID[m], - "MenuName": qMenus.MenuName[m], - "MenuDescription": isNull(qMenus.MenuDescription[m]) ? "" : qMenus.MenuDescription[m], - "MenuDaysActive": qMenus.MenuDaysActive[m], - "MenuStartTime": isNull(qMenus.MenuStartTime[m]) ? "" : timeFormat(qMenus.MenuStartTime[m], "HH:mm"), - "MenuEndTime": isNull(qMenus.MenuEndTime[m]) ? "" : timeFormat(qMenus.MenuEndTime[m], "HH:mm"), - "MenuSortOrder": qMenus.MenuSortOrder[m] + "MenuID": qMenus.ID[m], + "Name": qMenus.Name[m], + "Description": isNull(qMenus.Description[m]) ? "" : qMenus.Description[m], + "DaysActive": qMenus.DaysActive[m], + "StartTime": isNull(qMenus.StartTime[m]) ? "" : timeFormat(qMenus.StartTime[m], "HH:mm"), + "EndTime": isNull(qMenus.EndTime[m]) ? "" : timeFormat(qMenus.EndTime[m], "HH:mm"), + "SortOrder": qMenus.SortOrder[m] }); } @@ -102,21 +92,21 @@ try { for (m = 1; m <= qMenus.recordCount; m++) { // Check if menu is active today (days bitmask) - menuDays = qMenus.MenuDaysActive[m]; + menuDays = qMenus.DaysActive[m]; if (bitAnd(menuDays, dayBit) == 0) continue; // Check time range - hasStart = !isNull(qMenus.MenuStartTime[m]); - hasEnd = !isNull(qMenus.MenuEndTime[m]); + hasStart = !isNull(qMenus.StartTime[m]); + hasEnd = !isNull(qMenus.EndTime[m]); if (hasStart && hasEnd) { - startT = timeFormat(qMenus.MenuStartTime[m], "HH:mm"); - endT = timeFormat(qMenus.MenuEndTime[m], "HH:mm"); + startT = timeFormat(qMenus.StartTime[m], "HH:mm"); + endT = timeFormat(qMenus.EndTime[m], "HH:mm"); if (now >= startT && now <= endT) { - arrayAppend(activeMenuIds, qMenus.MenuID[m]); + arrayAppend(activeMenuIds, qMenus.ID[m]); } } else { // No time restriction = always active - arrayAppend(activeMenuIds, qMenus.MenuID[m]); + arrayAppend(activeMenuIds, qMenus.ID[m]); } } @@ -133,8 +123,8 @@ try { // Check if Categories table has data for this business hasCategoriesData = false; try { - qCatCheck = queryTimed(" - SELECT 1 FROM Categories WHERE CategoryBusinessID = :businessID LIMIT 1 + qCatCheck = queryExecute(" + SELECT 1 FROM Categories WHERE BusinessID = :businessID LIMIT 1 ", { businessID: businessID }, { datasource: "payfrit" }); hasCategoriesData = (qCatCheck.recordCount > 0); } catch (any e) { @@ -147,149 +137,149 @@ try { menuFilter = ""; menuParams = { businessID: businessID }; if (menuID > 0) { - menuFilter = " AND CategoryMenuID = :menuID"; + menuFilter = " AND MenuID = :menuID"; menuParams["menuID"] = menuID; } - qCategories = queryTimed(" + qCategories = queryExecute(" SELECT - CategoryID, - CategoryName, - CategorySortOrder as ItemSortOrder, - CategoryMenuID + ID, + Name, + SortOrder as SortOrder, + MenuID FROM Categories - WHERE CategoryBusinessID = :businessID #menuFilter# - ORDER BY CategorySortOrder, CategoryName + WHERE BusinessID = :businessID #menuFilter# + ORDER BY SortOrder, Name ", menuParams, { datasource: "payfrit" }); // Get menu items - items that belong to categories (not modifiers) - qItems = queryTimed(" + qItems = queryExecute(" SELECT - i.ItemID, - i.ItemCategoryID as CategoryItemID, - i.ItemName, - i.ItemDescription, - i.ItemPrice, - i.ItemSortOrder, - i.ItemIsActive + i.ID, + i.CategoryID as CategoryItemID, + i.Name, + i.Description, + i.Price, + i.SortOrder, + i.IsActive FROM Items i - WHERE i.ItemBusinessID = :businessID - AND i.ItemIsActive = 1 - AND i.ItemCategoryID > 0 - ORDER BY i.ItemSortOrder, i.ItemName + WHERE i.BusinessID = :businessID + AND i.IsActive = 1 + AND i.CategoryID > 0 + ORDER BY i.SortOrder, i.Name ", { businessID: businessID }, { datasource: "payfrit" }); // Get direct modifiers (items with ParentItemID pointing to menu items, not categories) - qDirectModifiers = queryTimed(" + qDirectModifiers = queryExecute(" SELECT m.ItemID, - m.ItemParentItemID as ParentItemID, - m.ItemName, - m.ItemPrice, - m.ItemIsCheckedByDefault as IsDefault, - m.ItemSortOrder, - m.ItemRequiresChildSelection as RequiresSelection, - m.ItemMaxNumSelectionReq as MaxSelections + m.ParentItemID as ParentItemID, + m.Name, + m.Price, + m.IsCheckedByDefault as IsDefault, + m.SortOrder, + m.RequiresChildSelection as RequiresSelection, + m.MaxNumSelectionReq as MaxSelections FROM Items m - WHERE m.ItemBusinessID = :businessID - AND m.ItemIsActive = 1 - AND m.ItemParentItemID > 0 - AND (m.ItemCategoryID = 0 OR m.ItemCategoryID IS NULL) - ORDER BY m.ItemSortOrder, m.ItemName + WHERE m.BusinessID = :businessID + AND m.IsActive = 1 + AND m.ParentItemID > 0 + AND (m.CategoryID = 0 OR m.CategoryID IS NULL) + ORDER BY m.SortOrder, m.Name ", { businessID: businessID }, { datasource: "payfrit" }); } else { // NEW UNIFIED SCHEMA: Categories are Items at ParentID=0 with children - qCategories = queryTimed(" + qCategories = queryExecute(" SELECT DISTINCT p.ItemID as CategoryID, - p.ItemName as CategoryName, - p.ItemSortOrder + p.Name as Name, + p.SortOrder FROM Items p - INNER JOIN Items c ON c.ItemParentItemID = p.ItemID - WHERE p.ItemBusinessID = :businessID - AND p.ItemParentItemID = 0 - AND p.ItemIsActive = 1 + INNER JOIN Items c ON c.ParentItemID = p.ItemID + WHERE p.BusinessID = :businessID + AND p.ParentItemID = 0 + AND p.IsActive = 1 AND NOT EXISTS ( - SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = p.ItemID + SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = p.ItemID ) - ORDER BY p.ItemSortOrder, p.ItemName + ORDER BY p.SortOrder, p.Name ", { businessID: businessID }, { datasource: "payfrit" }); - qItems = queryTimed(" + qItems = queryExecute(" SELECT - i.ItemID, - i.ItemParentItemID as CategoryItemID, - i.ItemName, - i.ItemDescription, - i.ItemPrice, - i.ItemSortOrder, - i.ItemIsActive + i.ID, + i.ParentItemID as CategoryItemID, + i.Name, + i.Description, + i.Price, + i.SortOrder, + i.IsActive FROM Items i - INNER JOIN Items cat ON cat.ItemID = i.ItemParentItemID - WHERE i.ItemBusinessID = :businessID - AND i.ItemIsActive = 1 - AND cat.ItemParentItemID = 0 + INNER JOIN Items cat ON cat.ID = i.ParentItemID + WHERE i.BusinessID = :businessID + AND i.IsActive = 1 + AND cat.ParentItemID = 0 AND NOT EXISTS ( - SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = cat.ItemID + SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = cat.ID ) - ORDER BY i.ItemSortOrder, i.ItemName + ORDER BY i.SortOrder, i.Name ", { businessID: businessID }, { datasource: "payfrit" }); - qDirectModifiers = queryTimed(" + qDirectModifiers = queryExecute(" SELECT m.ItemID, - m.ItemParentItemID as ParentItemID, - m.ItemName, - m.ItemPrice, - m.ItemIsCheckedByDefault as IsDefault, - m.ItemSortOrder, - m.ItemRequiresChildSelection as RequiresSelection, - m.ItemMaxNumSelectionReq as MaxSelections + m.ParentItemID as ParentItemID, + m.Name, + m.Price, + m.IsCheckedByDefault as IsDefault, + m.SortOrder, + m.RequiresChildSelection as RequiresSelection, + m.MaxNumSelectionReq as MaxSelections FROM Items m - WHERE m.ItemBusinessID = :businessID - AND m.ItemIsActive = 1 - AND m.ItemParentItemID > 0 - ORDER BY m.ItemSortOrder, m.ItemName + WHERE m.BusinessID = :businessID + AND m.IsActive = 1 + AND m.ParentItemID > 0 + ORDER BY m.SortOrder, m.Name ", { businessID: businessID }, { datasource: "payfrit" }); } // Collect menu item IDs for filtering template links menuItemIds = []; for (i = 1; i <= qItems.recordCount; i++) { - arrayAppend(menuItemIds, qItems.ItemID[i]); + arrayAppend(menuItemIds, qItems.ID[i]); } // Get template links ONLY for this business's menu items qTemplateLinks = queryNew("ParentItemID,TemplateItemID,SortOrder"); if (arrayLen(menuItemIds) > 0) { - qTemplateLinks = queryTimed(" + qTemplateLinks = queryExecute(" SELECT tl.ItemID as ParentItemID, tl.TemplateItemID, tl.SortOrder - FROM ItemTemplateLinks tl + FROM lt_ItemID_TemplateItemID tl WHERE tl.ItemID IN (:itemIds) ORDER BY tl.ItemID, tl.SortOrder ", { itemIds: { value: arrayToList(menuItemIds), cfsqltype: "cf_sql_varchar", list: true } }, { datasource: "payfrit" }); } // Get templates for this business only - qTemplates = queryTimed(" + qTemplates = queryExecute(" SELECT DISTINCT t.ItemID, - t.ItemName, - t.ItemPrice, - t.ItemIsCheckedByDefault as IsDefault, - t.ItemSortOrder, - t.ItemRequiresChildSelection as RequiresSelection, - t.ItemMaxNumSelectionReq as MaxSelections + t.Name, + t.Price, + t.IsCheckedByDefault as IsDefault, + t.SortOrder, + t.RequiresChildSelection as RequiresSelection, + t.MaxNumSelectionReq as MaxSelections FROM Items t - WHERE t.ItemBusinessID = :businessID - AND (t.ItemCategoryID = 0 OR t.ItemCategoryID IS NULL) - AND t.ItemParentItemID = 0 - AND t.ItemIsActive = 1 - ORDER BY t.ItemSortOrder, t.ItemName + WHERE t.BusinessID = :businessID + AND (t.CategoryID = 0 OR t.CategoryID IS NULL) + AND t.ParentItemID = 0 + AND t.IsActive = 1 + ORDER BY t.SortOrder, t.Name ", { businessID: businessID }, { datasource: "payfrit" }); // Get template children (options within templates) @@ -298,38 +288,37 @@ try { arrayAppend(templateIds, qTemplates.ItemID[i]); } - qTemplateChildren = queryNew("ItemID,ParentItemID,ItemName,ItemPrice,IsDefault,ItemSortOrder,RequiresSelection,MaxSelections"); + qTemplateChildren = queryNew("ItemID,ParentItemID,Name,Price,IsDefault,SortOrder,RequiresSelection,MaxSelections"); if (arrayLen(templateIds) > 0) { - qTemplateChildren = queryTimed(" + qTemplateChildren = queryExecute(" SELECT c.ItemID, - c.ItemParentItemID as ParentItemID, - c.ItemName, - c.ItemPrice, - c.ItemIsCheckedByDefault as IsDefault, - c.ItemSortOrder, - c.ItemRequiresChildSelection as RequiresSelection, - c.ItemMaxNumSelectionReq as MaxSelections + c.ParentItemID as ParentItemID, + c.Name, + c.Price, + c.IsCheckedByDefault as IsDefault, + c.SortOrder, + c.RequiresChildSelection as RequiresSelection, + c.MaxNumSelectionReq as MaxSelections FROM Items c - WHERE c.ItemParentItemID IN (:templateIds) - AND c.ItemIsActive = 1 - ORDER BY c.ItemSortOrder, c.ItemName + WHERE c.ParentItemID IN (:templateIds) + AND c.IsActive = 1 + ORDER BY c.SortOrder, c.Name ", { templateIds: { value: arrayToList(templateIds), cfsqltype: "cf_sql_varchar", list: true } }, { datasource: "payfrit" }); } - // Build templates lookup with their options (pre-index for fast tree building) - templateChildrenIndex = buildParentIndex(qTemplateChildren); + // Build templates lookup with their options templatesById = {}; for (i = 1; i <= qTemplates.recordCount; i++) { templateID = qTemplates.ItemID[i]; - options = buildOptionsTree(qTemplateChildren, templateID, templateChildrenIndex); + options = buildOptionsTree(qTemplateChildren, templateID); templatesById[templateID] = { "id": "mod_" & qTemplates.ItemID[i], "dbId": qTemplates.ItemID[i], - "name": qTemplates.ItemName[i], - "price": qTemplates.ItemPrice[i], + "name": qTemplates.Name[i], + "price": qTemplates.Price[i], "isDefault": qTemplates.IsDefault[i] == 1 ? true : false, - "sortOrder": qTemplates.ItemSortOrder[i], + "sortOrder": qTemplates.SortOrder[i], "isTemplate": true, "requiresSelection": isNull(qTemplates.RequiresSelection[i]) ? false : (qTemplates.RequiresSelection[i] == 1), "maxSelections": isNull(qTemplates.MaxSelections[i]) ? 0 : qTemplates.MaxSelections[i], @@ -354,11 +343,10 @@ try { } } - // Build nested direct modifiers for each menu item (pre-index for fast tree building) - directModifiersIndex = buildParentIndex(qDirectModifiers); + // Build nested direct modifiers for each menu item directModsByItem = {}; for (itemId in menuItemIds) { - options = buildOptionsTree(qDirectModifiers, itemId, directModifiersIndex); + options = buildOptionsTree(qDirectModifiers, itemId); if (arrayLen(options) > 0) { directModsByItem[itemId] = options; } @@ -372,7 +360,7 @@ try { itemsByCategory[catID] = []; } - itemID = qItems.ItemID[i]; + itemID = qItems.ID[i]; // Get template-linked modifiers itemModifiers = structKeyExists(templateLinksByItem, itemID) ? duplicate(templateLinksByItem[itemID]) : []; @@ -396,22 +384,22 @@ try { itemImageUrl = ""; itemsDir = expandPath("/uploads/items"); for (ext in ["jpg","jpeg","png","gif","webp","JPG","JPEG","PNG","GIF","WEBP"]) { - if (fileExists(itemsDir & "/" & qItems.ItemID[i] & "." & ext)) { - itemImageUrl = "/uploads/items/" & qItems.ItemID[i] & "." & ext; + if (fileExists(itemsDir & "/" & qItems.ID[i] & "." & ext)) { + itemImageUrl = "/uploads/items/" & qItems.ID[i] & "." & ext; break; } } arrayAppend(itemsByCategory[catID], { - "id": "item_" & qItems.ItemID[i], - "dbId": qItems.ItemID[i], - "name": qItems.ItemName[i], - "description": isNull(qItems.ItemDescription[i]) ? "" : qItems.ItemDescription[i], - "price": qItems.ItemPrice[i], + "id": "item_" & qItems.ID[i], + "dbId": qItems.ID[i], + "name": qItems.Name[i], + "description": isNull(qItems.Description[i]) ? "" : qItems.Description[i], + "price": qItems.Price[i], "imageUrl": len(itemImageUrl) ? itemImageUrl : javaCast("null", ""), "photoTaskId": javaCast("null", ""), "modifiers": itemModifiers, - "sortOrder": qItems.ItemSortOrder[i] + "sortOrder": qItems.SortOrder[i] }); } @@ -419,13 +407,13 @@ try { categories = []; catIndex = 0; for (i = 1; i <= qCategories.recordCount; i++) { - catID = qCategories.CategoryID[i]; + catID = qCategories.ID[i]; catItems = structKeyExists(itemsByCategory, catID) ? itemsByCategory[catID] : []; catStruct = { - "id": "cat_" & qCategories.CategoryID[i], - "dbId": qCategories.CategoryID[i], - "name": qCategories.CategoryName[i], + "id": "cat_" & qCategories.ID[i], + "dbId": qCategories.ID[i], + "name": qCategories.Name[i], "description": "", "sortOrder": catIndex, "items": catItems @@ -434,7 +422,7 @@ try { // Include MenuID if available (legacy schema with Categories table) if (hasCategoriesData) { try { - catStruct["menuId"] = isNull(qCategories.CategoryMenuID[i]) ? 0 : val(qCategories.CategoryMenuID[i]); + catStruct["menuId"] = isNull(qCategories.MenuID[i]) ? 0 : val(qCategories.MenuID[i]); } catch (any e) { catStruct["menuId"] = 0; } @@ -453,11 +441,11 @@ try { // Get business brand color brandColor = ""; try { - qBrand = queryTimed(" - SELECT BusinessBrandColor FROM Businesses WHERE BusinessID = :bizId + qBrand = queryExecute(" + SELECT BrandColor FROM Businesses WHERE ID = :bizId ", { bizId: businessID }, { datasource: "payfrit" }); - if (qBrand.recordCount > 0 && len(trim(qBrand.BusinessBrandColor))) { - brandColor = left(qBrand.BusinessBrandColor, 1) == chr(35) ? qBrand.BusinessBrandColor : chr(35) & qBrand.BusinessBrandColor; + if (qBrand.recordCount > 0 && len(trim(qBrand.BrandColor))) { + brandColor = left(qBrand.BrandColor, 1) == chr(35) ? qBrand.BrandColor : chr(35) & qBrand.BrandColor; } } catch (any e) { // Column may not exist yet, ignore @@ -486,6 +474,5 @@ try { response["DETAIL"] = e.detail ?: ""; } -logPerf(); writeOutput(serializeJSON(response)); diff --git a/api/menu/items.cfm b/api/menu/items.cfm index 780f5a8..a793a44 100644 --- a/api/menu/items.cfm +++ b/api/menu/items.cfm @@ -48,27 +48,17 @@ - - - - - - - #cachedMenu# - - - - + - 0", + 0", [ { value = BusinessID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" } )> @@ -80,12 +70,12 @@ - + - @@ -96,17 +86,17 @@ - + - - + @@ -134,42 +124,42 @@ - 0 + OR FIND_IN_SET(:orderTypeId, OrderTypes) > 0 ) AND ( - CategoryScheduleStart IS NULL - OR CategoryScheduleEnd IS NULL + ScheduleStart IS NULL + OR ScheduleEnd IS NULL OR ( - TIME(:currentTime) >= CategoryScheduleStart - AND TIME(:currentTime) <= CategoryScheduleEnd + TIME(:currentTime) >= ScheduleStart + AND TIME(:currentTime) <= ScheduleEnd ) ) AND ( - CategoryScheduleDays IS NULL - OR CategoryScheduleDays = '' - OR FIND_IN_SET(:currentDay, CategoryScheduleDays) > 0 + ScheduleDays IS NULL + OR ScheduleDays = '' + OR FIND_IN_SET(:currentDay, ScheduleDays) > 0 ) AND ( - CategoryMenuID IS NULL - OR CategoryMenuID = 0 - #len(activeMenuIds) ? "OR CategoryMenuID IN (#activeMenuIds#)" : ""# + MenuID IS NULL + OR MenuID = 0 + #len(activeMenuIds) ? "OR MenuID IN (#activeMenuIds#)" : ""# ) - ORDER BY CategorySortOrder + ORDER BY SortOrder ", { bizId: { value = BusinessID, cfsqltype = "cf_sql_integer" }, @@ -184,94 +174,93 @@ - + - - 0 - OR (i.ItemParentItemID = 0 AND i.ItemIsCollapsible = 0) + i.ParentItemID > 0 + OR (i.ParentItemID = 0 AND i.IsCollapsible = 0) ) - ORDER BY i.ItemParentItemID, i.ItemSortOrder, i.ItemID + ORDER BY i.ParentItemID, i.SortOrder, i.ID ", [ { value = BusinessID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" } @@ -279,31 +268,30 @@ - - - + + - + @@ -352,72 +339,66 @@ - + - - - + + + - - + + - - + + - + - - - - - - - @@ -485,21 +466,21 @@ @@ -509,21 +490,21 @@ @@ -533,20 +514,20 @@ - - - + + - - - - - #menuResponse# - 0) { queryExecute(" - UPDATE Categories SET CategoryMenuID = 0 - WHERE CategoryMenuID = :menuID AND CategoryBusinessID = :businessID + UPDATE Categories SET MenuID = 0 + WHERE MenuID = :menuID AND BusinessID = :businessID ", { menuID: menuID, businessID: businessID }, { datasource: "payfrit" }); } // Soft-delete the menu queryExecute(" - UPDATE Menus SET MenuIsActive = 0 - WHERE MenuID = :menuID AND MenuBusinessID = :businessID + UPDATE Menus SET IsActive = 0 + WHERE ID = :menuID AND BusinessID = :businessID ", { menuID: menuID, businessID: businessID }, { datasource: "payfrit" }); response = { @@ -227,8 +227,8 @@ try { for (i = 1; i <= arrayLen(menuOrder); i++) { queryExecute(" - UPDATE Menus SET MenuSortOrder = :sortOrder - WHERE MenuID = :menuID AND MenuBusinessID = :businessID + UPDATE Menus SET SortOrder = :sortOrder + WHERE ID = :menuID AND BusinessID = :businessID ", { menuID: val(menuOrder[i]), businessID: businessID, diff --git a/api/menu/saveCategory.cfm b/api/menu/saveCategory.cfm index 5d8ee1d..3bc66c1 100644 --- a/api/menu/saveCategory.cfm +++ b/api/menu/saveCategory.cfm @@ -10,13 +10,13 @@ * POST body: * { * "CategoryID": 123, // Required for update - * "CategoryBusinessID": 37, // Required for insert - * "CategoryName": "Breakfast", - * "CategorySortOrder": 1, - * "CategoryOrderTypes": "1,2,3", // 1=Dine-In, 2=Takeaway, 3=Delivery - * "CategoryScheduleStart": "06:00:00", // Optional, null = always available - * "CategoryScheduleEnd": "11:00:00", // Optional - * "CategoryScheduleDays": "2,3,4,5,6" // Optional, 1=Sun..7=Sat, null = all days + * "BusinessID": 37, // Required for insert + * "Name": "Breakfast", + * "SortOrder": 1, + * "OrderTypes": "1,2,3", // 1=Dine-In, 2=Takeaway, 3=Delivery + * "ScheduleStart": "06:00:00", // Optional, null = always available + * "ScheduleEnd": "11:00:00", // Optional + * "ScheduleDays": "2,3,4,5,6" // Optional, 1=Sun..7=Sat, null = all days * } */ @@ -37,58 +37,58 @@ try { data = readJsonBody(); CategoryID = structKeyExists(data, "CategoryID") ? val(data.CategoryID) : 0; - CategoryBusinessID = structKeyExists(data, "CategoryBusinessID") ? val(data.CategoryBusinessID) : 0; - CategoryName = structKeyExists(data, "CategoryName") ? left(trim(data.CategoryName), 30) : ""; - CategorySortOrder = structKeyExists(data, "CategorySortOrder") ? val(data.CategorySortOrder) : 0; - CategoryOrderTypes = structKeyExists(data, "CategoryOrderTypes") ? trim(data.CategoryOrderTypes) : "1,2,3"; - CategoryScheduleStart = structKeyExists(data, "CategoryScheduleStart") && len(trim(data.CategoryScheduleStart)) - ? trim(data.CategoryScheduleStart) : javaCast("null", ""); - CategoryScheduleEnd = structKeyExists(data, "CategoryScheduleEnd") && len(trim(data.CategoryScheduleEnd)) - ? trim(data.CategoryScheduleEnd) : javaCast("null", ""); - CategoryScheduleDays = structKeyExists(data, "CategoryScheduleDays") && len(trim(data.CategoryScheduleDays)) - ? trim(data.CategoryScheduleDays) : javaCast("null", ""); + BusinessID = structKeyExists(data, "BusinessID") ? val(data.BusinessID) : 0; + Name = structKeyExists(data, "Name") ? left(trim(data.Name), 30) : ""; + SortOrder = structKeyExists(data, "SortOrder") ? val(data.SortOrder) : 0; + OrderTypes = structKeyExists(data, "OrderTypes") ? trim(data.OrderTypes) : "1,2,3"; + ScheduleStart = structKeyExists(data, "ScheduleStart") && len(trim(data.ScheduleStart)) + ? trim(data.ScheduleStart) : javaCast("null", ""); + ScheduleEnd = structKeyExists(data, "ScheduleEnd") && len(trim(data.ScheduleEnd)) + ? trim(data.ScheduleEnd) : javaCast("null", ""); + ScheduleDays = structKeyExists(data, "ScheduleDays") && len(trim(data.ScheduleDays)) + ? trim(data.ScheduleDays) : javaCast("null", ""); if (CategoryID > 0) { // Update existing category queryExecute(" UPDATE Categories SET - CategoryName = :name, - CategorySortOrder = :sortOrder, - CategoryOrderTypes = :orderTypes, - CategoryScheduleStart = :schedStart, - CategoryScheduleEnd = :schedEnd, - CategoryScheduleDays = :schedDays - WHERE CategoryID = :catId + Name = :name, + SortOrder = :sortOrder, + OrderTypes = :orderTypes, + ScheduleStart = :schedStart, + ScheduleEnd = :schedEnd, + ScheduleDays = :schedDays + WHERE ID = :catId ", { catId: CategoryID, - name: CategoryName, - sortOrder: CategorySortOrder, - orderTypes: CategoryOrderTypes, - schedStart: { value = CategoryScheduleStart, cfsqltype = "cf_sql_time", null = isNull(CategoryScheduleStart) }, - schedEnd: { value = CategoryScheduleEnd, cfsqltype = "cf_sql_time", null = isNull(CategoryScheduleEnd) }, - schedDays: { value = CategoryScheduleDays, cfsqltype = "cf_sql_varchar", null = isNull(CategoryScheduleDays) } + name: Name, + sortOrder: SortOrder, + orderTypes: OrderTypes, + schedStart: { value = ScheduleStart, cfsqltype = "cf_sql_time", null = isNull(ScheduleStart) }, + schedEnd: { value = ScheduleEnd, cfsqltype = "cf_sql_time", null = isNull(ScheduleEnd) }, + schedDays: { value = ScheduleDays, cfsqltype = "cf_sql_varchar", null = isNull(ScheduleDays) } }, { datasource = "payfrit" }); response["OK"] = true; response["CategoryID"] = CategoryID; response["MESSAGE"] = "Category updated"; - } else if (CategoryBusinessID > 0 && len(CategoryName)) { + } else if (BusinessID > 0 && len(Name)) { // Insert new category queryExecute(" INSERT INTO Categories - (CategoryBusinessID, CategoryName, CategorySortOrder, CategoryOrderTypes, - CategoryScheduleStart, CategoryScheduleEnd, CategoryScheduleDays, CategoryAddedOn) + (BusinessID, Name, SortOrder, OrderTypes, + ScheduleStart, ScheduleEnd, ScheduleDays, AddedOn) VALUES (:bizId, :name, :sortOrder, :orderTypes, :schedStart, :schedEnd, :schedDays, NOW()) ", { - bizId: CategoryBusinessID, - name: CategoryName, - sortOrder: CategorySortOrder, - orderTypes: CategoryOrderTypes, - schedStart: { value = CategoryScheduleStart, cfsqltype = "cf_sql_time", null = isNull(CategoryScheduleStart) }, - schedEnd: { value = CategoryScheduleEnd, cfsqltype = "cf_sql_time", null = isNull(CategoryScheduleEnd) }, - schedDays: { value = CategoryScheduleDays, cfsqltype = "cf_sql_varchar", null = isNull(CategoryScheduleDays) } + bizId: BusinessID, + name: Name, + sortOrder: SortOrder, + orderTypes: OrderTypes, + schedStart: { value = ScheduleStart, cfsqltype = "cf_sql_time", null = isNull(ScheduleStart) }, + schedEnd: { value = ScheduleEnd, cfsqltype = "cf_sql_time", null = isNull(ScheduleEnd) }, + schedDays: { value = ScheduleDays, cfsqltype = "cf_sql_varchar", null = isNull(ScheduleDays) } }, { datasource = "payfrit" }); qNew = queryExecute("SELECT LAST_INSERT_ID() as newId", {}, { datasource = "payfrit" }); @@ -98,7 +98,7 @@ try { } else { response["ERROR"] = "invalid_params"; - response["MESSAGE"] = "CategoryID required for update, or CategoryBusinessID and CategoryName for insert"; + response["MESSAGE"] = "CategoryID required for update, or BusinessID and Name for insert"; } } catch (any e) { diff --git a/api/menu/saveFromBuilder.cfm b/api/menu/saveFromBuilder.cfm index 2f6f215..dcbd92b 100644 --- a/api/menu/saveFromBuilder.cfm +++ b/api/menu/saveFromBuilder.cfm @@ -24,13 +24,13 @@ function saveOptionsRecursive(options, parentID, businessID) { optionID = optDbId; queryExecute(" UPDATE Items - SET ItemName = :name, - ItemPrice = :price, - ItemIsCheckedByDefault = :isDefault, - ItemSortOrder = :sortOrder, - ItemRequiresChildSelection = :requiresSelection, - ItemMaxNumSelectionReq = :maxSelections, - ItemParentItemID = :parentID + SET Name = :name, + Price = :price, + IsCheckedByDefault = :isDefault, + SortOrder = :sortOrder, + RequiresChildSelection = :requiresSelection, + MaxNumSelectionReq = :maxSelections, + ParentItemID = :parentID WHERE ItemID = :optID ", { optID: optDbId, @@ -45,9 +45,9 @@ function saveOptionsRecursive(options, parentID, businessID) { } else { queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemParentItemID, ItemName, ItemPrice, - ItemIsCheckedByDefault, ItemSortOrder, ItemIsActive, ItemAddedOn, - ItemRequiresChildSelection, ItemMaxNumSelectionReq, ItemCategoryID + BusinessID, ParentItemID, Name, Price, + IsCheckedByDefault, SortOrder, IsActive, AddedOn, + RequiresChildSelection, MaxNumSelectionReq, CategoryID ) VALUES ( :businessID, :parentID, :name, :price, :isDefault, :sortOrder, 1, NOW(), @@ -100,7 +100,7 @@ try { try { qCheck = queryExecute(" SELECT 1 FROM Items - WHERE ItemBusinessID = :businessID AND ItemBusinessID > 0 + WHERE BusinessID = :businessID AND BusinessID > 0 LIMIT 1 ", { businessID: businessID }); newSchemaActive = (qCheck.recordCount > 0); @@ -120,10 +120,10 @@ try { categoryID = categoryDbId; queryExecute(" UPDATE Items - SET ItemName = :name, - ItemSortOrder = :sortOrder + SET Name = :name, + SortOrder = :sortOrder WHERE ItemID = :categoryID - AND ItemBusinessID = :businessID + AND BusinessID = :businessID ", { categoryID: categoryID, businessID: businessID, @@ -133,9 +133,9 @@ try { } else { queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemName, ItemDescription, - ItemParentItemID, ItemPrice, ItemIsActive, - ItemSortOrder, ItemAddedOn, ItemCategoryID + BusinessID, Name, Description, + ParentItemID, Price, IsActive, + SortOrder, AddedOn, CategoryID ) VALUES ( :businessID, :name, '', 0, 0, 1, @@ -159,9 +159,9 @@ try { categoryID = categoryDbId; queryExecute(" UPDATE Categories - SET CategoryName = :name, - CategorySortOrder = :sortOrder, - CategoryMenuID = :menuId + SET Name = :name, + SortOrder = :sortOrder, + MenuID = :menuId WHERE CategoryID = :categoryID ", { categoryID: categoryID, @@ -171,7 +171,7 @@ try { }); } else { queryExecute(" - INSERT INTO Categories (CategoryBusinessID, CategoryMenuID, CategoryName, CategorySortOrder, CategoryAddedOn) + INSERT INTO Categories (BusinessID, MenuID, Name, SortOrder, AddedOn) VALUES (:businessID, :menuId, :name, :sortOrder, NOW()) ", { businessID: businessID, @@ -198,11 +198,11 @@ try { if (newSchemaActive) { queryExecute(" UPDATE Items - SET ItemName = :name, - ItemDescription = :description, - ItemPrice = :price, - ItemParentItemID = :categoryID, - ItemSortOrder = :sortOrder + SET Name = :name, + Description = :description, + Price = :price, + ParentItemID = :categoryID, + SortOrder = :sortOrder WHERE ItemID = :itemID ", { itemID: itemID, @@ -215,11 +215,11 @@ try { } else { queryExecute(" UPDATE Items - SET ItemName = :name, - ItemDescription = :description, - ItemPrice = :price, - ItemCategoryID = :categoryID, - ItemSortOrder = :sortOrder + SET Name = :name, + Description = :description, + Price = :price, + CategoryID = :categoryID, + SortOrder = :sortOrder WHERE ItemID = :itemID ", { itemID: itemID, @@ -234,8 +234,8 @@ try { if (newSchemaActive) { queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemParentItemID, ItemName, ItemDescription, - ItemPrice, ItemSortOrder, ItemIsActive, ItemAddedOn, ItemCategoryID + BusinessID, ParentItemID, Name, Description, + Price, SortOrder, IsActive, AddedOn, CategoryID ) VALUES ( :businessID, :categoryID, :name, :description, :price, :sortOrder, 1, NOW(), 0 @@ -251,8 +251,8 @@ try { } else { queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemCategoryID, ItemName, ItemDescription, - ItemPrice, ItemSortOrder, ItemIsActive, ItemParentItemID, ItemAddedOn + BusinessID, CategoryID, Name, Description, + Price, SortOrder, IsActive, ParentItemID, AddedOn ) VALUES ( :businessID, :categoryID, :name, :description, :price, :sortOrder, 1, 0, NOW() @@ -274,7 +274,7 @@ try { // Handle modifiers if (structKeyExists(item, "modifiers") && isArray(item.modifiers) && arrayLen(item.modifiers) > 0) { // Clear existing template links for this item - queryExecute("DELETE FROM ItemTemplateLinks WHERE ItemID = :itemID", { itemID: itemID }); + queryExecute("DELETE FROM lt_ItemID_TemplateItemID WHERE ItemID = :itemID", { itemID: itemID }); modSortOrder = 0; for (mod in item.modifiers) { @@ -285,7 +285,7 @@ try { if (structKeyExists(mod, "isTemplate") && mod.isTemplate && modDbId > 0) { // This is a template reference - create link queryExecute(" - INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder) + INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder) VALUES (:itemID, :templateID, :sortOrder) ON DUPLICATE KEY UPDATE SortOrder = :sortOrder ", { @@ -297,8 +297,8 @@ try { // Update template's selection rules queryExecute(" UPDATE Items - SET ItemRequiresChildSelection = :requiresSelection, - ItemMaxNumSelectionReq = :maxSelections + SET RequiresChildSelection = :requiresSelection, + MaxNumSelectionReq = :maxSelections WHERE ItemID = :modID ", { modID: modDbId, @@ -317,13 +317,13 @@ try { // Direct modifier (not a template) - update it queryExecute(" UPDATE Items - SET ItemName = :name, - ItemPrice = :price, - ItemIsCheckedByDefault = :isDefault, - ItemSortOrder = :sortOrder, - ItemRequiresChildSelection = :requiresSelection, - ItemMaxNumSelectionReq = :maxSelections, - ItemParentItemID = :parentID + SET Name = :name, + Price = :price, + IsCheckedByDefault = :isDefault, + SortOrder = :sortOrder, + RequiresChildSelection = :requiresSelection, + MaxNumSelectionReq = :maxSelections, + ParentItemID = :parentID WHERE ItemID = :modID ", { modID: modDbId, @@ -343,9 +343,9 @@ try { // New direct modifier - insert it queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemParentItemID, ItemName, ItemPrice, - ItemIsCheckedByDefault, ItemSortOrder, ItemIsActive, ItemAddedOn, - ItemRequiresChildSelection, ItemMaxNumSelectionReq, ItemCategoryID + BusinessID, ParentItemID, Name, Price, + IsCheckedByDefault, SortOrder, IsActive, AddedOn, + RequiresChildSelection, MaxNumSelectionReq, CategoryID ) VALUES ( :businessID, :parentID, :name, :price, :isDefault, :sortOrder, 1, NOW(), @@ -379,9 +379,6 @@ try { } response = { "OK": true, "SCHEMA": newSchemaActive ? "unified" : "legacy" }; - // Invalidate menu cache for this business - appCacheInvalidate("menu_" & businessID); - appCacheInvalidate("menuBuilder_" & businessID); } catch (any e) { response = { diff --git a/api/menu/updateStations.cfm b/api/menu/updateStations.cfm index 2363302..a3d1b68 100644 --- a/api/menu/updateStations.cfm +++ b/api/menu/updateStations.cfm @@ -38,11 +38,11 @@ - + @@ -50,7 +50,7 @@ - SELECT BusinessHeaderImageExtension + SELECT HeaderImageExtension FROM Businesses - WHERE BusinessID = + WHERE ID = - - + + @@ -75,7 +75,7 @@ if (bizId LTE 0) { UPDATE Businesses - SET BusinessHeaderImageExtension = + SET HeaderImageExtension = WHERE BusinessID = diff --git a/api/orders/abandonOrder.cfm b/api/orders/abandonOrder.cfm index cf9794d..586a83a 100644 --- a/api/orders/abandonOrder.cfm +++ b/api/orders/abandonOrder.cfm @@ -37,7 +37,7 @@ @@ -46,20 +46,20 @@ - + diff --git a/api/orders/checkStatusUpdate.cfm b/api/orders/checkStatusUpdate.cfm index edc5de6..cac62ec 100644 --- a/api/orders/checkStatusUpdate.cfm +++ b/api/orders/checkStatusUpdate.cfm @@ -30,15 +30,15 @@ SELECT - OrderID, - OrderStatusID, - OrderLastEditedOn, - OrderServicePointID, - OrderBusinessID, - OrderUserID + ID, + StatusID, + LastEditedOn, + ServicePointID, + BusinessID, + UserID FROM Orders - WHERE OrderID = - AND OrderStatusID != + WHERE ID = + AND StatusID != @@ -47,7 +47,7 @@ - + @@ -84,11 +84,11 @@ @@ -103,6 +103,5 @@ - #serializeJSON(payload)# diff --git a/api/orders/debugLineItems.cfm b/api/orders/debugLineItems.cfm index 38b1caf..1529f7d 100644 --- a/api/orders/debugLineItems.cfm +++ b/api/orders/debugLineItems.cfm @@ -14,33 +14,33 @@ diff --git a/api/orders/getActiveCart.cfm b/api/orders/getActiveCart.cfm index ae84140..c82cc9c 100644 --- a/api/orders/getActiveCart.cfm +++ b/api/orders/getActiveCart.cfm @@ -29,27 +29,27 @@ try { // Get active cart (status = 0) for this user qCart = queryExecute(" SELECT - o.OrderID, - o.OrderUUID, - o.OrderBusinessID, + o.ID, + o.UUID, + o.BusinessID, o.OrderTypeID, - o.OrderStatusID, - o.OrderServicePointID, - o.OrderAddedOn, - b.BusinessName, - b.BusinessOrderTypes, - sp.ServicePointName, + o.StatusID, + o.ServicePointID, + o.AddedOn, + b.Name, + b.OrderTypes, + sp.Name, (SELECT COUNT(*) FROM OrderLineItems oli - WHERE oli.OrderLineItemOrderID = o.OrderID - AND oli.OrderLineItemIsDeleted = 0 - AND oli.OrderLineItemParentOrderLineItemID = 0) as ItemCount + WHERE oli.OrderID = o.ID + AND oli.IsDeleted = 0 + AND oli.ParentOrderLineItemID = 0) as ItemCount FROM Orders o - LEFT JOIN Businesses b ON b.BusinessID = o.OrderBusinessID - LEFT JOIN ServicePoints sp ON sp.ServicePointID = o.OrderServicePointID - WHERE o.OrderUserID = :userId - AND o.OrderStatusID = 0 - ORDER BY o.OrderID DESC + LEFT JOIN Businesses b ON b.ID = o.BusinessID + LEFT JOIN ServicePoints sp ON sp.ID = o.ServicePointID + WHERE o.UserID = :userId + AND o.StatusID = 0 + ORDER BY o.ID DESC LIMIT 1 ", { userId: { value: UserID, cfsqltype: "cf_sql_integer" } @@ -65,23 +65,23 @@ try { } // Parse business order types (e.g., "1,2,3" -> array of ints) - businessOrderTypes = len(trim(qCart.BusinessOrderTypes)) ? qCart.BusinessOrderTypes : "1,2,3"; + businessOrderTypes = len(trim(qCart.OrderTypes)) ? qCart.OrderTypes : "1,2,3"; orderTypesArray = listToArray(businessOrderTypes, ","); response["OK"] = true; response["HAS_CART"] = true; response["CART"] = { "OrderID": val(qCart.OrderID), - "OrderUUID": qCart.OrderUUID ?: "", - "BusinessID": val(qCart.OrderBusinessID), - "BusinessName": len(trim(qCart.BusinessName)) ? qCart.BusinessName : "", - "BusinessOrderTypes": orderTypesArray, + "UUID": qCart.UUID ?: "", + "BusinessID": val(qCart.BusinessID), + "Name": len(trim(qCart.Name)) ? qCart.Name : "", + "OrderTypes": orderTypesArray, "OrderTypeID": val(qCart.OrderTypeID), "OrderTypeName": orderTypeName, - "ServicePointID": val(qCart.OrderServicePointID), - "ServicePointName": len(trim(qCart.ServicePointName)) ? qCart.ServicePointName : "", + "ServicePointID": val(qCart.ServicePointID), + "Name": len(trim(qCart.Name)) ? qCart.Name : "", "ItemCount": val(qCart.ItemCount), - "AddedOn": dateTimeFormat(qCart.OrderAddedOn, "yyyy-mm-dd HH:nn:ss") + "AddedOn": dateTimeFormat(qCart.AddedOn, "yyyy-mm-dd HH:nn:ss") }; } else { response["OK"] = true; diff --git a/api/orders/getCart.cfm b/api/orders/getCart.cfm index 5aad4ee..dd209d9 100644 --- a/api/orders/getCart.cfm +++ b/api/orders/getCart.cfm @@ -37,24 +37,24 @@ - - + + @@ -126,24 +126,24 @@ "OK": true, "ERROR": "", "ORDER": { - "OrderID": val(qOrder.OrderID), - "OrderUUID": qOrder.OrderUUID ?: "", - "OrderUserID": val(qOrder.OrderUserID), - "OrderBusinessID": val(qOrder.OrderBusinessID), - "OrderBusinessDeliveryMultiplier": val(qOrder.OrderBusinessDeliveryMultiplier), + "OrderID": val(qOrder.ID), + "UUID": qOrder.UUID ?: "", + "UserID": val(qOrder.UserID), + "BusinessID": val(qOrder.BusinessID), + "DeliveryMultiplier": val(qOrder.DeliveryMultiplier), "OrderTypeID": val(qOrder.OrderTypeID), - "OrderDeliveryFee": val(qOrder.OrderDeliveryFee), + "DeliveryFee": val(qOrder.DeliveryFee), "BusinessDeliveryFee": val(businessDeliveryFee), - "BusinessOrderTypes": businessOrderTypesArray, - "OrderStatusID": val(qOrder.OrderStatusID), - "OrderAddressID": val(qOrder.OrderAddressID), - "OrderPaymentID": val(qOrder.OrderPaymentID), - "OrderPaymentStatus": qOrder.OrderPaymentStatus ?: "", - "OrderRemarks": qOrder.OrderRemarks ?: "", - "OrderAddedOn": qOrder.OrderAddedOn, - "OrderLastEditedOn": qOrder.OrderLastEditedOn, - "OrderSubmittedOn": qOrder.OrderSubmittedOn, - "OrderServicePointID": val(qOrder.OrderServicePointID) + "OrderTypes": businessOrderTypesArray, + "StatusID": val(qOrder.StatusID), + "AddressID": val(qOrder.AddressID), + "PaymentID": val(qOrder.PaymentID), + "PaymentStatus": qOrder.PaymentStatus ?: "", + "Remarks": qOrder.Remarks ?: "", + "AddedOn": qOrder.AddedOn, + "LastEditedOn": qOrder.LastEditedOn, + "SubmittedOn": qOrder.SubmittedOn, + "ServicePointID": val(qOrder.ServicePointID) }, "ORDERLINEITEMS": rows })> diff --git a/api/orders/getDetail.cfm b/api/orders/getDetail.cfm index 3491ca6..bd0e744 100644 --- a/api/orders/getDetail.cfm +++ b/api/orders/getDetail.cfm @@ -42,32 +42,32 @@ try { } // Get order details - qOrder = queryTimed(" + qOrder = queryExecute(" SELECT - o.OrderID, - o.OrderBusinessID, - o.OrderUserID, - o.OrderServicePointID, - o.OrderStatusID, + o.ID, + o.BusinessID, + o.UserID, + o.ServicePointID, + o.StatusID, o.OrderTypeID, - o.OrderRemarks, - o.OrderAddedOn, - o.OrderLastEditedOn, - o.OrderSubmittedOn, + o.Remarks, + o.AddedOn, + o.LastEditedOn, + o.SubmittedOn, o.OrderTipAmount, - u.UserFirstName, - u.UserLastName, - u.UserContactNumber, - u.UserEmailAddress, - sp.ServicePointName, - sp.ServicePointTypeID, - b.BusinessName, - b.BusinessTaxRate + u.FirstName, + u.LastName, + u.ContactNumber, + u.EmailAddress, + sp.Name, + sp.TypeID, + b.Name, + b.TaxRate FROM Orders o - LEFT JOIN Users u ON u.UserID = o.OrderUserID - LEFT JOIN ServicePoints sp ON sp.ServicePointID = o.OrderServicePointID - LEFT JOIN Businesses b ON b.BusinessID = o.OrderBusinessID - WHERE o.OrderID = :orderID + LEFT JOIN Users u ON u.ID = o.UserID + LEFT JOIN ServicePoints sp ON sp.ID = o.ServicePointID + LEFT JOIN Businesses b ON b.ID = o.BusinessID + WHERE o.ID = :orderID ", { orderID: orderID }); if (qOrder.recordCount == 0) { @@ -78,22 +78,22 @@ try { } // Get line items (excluding deleted items) - qItems = queryTimed(" + qItems = queryExecute(" SELECT - oli.OrderLineItemID, - oli.OrderLineItemItemID, - oli.OrderLineItemParentOrderLineItemID, - oli.OrderLineItemQuantity, - oli.OrderLineItemPrice, - oli.OrderLineItemRemark, - i.ItemName, - i.ItemPrice, - i.ItemIsCheckedByDefault + oli.ID, + oli.ItemID, + oli.ParentOrderLineItemID, + oli.Quantity, + oli.Price, + oli.Remark, + i.Name, + i.Price, + i.IsCheckedByDefault FROM OrderLineItems oli - INNER JOIN Items i ON i.ItemID = oli.OrderLineItemItemID - WHERE oli.OrderLineItemOrderID = :orderID - AND oli.OrderLineItemIsDeleted = 0 - ORDER BY oli.OrderLineItemID + INNER JOIN Items i ON i.ID = oli.ItemID + WHERE oli.OrderID = :orderID + AND oli.IsDeleted = 0 + ORDER BY oli.ID ", { orderID: orderID }); // Build line items array with parent-child structure @@ -103,22 +103,22 @@ try { // First pass: create all items (use bracket notation to preserve key casing) for (row in qItems) { item = structNew("ordered"); - item["LineItemID"] = val(row.OrderLineItemID); - item["ItemID"] = val(row.OrderLineItemItemID); - item["ParentLineItemID"] = val(row.OrderLineItemParentOrderLineItemID); - item["ItemName"] = row.ItemName ?: ""; - item["Quantity"] = val(row.OrderLineItemQuantity); - item["UnitPrice"] = val(row.OrderLineItemPrice); - item["Remarks"] = row.OrderLineItemRemark ?: ""; - item["IsDefault"] = (val(row.ItemIsCheckedByDefault) == 1); + item["LineItemID"] = val(row.ID); + item["ItemID"] = val(row.ID); + item["ParentLineItemID"] = val(row.ParentOrderLineItemID); + item["Name"] = row.Name ?: ""; + item["Quantity"] = val(row.Quantity); + item["UnitPrice"] = val(row.Price); + item["Remarks"] = row.Remark ?: ""; + item["IsDefault"] = (val(row.IsCheckedByDefault) == 1); item["Modifiers"] = []; - itemsById[row.OrderLineItemID] = item; + itemsById[row.ID] = item; } // Second pass: build hierarchy for (row in qItems) { - item = itemsById[row.OrderLineItemID]; - parentID = row.OrderLineItemParentOrderLineItemID; + item = itemsById[row.ID]; + parentID = row.ParentOrderLineItemID; if (parentID > 0 && structKeyExists(itemsById, parentID)) { // This is a modifier - add to parent (use bracket notation) @@ -141,7 +141,7 @@ try { } // Calculate tax using business tax rate or default 8.25% - taxRate = isNumeric(qOrder.BusinessTaxRate) && qOrder.BusinessTaxRate > 0 ? qOrder.BusinessTaxRate : 0.0825; + taxRate = isNumeric(qOrder.TaxRate) && qOrder.TaxRate > 0 ? qOrder.TaxRate : 0.0825; tax = subtotal * taxRate; // Get tip from order @@ -150,60 +150,64 @@ try { // Calculate total total = subtotal + tax + tip; - // Get staff who worked on this order (LEFT JOIN instead of correlated subquery) - qStaff = queryTimed(" - SELECT DISTINCT u.UserID, u.UserFirstName, r.TaskRatingAccessToken AS RatingToken + // Get staff who worked on this order (from Tasks table) with pending rating tokens + qStaff = queryExecute(" + SELECT DISTINCT u.ID, u.FirstName, + (SELECT r.AccessToken + FROM TaskRatings r + INNER JOIN Tasks t2 ON t2.ID = r.TaskID + WHERE t2.OrderID = :orderID + AND r.ForUserID = u.ID + AND r.Direction = 'customer_rates_worker' + AND r.CompletedOn IS NULL + AND r.ExpiresOn > NOW() + LIMIT 1) AS RatingToken FROM Tasks t - INNER JOIN Users u ON u.UserID = t.TaskClaimedByUserID - LEFT JOIN TaskRatings r ON r.TaskRatingTaskID = t.TaskID - AND r.TaskRatingForUserID = u.UserID - AND r.TaskRatingDirection = 'customer_rates_worker' - AND r.TaskRatingCompletedOn IS NULL - AND r.TaskRatingExpiresOn > NOW() - WHERE t.TaskOrderID = :orderID - AND t.TaskClaimedByUserID > 0 + INNER JOIN Users u ON u.ID = t.ClaimedByUserID + WHERE t.OrderID = :orderID + AND t.ClaimedByUserID > 0 ", { orderID: orderID }); // Build staff array with avatar URLs and rating tokens (use ordered structs) staff = []; for (row in qStaff) { staffMember = structNew("ordered"); - staffMember["UserID"] = row.UserID; - staffMember["FirstName"] = row.UserFirstName; - staffMember["AvatarUrl"] = "https://biz.payfrit.com/uploads/users/" & row.UserID & ".jpg"; + staffMember["UserID"] = row.ID; + staffMember["FirstName"] = row.FirstName; + staffMember["AvatarUrl"] = "https://biz.payfrit.com/uploads/users/" & row.ID & ".jpg"; staffMember["RatingToken"] = row.RatingToken ?: ""; arrayAppend(staff, staffMember); } // Build response (use ordered structs to preserve key casing) customer = structNew("ordered"); - customer["UserID"] = qOrder.OrderUserID; - customer["FirstName"] = qOrder.UserFirstName; - customer["LastName"] = qOrder.UserLastName; - customer["Phone"] = qOrder.UserContactNumber; - customer["Email"] = qOrder.UserEmailAddress; + customer["UserID"] = qOrder.UserID; + customer["FirstName"] = qOrder.FirstName; + customer["LastName"] = qOrder.LastName; + customer["Phone"] = qOrder.ContactNumber; + customer["Email"] = qOrder.EmailAddress; servicePoint = structNew("ordered"); - servicePoint["ServicePointID"] = qOrder.OrderServicePointID; - servicePoint["Name"] = qOrder.ServicePointName; - servicePoint["TypeID"] = qOrder.ServicePointTypeID; + servicePoint["ServicePointID"] = qOrder.ServicePointID; + servicePoint["Name"] = qOrder.Name; + servicePoint["TypeID"] = qOrder.TypeID; order = structNew("ordered"); - order["OrderID"] = qOrder.OrderID; - order["BusinessID"] = qOrder.OrderBusinessID; - order["BusinessName"] = qOrder.BusinessName ?: ""; - order["Status"] = qOrder.OrderStatusID; - order["StatusText"] = getStatusText(qOrder.OrderStatusID); + order["OrderID"] = qOrder.ID; + order["BusinessID"] = qOrder.BusinessID; + order["Name"] = qOrder.Name ?: ""; + order["Status"] = qOrder.StatusID; + order["StatusText"] = getStatusText(qOrder.StatusID); order["OrderTypeID"] = qOrder.OrderTypeID ?: 0; order["OrderTypeName"] = getOrderTypeName(qOrder.OrderTypeID ?: 0); order["Subtotal"] = subtotal; order["Tax"] = tax; order["Tip"] = tip; order["Total"] = total; - order["Notes"] = qOrder.OrderRemarks; - order["CreatedOn"] = dateTimeFormat(qOrder.OrderAddedOn, "yyyy-mm-dd HH:nn:ss"); - order["SubmittedOn"] = len(qOrder.OrderSubmittedOn) ? dateTimeFormat(qOrder.OrderSubmittedOn, "yyyy-mm-dd HH:nn:ss") : ""; - order["UpdatedOn"] = len(qOrder.OrderLastEditedOn) ? dateTimeFormat(qOrder.OrderLastEditedOn, "yyyy-mm-dd HH:nn:ss") : ""; + order["Notes"] = qOrder.Remarks; + order["CreatedOn"] = dateTimeFormat(qOrder.AddedOn, "yyyy-mm-dd HH:nn:ss"); + order["SubmittedOn"] = len(qOrder.SubmittedOn) ? dateTimeFormat(qOrder.SubmittedOn, "yyyy-mm-dd HH:nn:ss") : ""; + order["UpdatedOn"] = len(qOrder.LastEditedOn) ? dateTimeFormat(qOrder.LastEditedOn, "yyyy-mm-dd HH:nn:ss") : ""; order["Customer"] = customer; order["ServicePoint"] = servicePoint; order["LineItems"] = lineItems; @@ -217,7 +221,6 @@ try { response["MESSAGE"] = e.message; } -logPerf(); writeOutput(serializeJSON(response)); // Helper functions diff --git a/api/orders/getOrCreateCart.cfm b/api/orders/getOrCreateCart.cfm index 890be99..dfea049 100644 --- a/api/orders/getOrCreateCart.cfm +++ b/api/orders/getOrCreateCart.cfm @@ -33,23 +33,23 @@ - + @@ -143,16 +143,16 @@ - + - + - + @@ -168,20 +168,20 @@ - + - + @@ -205,33 +205,33 @@ - + - + @@ -262,21 +262,21 @@ - + diff --git a/api/orders/getPendingForUser.cfm b/api/orders/getPendingForUser.cfm index 103fc11..5cfc0b1 100644 --- a/api/orders/getPendingForUser.cfm +++ b/api/orders/getPendingForUser.cfm @@ -39,26 +39,26 @@ try { // These are orders that are paid but not yet completed/picked up qOrders = queryExecute(" SELECT - o.OrderID, - o.OrderUUID, + o.ID, + o.UUID, o.OrderTypeID, - o.OrderStatusID, - o.OrderSubmittedOn, - o.OrderServicePointID, - sp.ServicePointName, - b.BusinessName, - (SELECT COALESCE(SUM(oli.OrderLineItemPrice * oli.OrderLineItemQuantity), 0) + o.StatusID, + o.SubmittedOn, + o.ServicePointID, + sp.Name, + b.Name, + (SELECT COALESCE(SUM(oli.Price * oli.Quantity), 0) FROM OrderLineItems oli - WHERE oli.OrderLineItemOrderID = o.OrderID - AND oli.OrderLineItemIsDeleted = 0 - AND oli.OrderLineItemParentOrderLineItemID = 0) as Subtotal + WHERE oli.OrderID = o.ID + AND oli.IsDeleted = 0 + AND oli.ParentOrderLineItemID = 0) as Subtotal FROM Orders o - LEFT JOIN ServicePoints sp ON sp.ServicePointID = o.OrderServicePointID - LEFT JOIN Businesses b ON b.BusinessID = o.OrderBusinessID - WHERE o.OrderUserID = :userId - AND o.OrderBusinessID = :businessId - AND o.OrderStatusID IN (1, 2, 3) - ORDER BY o.OrderSubmittedOn DESC + LEFT JOIN ServicePoints sp ON sp.ID = o.ServicePointID + LEFT JOIN Businesses b ON b.ID = o.BusinessID + WHERE o.UserID = :userId + AND o.BusinessID = :businessId + AND o.StatusID IN (1, 2, 3) + ORDER BY o.SubmittedOn DESC LIMIT 5 ", { userId: { value: UserID, cfsqltype: "cf_sql_integer" }, @@ -68,7 +68,7 @@ try { orders = []; for (row in qOrders) { statusName = ""; - switch (row.OrderStatusID) { + switch (row.StatusID) { case 1: statusName = "Submitted"; break; case 2: statusName = "Preparing"; break; case 3: statusName = "Ready for Pickup"; break; @@ -82,16 +82,16 @@ try { } arrayAppend(orders, { - "OrderID": row.OrderID, - "OrderUUID": row.OrderUUID, + "OrderID": row.ID, + "UUID": row.UUID, "OrderTypeID": row.OrderTypeID, "OrderTypeName": orderTypeName, - "OrderStatusID": row.OrderStatusID, + "StatusID": row.StatusID, "StatusName": statusName, - "SubmittedOn": dateTimeFormat(row.OrderSubmittedOn, "yyyy-mm-dd HH:nn:ss"), - "ServicePointID": row.OrderServicePointID, - "ServicePointName": len(trim(row.ServicePointName)) ? row.ServicePointName : "", - "BusinessName": len(trim(row.BusinessName)) ? row.BusinessName : "", + "SubmittedOn": dateTimeFormat(row.SubmittedOn, "yyyy-mm-dd HH:nn:ss"), + "ServicePointID": row.ServicePointID, + "Name": len(trim(row.Name)) ? row.Name : "", + "Name": len(trim(row.Name)) ? row.Name : "", "Subtotal": row.Subtotal }); } diff --git a/api/orders/history.cfm b/api/orders/history.cfm index 54325ff..1cc10bc 100644 --- a/api/orders/history.cfm +++ b/api/orders/history.cfm @@ -38,7 +38,7 @@ if (structKeyExists(request, "UserID") && isNumeric(request.UserID) && request.U userToken = getHeader("X-User-Token"); if (len(userToken)) { try { - qTok = queryTimed( + qTok = queryExecute( "SELECT UserID FROM UserTokens WHERE Token = ? LIMIT 1", [ { value = userToken, cfsqltype = "cf_sql_varchar" } ], { datasource = "payfrit" } @@ -63,23 +63,23 @@ if (offset < 0) offset = 0; try { // Get orders for this user (exclude carts - status 0) - qOrders = queryTimed(" + qOrders = queryExecute(" SELECT - o.OrderID, - o.OrderUUID, - o.OrderBusinessID, - o.OrderStatusID, + o.ID, + o.UUID, + o.BusinessID, + o.StatusID, o.OrderTypeID, - o.OrderAddedOn, - o.OrderLastEditedOn, - b.BusinessName, - COALESCE(ot.tt_OrderTypeName, 'Unknown') as OrderTypeName + o.AddedOn, + o.LastEditedOn, + b.Name, + COALESCE(ot.Name, 'Unknown') as OrderTypeName FROM Orders o - LEFT JOIN Businesses b ON b.BusinessID = o.OrderBusinessID - LEFT JOIN tt_OrderTypes ot ON ot.tt_OrderTypeID = o.OrderTypeID - WHERE o.OrderUserID = :userId - AND o.OrderStatusID > 0 - ORDER BY o.OrderAddedOn DESC + LEFT JOIN Businesses b ON b.ID = o.BusinessID + LEFT JOIN tt_OrderTypes ot ON ot.ID = o.OrderTypeID + WHERE o.UserID = :userId + AND o.StatusID > 0 + ORDER BY o.AddedOn DESC LIMIT :limit OFFSET :offset ", { userId: { value = userId, cfsqltype = "cf_sql_integer" }, @@ -88,46 +88,35 @@ try { }); // Get total count - qCount = queryTimed(" + qCount = queryExecute(" SELECT COUNT(*) as TotalCount FROM Orders - WHERE OrderUserID = :userId - AND OrderStatusID > 0 + WHERE UserID = :userId + AND StatusID > 0 ", { userId: { value = userId, cfsqltype = "cf_sql_integer" } }); - // Batch fetch line item counts and totals for ALL orders (eliminates N+1) - itemSummary = {}; - orderIds = valueList(qOrders.OrderID); - if (len(orderIds)) { - qAllItems = queryTimed(" - SELECT - OrderLineItemOrderID, - COUNT(*) as ItemCount, - SUM(OrderLineItemQuantity * OrderLineItemPrice) as Subtotal - FROM OrderLineItems - WHERE OrderLineItemOrderID IN (:orderIds) - AND OrderLineItemParentOrderLineItemID = 0 - AND (OrderLineItemIsDeleted = 0 OR OrderLineItemIsDeleted IS NULL) - GROUP BY OrderLineItemOrderID - ", { orderIds: { value = orderIds, cfsqltype = "cf_sql_varchar", list = true } }); - - for (r in qAllItems) { - itemSummary[r.OrderLineItemOrderID] = { count: r.ItemCount, subtotal: r.Subtotal }; - } - } - - // Build orders array + // Build orders array with item counts and totals orders = []; for (row in qOrders) { - summary = structKeyExists(itemSummary, row.OrderID) ? itemSummary[row.OrderID] : { count: 0, subtotal: 0 }; - itemCount = val(summary.count); - subtotal = val(summary.subtotal); + // Get line item count and calculate total + qItems = queryExecute(" + SELECT + COUNT(*) as ItemCount, + SUM(Quantity * Price) as Subtotal + FROM OrderLineItems + WHERE OrderID = :orderId + AND ParentOrderLineItemID = 0 + AND (IsDeleted = 0 OR IsDeleted IS NULL) + ", { orderId: { value = row.ID, cfsqltype = "cf_sql_integer" } }); + + itemCount = val(qItems.ItemCount); + subtotal = val(qItems.Subtotal); tax = subtotal * 0.0875; total = subtotal + tax; // Get status text statusText = ""; - switch (row.OrderStatusID) { + switch (row.StatusID) { case 1: statusText = "Submitted"; break; case 2: statusText = "In Progress"; break; case 3: statusText = "Ready"; break; @@ -139,25 +128,25 @@ try { // Safely format dates createdAt = ""; try { - if (!isNull(row.OrderAddedOn) && len(trim(row.OrderAddedOn))) { - createdAt = dateTimeFormat(row.OrderAddedOn, "yyyy-mm-dd'T'HH:nn:ss"); + if (!isNull(row.AddedOn) && len(trim(row.AddedOn))) { + createdAt = dateTimeFormat(row.AddedOn, "yyyy-mm-dd'T'HH:nn:ss"); } } catch (any de) { createdAt = ""; } completedAt = ""; try { - if (row.OrderStatusID >= 4 && !isNull(row.OrderLastEditedOn) && len(trim(row.OrderLastEditedOn))) { - completedAt = dateTimeFormat(row.OrderLastEditedOn, "yyyy-mm-dd'T'HH:nn:ss"); + if (row.StatusID >= 4 && !isNull(row.LastEditedOn) && len(trim(row.LastEditedOn))) { + completedAt = dateTimeFormat(row.LastEditedOn, "yyyy-mm-dd'T'HH:nn:ss"); } } catch (any de) { completedAt = ""; } arrayAppend(orders, { - "OrderID": val(row.OrderID), - "OrderUUID": row.OrderUUID ?: "", - "BusinessID": val(row.OrderBusinessID), - "BusinessName": row.BusinessName ?: "Unknown", + "OrderID": val(row.ID), + "UUID": row.UUID ?: "", + "BusinessID": val(row.BusinessID), + "Name": row.Name ?: "Unknown", "OrderTotal": round(val(total) * 100) / 100, - "OrderStatusID": val(row.OrderStatusID), + "StatusID": val(row.StatusID), "StatusName": statusText, "OrderTypeID": val(row.OrderTypeID), "TypeName": row.OrderTypeName ?: "Unknown", @@ -167,7 +156,6 @@ try { }); } - logPerf(); writeOutput(serializeJSON({ "OK": true, "ORDERS": orders, diff --git a/api/orders/listForKDS.cfm b/api/orders/listForKDS.cfm index b280430..82a9fdb 100644 --- a/api/orders/listForKDS.cfm +++ b/api/orders/listForKDS.cfm @@ -1,4 +1,4 @@ - + @@ -37,20 +37,20 @@ - + - + - = 1")> + = 1")> - + @@ -58,135 +58,126 @@ - - - - - - + + + - 0) - ORDER BY oli.OrderLineItemOrderID, oli.OrderLineItemID - ", [ { value = StationID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })> + INNER JOIN Items i ON i.ID = oli.ItemID + LEFT JOIN Items parent ON parent.ItemID = i.ParentItemID + WHERE oli.OrderID = ? + AND oli.IsDeleted = b'0' + AND (i.StationID = ? OR i.StationID = 0 OR i.StationID IS NULL OR oli.ParentOrderLineItemID > 0) + ORDER BY oli.ID + ", [ + { value = qOrders.ID, cfsqltype = "cf_sql_integer" }, + { value = StationID, cfsqltype = "cf_sql_integer" } + ], { datasource = "payfrit" })> - + INNER JOIN Items i ON i.ID = oli.ItemID + LEFT JOIN Items parent ON parent.ItemID = i.ParentItemID + WHERE oli.OrderID = ? + AND oli.IsDeleted = b'0' + ORDER BY oli.ID + ", [ { value = qOrders.ID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })> - - - - - - - + + - - - - - @@ -198,25 +189,24 @@ - direct child: ItemID=#qKids.ItemID#")> - + template child: ItemID=#qTemplateKids.ItemID#")> - + @@ -96,16 +96,16 @@ - + @@ -318,16 +318,16 @@ - + @@ -364,21 +364,21 @@ - + - + @@ -180,9 +180,9 @@ - + @@ -201,12 +201,12 @@ - + @@ -218,9 +218,9 @@ " UPDATE Orders SET OrderTypeID = ?, - OrderAddressID = ?, - OrderDeliveryFee = ?, - OrderLastEditedOn = ? + AddressID = ?, + DeliveryFee = ?, + LastEditedOn = ? WHERE OrderID = ? ", [ @@ -238,9 +238,9 @@ " UPDATE Orders SET OrderTypeID = ?, - OrderAddressID = NULL, - OrderDeliveryFee = 0, - OrderLastEditedOn = ? + AddressID = NULL, + DeliveryFee = 0, + LastEditedOn = ? WHERE OrderID = ? ", [ diff --git a/api/orders/submit.cfm b/api/orders/submit.cfm index 1d52472..f9878c0 100644 --- a/api/orders/submit.cfm +++ b/api/orders/submit.cfm @@ -37,12 +37,12 @@ - - + + - - + + @@ -79,11 +79,11 @@ @@ -140,11 +140,11 @@ - + @@ -167,11 +167,11 @@ - + @@ -181,9 +181,9 @@ " SELECT COUNT(*) AS Cnt FROM OrderLineItems - WHERE OrderLineItemOrderID = ? - AND OrderLineItemParentOrderLineItemID = 0 - AND OrderLineItemIsDeleted = b'0' + WHERE OrderID = ? + AND ParentOrderLineItemID = 0 + AND IsDeleted = b'0' ", [ { value = OrderID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" } @@ -250,9 +250,9 @@ " UPDATE Orders SET - OrderStatusID = 1, - OrderSubmittedOn = ?, - OrderLastEditedOn = ? + StatusID = 1, + SubmittedOn = ?, + LastEditedOn = ? WHERE OrderID = ? ", [ diff --git a/api/orders/updateStatus.cfm b/api/orders/updateStatus.cfm index 46a80f8..bfde882 100644 --- a/api/orders/updateStatus.cfm +++ b/api/orders/updateStatus.cfm @@ -37,11 +37,11 @@ @@ -49,13 +49,13 @@ - + @@ -99,7 +99,7 @@ @@ -107,7 +107,7 @@ - + @@ -125,13 +125,13 @@ 0) { // Update to active queryExecute(" - UPDATE lt_Users_Businesses_Employees - SET EmployeeIsActive = 1, EmployeeStatusID = 2 + UPDATE Employees + SET IsActive = 1, StatusID = 2 WHERE BusinessID = ? AND UserID = ? ", [ { value: businessId, cfsqltype: "cf_sql_integer" }, { value: userId, cfsqltype: "cf_sql_integer" } ], { datasource: "payfrit" }); - apiAbort({ "OK": true, "MESSAGE": "Employee reactivated", "EmployeeID": qCheck.EmployeeID }); + apiAbort({ "OK": true, "MESSAGE": "Employee reactivated", "EmployeeID": qCheck.ID }); } // Insert new - // NOTE: BusinessID in lt_Users_Businesses_Employees is technically redundant since + // NOTE: BusinessID in Employees is technically redundant since // the business relationship is established via ServicePoint -> Beacon chain. // Kept for legacy/convenience but could be derived from context. queryExecute(" - INSERT INTO lt_Users_Businesses_Employees (BusinessID, UserID, EmployeeStatusID, EmployeeIsActive) + INSERT INTO Employees (BusinessID, UserID, StatusID, IsActive) VALUES (?, ?, 2, 1) ", [ { value: businessId, cfsqltype: "cf_sql_integer" }, @@ -67,7 +67,7 @@ try { qNew = queryExecute("SELECT LAST_INSERT_ID() AS EmployeeID", {}, { datasource: "payfrit" }); - apiAbort({ "OK": true, "MESSAGE": "Team member added", "EmployeeID": qNew.EmployeeID }); + apiAbort({ "OK": true, "MESSAGE": "Team member added", "EmployeeID": qNew.ID }); } catch (any e) { apiAbort({ "OK": false, "ERROR": "server_error", "MESSAGE": e.message }); diff --git a/api/portal/getSettings.cfm b/api/portal/getSettings.cfm index e6c5211..b128375 100644 --- a/api/portal/getSettings.cfm +++ b/api/portal/getSettings.cfm @@ -24,17 +24,12 @@ if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || try { q = queryExecute(" SELECT - BusinessID, - BusinessName, - BusinessTaxRate, - BusinessAddress, - BusinessCity, - BusinessState, - BusinessZip, - BusinessContactNumber, - BusinessEmailAddress - FROM Businesses - WHERE BusinessID = :businessId + b.ID, + b.Name, + b.TaxRate, + b.Phone + FROM Businesses b + WHERE b.ID = :businessId LIMIT 1 ", { businessId: request.BusinessID }, { datasource: "payfrit" }); @@ -42,23 +37,52 @@ try { apiAbort({ OK: false, ERROR: "business_not_found" }); } + // Get address from Addresses table + qAddr = queryExecute(" + SELECT a.Line1, a.Line2, a.City, a.ZIPCode, s.Abbreviation AS State + FROM Addresses a + LEFT JOIN tt_States s ON s.ID = a.StateID + WHERE (a.BusinessID = :businessId OR a.ID = (SELECT AddressID FROM Businesses WHERE ID = :businessId)) + AND a.IsDeleted = 0 + LIMIT 1 + ", { businessId: request.BusinessID }, { datasource: "payfrit" }); + + addressStr = ""; + addrCity = ""; + addrState = ""; + addrZip = ""; + if (qAddr.recordCount > 0) { + addressStr = qAddr.Line1 ?: ""; + addrCity = qAddr.City ?: ""; + addrState = qAddr.State ?: ""; + addrZip = qAddr.ZIPCode ?: ""; + } + + // Get owner email from Users table + qUser = queryExecute(" + SELECT ContactNumber, EmailAddress + FROM Users + WHERE ID = (SELECT UserID FROM Businesses WHERE ID = :businessId) + LIMIT 1 + ", { businessId: request.BusinessID }, { datasource: "payfrit" }); + // Format tax rate as percentage for display (0.0825 -> 8.25) - taxRateRaw = isNumeric(q.BusinessTaxRate) ? q.BusinessTaxRate : 0; + taxRateRaw = isNumeric(q.TaxRate) ? q.TaxRate : 0; taxRatePercent = taxRateRaw * 100; writeOutput(serializeJSON({ "OK": true, "SETTINGS": { - "BusinessID": q.BusinessID, - "BusinessName": q.BusinessName, + "BusinessID": q.ID, + "Name": q.Name, "TaxRate": taxRateRaw, "TaxRatePercent": taxRatePercent, - "Address": q.BusinessAddress ?: "", - "City": q.BusinessCity ?: "", - "State": q.BusinessState ?: "", - "Zip": q.BusinessZip ?: "", - "Phone": q.BusinessContactNumber ?: "", - "Email": q.BusinessEmailAddress ?: "" + "Address": addressStr, + "City": addrCity, + "State": addrState, + "Zip": addrZip, + "Phone": q.Phone ?: "", + "Email": qUser.recordCount > 0 ? (qUser.EmailAddress ?: "") : "" } })); diff --git a/api/portal/myBusinesses.cfm b/api/portal/myBusinesses.cfm index 45d97d9..aa17c67 100644 --- a/api/portal/myBusinesses.cfm +++ b/api/portal/myBusinesses.cfm @@ -43,22 +43,22 @@ try { } // Get businesses for this user - // Users are linked to businesses via BusinessUserID field (owner) + // Users are linked to businesses via UserID field (owner) - q = queryTimed(" + q = queryExecute(" SELECT - b.BusinessID, - b.BusinessName + b.ID, + b.Name FROM Businesses b - WHERE b.BusinessUserID = :userID - ORDER BY b.BusinessName + WHERE b.UserID = :userID + ORDER BY b.Name ", { userID: userID }, { datasource: "payfrit" }); businesses = []; for (row in q) { arrayAppend(businesses, { - "BusinessID": row.BusinessID, - "BusinessName": row.BusinessName + "BusinessID": row.ID, + "Name": row.Name }); } @@ -71,6 +71,5 @@ try { response["MESSAGE"] = e.message; } -logPerf(); writeOutput(serializeJSON(response)); diff --git a/api/portal/reassign_employees.cfm b/api/portal/reassign_employees.cfm index 4eacb4d..dc6920c 100644 --- a/api/portal/reassign_employees.cfm +++ b/api/portal/reassign_employees.cfm @@ -5,12 +5,12 @@ - UPDATE lt_Users_Businesses_Employees + UPDATE Employees SET BusinessID = - SELECT COUNT(*) AS cnt FROM lt_Users_Businesses_Employees WHERE BusinessID = + SELECT COUNT(*) AS cnt FROM Employees WHERE BusinessID = #serializeJSON({ diff --git a/api/portal/searchUser.cfm b/api/portal/searchUser.cfm index 8ae6c45..a4634c2 100644 --- a/api/portal/searchUser.cfm +++ b/api/portal/searchUser.cfm @@ -41,9 +41,9 @@ try { // Search by phone - normalize both sides phoneDigits = normalizePhone(query); qUser = queryExecute(" - SELECT UserID, UserFirstName, UserLastName, UserContactNumber, UserEmailAddress + SELECT ID, FirstName, LastName, ContactNumber, EmailAddress FROM Users - WHERE REPLACE(REPLACE(REPLACE(REPLACE(UserContactNumber, '-', ''), ' ', ''), '(', ''), ')', '') LIKE :phone + WHERE REPLACE(REPLACE(REPLACE(REPLACE(ContactNumber, '-', ''), ' ', ''), '(', ''), ')', '') LIKE :phone LIMIT 1 ", { phone: { value: "%" & phoneDigits & "%", cfsqltype: "cf_sql_varchar" } @@ -51,9 +51,9 @@ try { } else if (isEmail) { // Search by email (partial match) qUser = queryExecute(" - SELECT UserID, UserFirstName, UserLastName, UserContactNumber, UserEmailAddress + SELECT ID, FirstName, LastName, ContactNumber, EmailAddress FROM Users - WHERE UserEmailAddress LIKE :email + WHERE EmailAddress LIKE :email LIMIT 1 ", { email: { value: "%" & query & "%", cfsqltype: "cf_sql_varchar" } @@ -61,10 +61,10 @@ try { } else { // Search by name qUser = queryExecute(" - SELECT UserID, UserFirstName, UserLastName, UserContactNumber, UserEmailAddress + SELECT ID, FirstName, LastName, ContactNumber, EmailAddress FROM Users - WHERE UserFirstName LIKE :name OR UserLastName LIKE :name - OR CONCAT(UserFirstName, ' ', UserLastName) LIKE :name + WHERE FirstName LIKE :name OR LastName LIKE :name + OR CONCAT(FirstName, ' ', LastName) LIKE :name LIMIT 1 ", { name: { value: "%" & query & "%", cfsqltype: "cf_sql_varchar" } @@ -74,20 +74,20 @@ try { if (qUser.recordCount > 0) { // Check if already on team qTeam = queryExecute(" - SELECT EmployeeID FROM lt_Users_Businesses_Employees + SELECT ID FROM Employees WHERE BusinessID = :bizId AND UserID = :userId ", { bizId: { value: businessId, cfsqltype: "cf_sql_integer" }, - userId: { value: qUser.UserID, cfsqltype: "cf_sql_integer" } + userId: { value: qUser.ID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); apiAbort({ "OK": true, "USER": { - "UserID": qUser.UserID, - "Name": trim(qUser.UserFirstName & " " & qUser.UserLastName), - "Phone": qUser.UserContactNumber, - "Email": qUser.UserEmailAddress, + "UserID": qUser.ID, + "Name": trim(qUser.FirstName & " " & qUser.LastName), + "Phone": qUser.ContactNumber, + "Email": qUser.EmailAddress, "AlreadyOnTeam": qTeam.recordCount > 0 } }); diff --git a/api/portal/stats.cfm b/api/portal/stats.cfm index 0181805..43c7f30 100644 --- a/api/portal/stats.cfm +++ b/api/portal/stats.cfm @@ -36,51 +36,63 @@ try { todayStart = dateFormat(now(), "yyyy-mm-dd") & " 00:00:00"; todayEnd = dateFormat(now(), "yyyy-mm-dd") & " 23:59:59"; - // Combined stats query — 1 round trip instead of 4 - qStats = queryTimed(" - SELECT - (SELECT COUNT(*) - FROM Orders - WHERE OrderBusinessID = :businessID - AND OrderSubmittedOn >= :todayStart - AND OrderSubmittedOn <= :todayEnd) as ordersToday, - - (SELECT COALESCE(SUM(li.OrderLineItemQuantity * li.OrderLineItemPrice), 0) - FROM Orders o - JOIN OrderLineItems li ON li.OrderLineItemOrderID = o.OrderID - WHERE o.OrderBusinessID = :businessID - AND o.OrderSubmittedOn >= :todayStart - AND o.OrderSubmittedOn <= :todayEnd - AND o.OrderStatusID >= 1) as revenueToday, - - (SELECT COUNT(*) - FROM Orders - WHERE OrderBusinessID = :businessID - AND OrderStatusID IN (1, 2)) as pendingOrders, - - (SELECT COUNT(*) - FROM Items - WHERE ItemBusinessID = :businessID - AND ItemIsActive = 1 - AND ItemParentItemID > 0) as menuItems + // Orders today count + qOrdersToday = queryExecute(" + SELECT COUNT(*) as cnt + FROM Orders + WHERE BusinessID = :businessID + AND SubmittedOn >= :todayStart + AND SubmittedOn <= :todayEnd ", { businessID: businessID, todayStart: { value: todayStart, cfsqltype: "cf_sql_varchar" }, todayEnd: { value: todayEnd, cfsqltype: "cf_sql_varchar" } }); + // Revenue today (sum of line items) + qRevenueToday = queryExecute(" + SELECT COALESCE(SUM(li.Quantity * li.Price), 0) as total + FROM Orders o + JOIN OrderLineItems li ON li.OrderID = o.ID + WHERE o.BusinessID = :businessID + AND o.SubmittedOn >= :todayStart + AND o.SubmittedOn <= :todayEnd + AND o.StatusID >= 1 + ", { + businessID: businessID, + todayStart: { value: todayStart, cfsqltype: "cf_sql_varchar" }, + todayEnd: { value: todayEnd, cfsqltype: "cf_sql_varchar" } + }); + + // Pending orders (status 1 = submitted, 2 = preparing) + qPendingOrders = queryExecute(" + SELECT COUNT(*) as cnt + FROM Orders + WHERE BusinessID = :businessID + AND StatusID IN (1, 2) + ", { businessID: businessID }); + + // Menu items count (active items that have a parent category, excluding categories themselves) + // Categories are items with ParentItemID = 0 and IsCollapsible = 0 + qMenuItems = queryExecute(" + SELECT COUNT(*) as cnt + FROM Items + WHERE BusinessID = :businessID + AND IsActive = 1 + AND ParentItemID > 0 + ", { businessID: businessID }); + response["OK"] = true; response["STATS"] = { - "ordersToday": qStats.ordersToday, - "revenueToday": qStats.revenueToday, - "pendingOrders": qStats.pendingOrders, - "menuItems": qStats.menuItems + "ordersToday": qOrdersToday.cnt, + "revenueToday": qRevenueToday.total, + "pendingOrders": qPendingOrders.cnt, + "menuItems": qMenuItems.cnt }; } catch (any e) { response["ERROR"] = e.message; } -logPerf(); writeOutput(serializeJSON(response)); diff --git a/api/portal/team.cfm b/api/portal/team.cfm index 147b27f..5b057f2 100644 --- a/api/portal/team.cfm +++ b/api/portal/team.cfm @@ -42,25 +42,25 @@ try { // Cast BIT to INT to avoid binary comparison issues qTeam = queryExecute(" SELECT - e.EmployeeID, + e.ID, e.UserID, - e.EmployeeStatusID, - CAST(e.EmployeeIsActive AS UNSIGNED) AS EmployeeIsActive, - u.UserFirstName, - u.UserLastName, - u.UserEmailAddress, - u.UserContactNumber, - CASE e.EmployeeStatusID + e.StatusID, + CAST(e.IsActive AS UNSIGNED) AS IsActive, + u.FirstName, + u.LastName, + u.EmailAddress, + u.ContactNumber, + CASE e.StatusID WHEN 0 THEN 'Pending' WHEN 1 THEN 'Invited' WHEN 2 THEN 'Active' WHEN 3 THEN 'Suspended' ELSE 'Unknown' END AS StatusName - FROM lt_Users_Businesses_Employees e - JOIN Users u ON e.UserID = u.UserID + FROM Employees e + JOIN Users u ON e.UserID = u.ID WHERE e.BusinessID = ? - ORDER BY e.EmployeeIsActive DESC, u.UserFirstName ASC + ORDER BY e.IsActive DESC, u.FirstName ASC ", [ { value: businessId, cfsqltype: "cf_sql_integer" } ], { datasource: "payfrit" }); @@ -68,16 +68,16 @@ try { team = []; for (row in qTeam) { arrayAppend(team, { - "EmployeeID": row.EmployeeID, + "EmployeeID": row.ID, "UserID": row.UserID, - "Name": trim(row.UserFirstName & " " & row.UserLastName), - "FirstName": row.UserFirstName, - "LastName": row.UserLastName, - "Email": row.UserEmailAddress, - "Phone": row.UserContactNumber, - "StatusID": row.EmployeeStatusID, + "Name": trim(row.FirstName & " " & row.LastName), + "FirstName": row.FirstName, + "LastName": row.LastName, + "Email": row.EmailAddress, + "Phone": row.ContactNumber, + "StatusID": row.StatusID, "StatusName": row.StatusName, - "IsActive": val(row.EmployeeIsActive) == 1 + "IsActive": val(row.IsActive) == 1 }); } diff --git a/api/portal/updateSettings.cfm b/api/portal/updateSettings.cfm index 33f29a3..ff01f74 100644 --- a/api/portal/updateSettings.cfm +++ b/api/portal/updateSettings.cfm @@ -54,95 +54,119 @@ try { if (taxRate < 0 || taxRate > 0.5) { apiAbort({ OK: false, ERROR: "invalid_tax_rate", MESSAGE: "Tax rate must be between 0% and 50%" }); } - arrayAppend(updates, "BusinessTaxRate = :taxRate"); + arrayAppend(updates, "TaxRate = :taxRate"); params.taxRate = { value: taxRate, cfsqltype: "cf_sql_decimal" }; } else if (structKeyExists(data, "TaxRate") && isNumeric(data.TaxRate)) { taxRate = data.TaxRate; if (taxRate < 0 || taxRate > 0.5) { apiAbort({ OK: false, ERROR: "invalid_tax_rate", MESSAGE: "Tax rate must be between 0 and 0.5" }); } - arrayAppend(updates, "BusinessTaxRate = :taxRate"); + arrayAppend(updates, "TaxRate = :taxRate"); params.taxRate = { value: taxRate, cfsqltype: "cf_sql_decimal" }; } // Add more updatable fields as needed - if (structKeyExists(data, "BusinessName") && len(trim(data.BusinessName))) { - arrayAppend(updates, "BusinessName = :businessName"); - params.businessName = { value: left(trim(data.BusinessName), 100), cfsqltype: "cf_sql_varchar" }; - } - - if (structKeyExists(data, "Address") && len(trim(data.Address))) { - arrayAppend(updates, "BusinessAddress = :address"); - params.address = { value: left(trim(data.Address), 255), cfsqltype: "cf_sql_varchar" }; - } - - if (structKeyExists(data, "City")) { - arrayAppend(updates, "BusinessCity = :city"); - params.city = { value: left(trim(data.City), 100), cfsqltype: "cf_sql_varchar" }; - } - - if (structKeyExists(data, "State")) { - arrayAppend(updates, "BusinessState = :state"); - params.state = { value: left(trim(data.State), 2), cfsqltype: "cf_sql_varchar" }; - } - - if (structKeyExists(data, "Zip")) { - arrayAppend(updates, "BusinessZip = :zip"); - params.zip = { value: left(trim(data.Zip), 10), cfsqltype: "cf_sql_varchar" }; + if (structKeyExists(data, "Name") && len(trim(data.Name))) { + arrayAppend(updates, "Name = :businessName"); + params.businessName = { value: left(trim(data.Name), 100), cfsqltype: "cf_sql_varchar" }; } if (structKeyExists(data, "Phone")) { - arrayAppend(updates, "BusinessContactNumber = :phone"); + arrayAppend(updates, "Phone = :phone"); params.phone = { value: left(trim(data.Phone), 20), cfsqltype: "cf_sql_varchar" }; } - if (structKeyExists(data, "Email")) { - arrayAppend(updates, "BusinessEmailAddress = :email"); - params.email = { value: left(trim(data.Email), 100), cfsqltype: "cf_sql_varchar" }; + // Track whether we need to update address separately + hasAddressUpdate = false; + addrFields = {}; + if (structKeyExists(data, "Address") && len(trim(data.Address))) { + hasAddressUpdate = true; + addrFields.Line1 = left(trim(data.Address), 100); + } + if (structKeyExists(data, "City")) { + hasAddressUpdate = true; + addrFields.City = left(trim(data.City), 50); + } + if (structKeyExists(data, "Zip")) { + hasAddressUpdate = true; + addrFields.ZIPCode = left(trim(data.Zip), 10); } - if (arrayLen(updates) == 0) { + if (arrayLen(updates) == 0 && !hasAddressUpdate) { apiAbort({ OK: false, ERROR: "no_fields", MESSAGE: "No valid fields to update" }); } - // Build and execute update - sql = "UPDATE Businesses SET " & arrayToList(updates, ", ") & " WHERE BusinessID = :businessId"; - queryExecute(sql, params, { datasource: "payfrit" }); + // Build and execute Businesses update + if (arrayLen(updates) > 0) { + sql = "UPDATE Businesses SET " & arrayToList(updates, ", ") & " WHERE ID = :businessId"; + queryExecute(sql, params, { datasource: "payfrit" }); + } + + // Update address in Addresses table if needed + if (hasAddressUpdate) { + qExistingAddr = queryExecute(" + SELECT ID FROM Addresses + WHERE (BusinessID = :businessId OR ID = (SELECT AddressID FROM Businesses WHERE ID = :businessId)) + AND IsDeleted = 0 + LIMIT 1 + ", { businessId: request.BusinessID }, { datasource: "payfrit" }); + + if (qExistingAddr.recordCount > 0) { + addrUpdates = []; + addrParams = { addrId: qExistingAddr.ID }; + if (structKeyExists(addrFields, "Line1")) { + arrayAppend(addrUpdates, "Line1 = :line1"); + addrParams.line1 = { value: addrFields.Line1, cfsqltype: "cf_sql_varchar" }; + } + if (structKeyExists(addrFields, "City")) { + arrayAppend(addrUpdates, "City = :city"); + addrParams.city = { value: addrFields.City, cfsqltype: "cf_sql_varchar" }; + } + if (structKeyExists(addrFields, "ZIPCode")) { + arrayAppend(addrUpdates, "ZIPCode = :zip"); + addrParams.zip = { value: addrFields.ZIPCode, cfsqltype: "cf_sql_varchar" }; + } + if (arrayLen(addrUpdates) > 0) { + queryExecute("UPDATE Addresses SET " & arrayToList(addrUpdates, ", ") & " WHERE ID = :addrId", + addrParams, { datasource: "payfrit" }); + } + } + } // Return updated settings q = queryExecute(" - SELECT - BusinessID, - BusinessName, - BusinessTaxRate, - BusinessAddress, - BusinessCity, - BusinessState, - BusinessZip, - BusinessContactNumber, - BusinessEmailAddress - FROM Businesses - WHERE BusinessID = :businessId + SELECT b.ID, b.Name, b.TaxRate, b.Phone + FROM Businesses b + WHERE b.ID = :businessId LIMIT 1 ", { businessId: request.BusinessID }, { datasource: "payfrit" }); - taxRateRaw = isNumeric(q.BusinessTaxRate) ? q.BusinessTaxRate : 0; + qAddr = queryExecute(" + SELECT a.Line1, a.City, a.ZIPCode, s.Abbreviation AS State + FROM Addresses a + LEFT JOIN tt_States s ON s.ID = a.StateID + WHERE (a.BusinessID = :businessId OR a.ID = (SELECT AddressID FROM Businesses WHERE ID = :businessId)) + AND a.IsDeleted = 0 + LIMIT 1 + ", { businessId: request.BusinessID }, { datasource: "payfrit" }); + + taxRateRaw = isNumeric(q.TaxRate) ? q.TaxRate : 0; taxRatePercent = taxRateRaw * 100; writeOutput(serializeJSON({ "OK": true, "MESSAGE": "Settings updated", "SETTINGS": { - "BusinessID": q.BusinessID, - "BusinessName": q.BusinessName, + "BusinessID": q.ID, + "Name": q.Name, "TaxRate": taxRateRaw, "TaxRatePercent": taxRatePercent, - "Address": q.BusinessAddress ?: "", - "City": q.BusinessCity ?: "", - "State": q.BusinessState ?: "", - "Zip": q.BusinessZip ?: "", - "Phone": q.BusinessContactNumber ?: "", - "Email": q.BusinessEmailAddress ?: "" + "Address": qAddr.recordCount > 0 ? (qAddr.Line1 ?: "") : "", + "City": qAddr.recordCount > 0 ? (qAddr.City ?: "") : "", + "State": qAddr.recordCount > 0 ? (qAddr.State ?: "") : "", + "Zip": qAddr.recordCount > 0 ? (qAddr.ZIPCode ?: "") : "", + "Phone": q.Phone ?: "", + "Email": "" } })); diff --git a/api/ratings/createAdminRating.cfm b/api/ratings/createAdminRating.cfm index d52face..6511424 100644 --- a/api/ratings/createAdminRating.cfm +++ b/api/ratings/createAdminRating.cfm @@ -46,9 +46,9 @@ try { // Verify task exists and is completed qTask = queryExecute(" - SELECT t.TaskID, t.TaskClaimedByUserID, t.TaskCompletedOn, t.TaskBusinessID + SELECT t.ID, t.ClaimedByUserID, t.CompletedOn, t.BusinessID FROM Tasks t - WHERE t.TaskID = :taskID + WHERE t.ID = :taskID ", { taskID: taskID }); if (qTask.recordCount == 0) { @@ -56,12 +56,12 @@ try { abort; } - if (len(trim(qTask.TaskCompletedOn)) == 0) { + if (len(trim(qTask.CompletedOn)) == 0) { writeOutput(serializeJSON({ "OK": false, "ERROR": "not_completed", "MESSAGE": "Task has not been completed yet." })); abort; } - workerUserID = qTask.TaskClaimedByUserID; + workerUserID = qTask.ClaimedByUserID; if (workerUserID == 0) { writeOutput(serializeJSON({ "OK": false, "ERROR": "no_worker", "MESSAGE": "No worker assigned to this task." })); abort; @@ -70,8 +70,8 @@ try { // Check if admin rating already exists for this task qExisting = queryExecute(" SELECT TaskRatingID FROM TaskRatings - WHERE TaskRatingTaskID = :taskID - AND TaskRatingDirection = 'admin_rates_worker' + WHERE TaskID = :taskID + AND Direction = 'admin_rates_worker' LIMIT 1 ", { taskID: taskID }); @@ -84,9 +84,9 @@ try { token = generateToken(); queryExecute(" INSERT INTO TaskRatings ( - TaskRatingTaskID, TaskRatingByUserID, TaskRatingForUserID, TaskRatingDirection, - TaskRatingOnTime, TaskRatingCompletedScope, TaskRatingRequiredFollowup, TaskRatingContinueAllow, - TaskRatingAccessToken, TaskRatingExpiresOn, TaskRatingCompletedOn + TaskID, ByUserID, ForUserID, Direction, + OnTime, CompletedScope, RequiredFollowup, ContinueAllow, + AccessToken, ExpiresOn, CompletedOn ) VALUES ( :taskID, :adminUserID, :workerUserID, 'admin_rates_worker', :onTime, :completedScope, :requiredFollowup, :continueAllow, diff --git a/api/ratings/listForAdmin.cfm b/api/ratings/listForAdmin.cfm index 0270c53..7c8cf46 100644 --- a/api/ratings/listForAdmin.cfm +++ b/api/ratings/listForAdmin.cfm @@ -31,32 +31,32 @@ try { // Get completed tasks from last 7 days where a worker was assigned // and no admin rating exists yet qTasks = queryExecute(" - SELECT t.TaskID, t.TaskTitle, t.TaskCompletedOn, t.TaskClaimedByUserID, t.TaskOrderID, - u.UserFirstName AS WorkerFirstName, u.UserLastName AS WorkerLastName, - o.OrderID, o.OrderUserID, - cu.UserFirstName AS CustomerFirstName, cu.UserLastName AS CustomerLastName, - sp.ServicePointName, + SELECT t.ID, t.Title, t.CompletedOn, t.ClaimedByUserID, t.OrderID, + u.FirstName AS WorkerFirstName, u.LastName AS WorkerLastName, + o.ID, o.UserID, + cu.FirstName AS CustomerFirstName, cu.LastName AS CustomerLastName, + sp.Name, (SELECT COUNT(*) FROM TaskRatings r - WHERE r.TaskRatingTaskID = t.TaskID - AND r.TaskRatingDirection = 'admin_rates_worker') AS HasAdminRating + WHERE r.TaskID = t.ID + AND r.Direction = 'admin_rates_worker') AS HasAdminRating FROM Tasks t - INNER JOIN Users u ON u.UserID = t.TaskClaimedByUserID - LEFT JOIN Orders o ON o.OrderID = t.TaskOrderID - LEFT JOIN Users cu ON cu.UserID = o.OrderUserID - LEFT JOIN ServicePoints sp ON sp.ServicePointID = o.OrderServicePointID - WHERE t.TaskBusinessID = :businessID - AND t.TaskCompletedOn IS NOT NULL - AND t.TaskCompletedOn > DATE_SUB(NOW(), INTERVAL 7 DAY) - AND t.TaskClaimedByUserID > 0 + INNER JOIN Users u ON u.ID = t.ClaimedByUserID + LEFT JOIN Orders o ON o.ID = t.OrderID + LEFT JOIN Users cu ON cu.ID = o.UserID + LEFT JOIN ServicePoints sp ON sp.ID = o.ServicePointID + WHERE t.BusinessID = :businessID + AND t.CompletedOn IS NOT NULL + AND t.CompletedOn > DATE_SUB(NOW(), INTERVAL 7 DAY) + AND t.ClaimedByUserID > 0 HAVING HasAdminRating = 0 - ORDER BY t.TaskCompletedOn DESC + ORDER BY t.CompletedOn DESC LIMIT 50 ", { businessID: businessID }); tasks = []; for (row in qTasks) { // Build task title - taskTitle = row.TaskTitle; + taskTitle = row.Title; if (len(taskTitle) == 0 && row.OrderID > 0) { taskTitle = "Order ##" & row.OrderID; } @@ -66,12 +66,12 @@ try { arrayAppend(tasks, { "TaskID": row.TaskID, - "TaskTitle": taskTitle, - "CompletedOn": dateTimeFormat(row.TaskCompletedOn, "yyyy-mm-dd HH:nn:ss"), - "WorkerUserID": row.TaskClaimedByUserID, + "Title": taskTitle, + "CompletedOn": dateTimeFormat(row.CompletedOn, "yyyy-mm-dd HH:nn:ss"), + "WorkerUserID": row.ClaimedByUserID, "WorkerName": trim(row.WorkerFirstName & " " & row.WorkerLastName), "CustomerName": len(row.CustomerFirstName) ? trim(row.CustomerFirstName & " " & row.CustomerLastName) : "", - "ServicePointName": row.ServicePointName ?: "", + "Name": row.Name ?: "", "OrderID": row.OrderID ?: 0 }); } diff --git a/api/ratings/setup.cfm b/api/ratings/setup.cfm index 8edfe6a..018b46c 100644 --- a/api/ratings/setup.cfm +++ b/api/ratings/setup.cfm @@ -5,36 +5,36 @@ try { // Create TaskRatings table queryExecute(" CREATE TABLE IF NOT EXISTS TaskRatings ( - TaskRatingID INT AUTO_INCREMENT PRIMARY KEY, - TaskRatingTaskID INT NOT NULL, + ID INT AUTO_INCREMENT PRIMARY KEY, + TaskID INT NOT NULL, - TaskRatingByUserID INT NOT NULL, - TaskRatingForUserID INT NOT NULL, - TaskRatingDirection VARCHAR(25) NOT NULL, + ByUserID INT NOT NULL, + ForUserID INT NOT NULL, + Direction VARCHAR(25) NOT NULL, -- Customer/Admin rates Worker - TaskRatingOnTime TINYINT(1) NULL, - TaskRatingCompletedScope TINYINT(1) NULL, - TaskRatingRequiredFollowup TINYINT(1) NULL, - TaskRatingContinueAllow TINYINT(1) NULL, + OnTime TINYINT(1) NULL, + CompletedScope TINYINT(1) NULL, + RequiredFollowup TINYINT(1) NULL, + ContinueAllow TINYINT(1) NULL, -- Worker rates Customer - TaskRatingPrepared TINYINT(1) NULL, - TaskRatingRespectful TINYINT(1) NULL, - TaskRatingWouldAutoAssign TINYINT(1) NULL, + Prepared TINYINT(1) NULL, + Respectful TINYINT(1) NULL, + WouldAutoAssign TINYINT(1) NULL, -- For rating links in receipts - TaskRatingAccessToken VARCHAR(64) NOT NULL UNIQUE, - TaskRatingExpiresOn DATETIME NOT NULL, + AccessToken VARCHAR(64) NOT NULL UNIQUE, + ExpiresOn DATETIME NOT NULL, -- Timestamps - TaskRatingCreatedOn DATETIME DEFAULT CURRENT_TIMESTAMP, - TaskRatingCompletedOn DATETIME NULL, + CreatedOn DATETIME DEFAULT CURRENT_TIMESTAMP, + CompletedOn DATETIME NULL, - INDEX idx_task (TaskRatingTaskID), - INDEX idx_for_user (TaskRatingForUserID), - INDEX idx_by_user (TaskRatingByUserID), - INDEX idx_token (TaskRatingAccessToken) + INDEX idx_task (TaskID), + INDEX idx_for_user (ForUserID), + INDEX idx_by_user (ByUserID), + INDEX idx_token (AccessToken) ) ", {}, { datasource: "payfrit" }); diff --git a/api/ratings/submit.cfm b/api/ratings/submit.cfm index 22ace82..54b6a81 100644 --- a/api/ratings/submit.cfm +++ b/api/ratings/submit.cfm @@ -27,14 +27,14 @@ try { // Look up the rating by token qRating = queryExecute(" - SELECT r.*, t.TaskTitle, - u_for.UserFirstName AS ForUserFirstName, u_for.UserLastName AS ForUserLastName, - u_by.UserFirstName AS ByUserFirstName, u_by.UserLastName AS ByUserLastName + SELECT r.*, t.Title, + u_for.FirstName AS ForFirstName, u_for.LastName AS ForLastName, + u_by.FirstName AS ByFirstName, u_by.LastName AS ByLastName FROM TaskRatings r - JOIN Tasks t ON t.TaskID = r.TaskRatingTaskID - LEFT JOIN Users u_for ON u_for.UserID = r.TaskRatingForUserID - LEFT JOIN Users u_by ON u_by.UserID = r.TaskRatingByUserID - WHERE r.TaskRatingAccessToken = ? + JOIN Tasks t ON t.ID = r.TaskID + LEFT JOIN Users u_for ON u_for.ID = r.ForUserID + LEFT JOIN Users u_by ON u_by.ID = r.ByUserID + WHERE r.AccessToken = ? LIMIT 1 ", [{ value = token, cfsqltype = "cf_sql_varchar" }]); @@ -44,13 +44,13 @@ try { } // Check if expired - if (qRating.TaskRatingExpiresOn < now()) { + if (qRating.ExpiresOn < now()) { writeOutput(serializeJSON({ "OK": false, "ERROR": "expired", "MESSAGE": "This rating link has expired." })); abort; } // Check if already completed - if (len(trim(qRating.TaskRatingCompletedOn)) > 0) { + if (len(trim(qRating.CompletedOn)) > 0) { writeOutput(serializeJSON({ "OK": false, "ERROR": "already_submitted", "MESSAGE": "This rating has already been submitted." })); abort; } @@ -65,22 +65,22 @@ try { // Return rating details for UI to display result = { "OK": true, - "RatingID": qRating.TaskRatingID, - "Direction": qRating.TaskRatingDirection, - "TaskTitle": qRating.TaskTitle, - "ForUserName": trim(qRating.ForUserFirstName & " " & qRating.ForUserLastName), - "ExpiresOn": dateTimeFormat(qRating.TaskRatingExpiresOn, "yyyy-mm-dd HH:nn:ss") + "RatingID": qRating.ID, + "Direction": qRating.Direction, + "Title": qRating.Title, + "ForUserName": trim(qRating.ForFirstName & " " & qRating.ForLastName), + "ExpiresOn": dateTimeFormat(qRating.ExpiresOn, "yyyy-mm-dd HH:nn:ss") }; // Include appropriate questions based on direction - if (qRating.TaskRatingDirection == "customer_rates_worker" || qRating.TaskRatingDirection == "admin_rates_worker") { + if (qRating.Direction == "customer_rates_worker" || qRating.Direction == "admin_rates_worker") { result["Questions"] = { "onTime": "Was the worker on time?", "completedScope": "Was the scope completed?", "requiredFollowup": "Was follow-up required?", "continueAllow": "Continue to allow these tasks?" }; - } else if (qRating.TaskRatingDirection == "worker_rates_customer") { + } else if (qRating.Direction == "worker_rates_customer") { result["Questions"] = { "prepared": "Was the customer prepared?", "completedScope": "Was the scope clear?", @@ -94,37 +94,37 @@ try { } // Process submission based on direction - if (qRating.TaskRatingDirection == "customer_rates_worker" || qRating.TaskRatingDirection == "admin_rates_worker") { + if (qRating.Direction == "customer_rates_worker" || qRating.Direction == "admin_rates_worker") { queryExecute(" UPDATE TaskRatings SET - TaskRatingOnTime = ?, - TaskRatingCompletedScope = ?, - TaskRatingRequiredFollowup = ?, - TaskRatingContinueAllow = ?, - TaskRatingCompletedOn = NOW() - WHERE TaskRatingID = ? + OnTime = ?, + CompletedScope = ?, + RequiredFollowup = ?, + ContinueAllow = ?, + CompletedOn = NOW() + WHERE ID = ? ", [ { value = structKeyExists(data,"onTime") ? (data.onTime ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"onTime") }, { value = structKeyExists(data,"completedScope") ? (data.completedScope ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"completedScope") }, { value = structKeyExists(data,"requiredFollowup") ? (data.requiredFollowup ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"requiredFollowup") }, { value = structKeyExists(data,"continueAllow") ? (data.continueAllow ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"continueAllow") }, - { value = qRating.TaskRatingID, cfsqltype = "cf_sql_integer" } + { value = qRating.ID, cfsqltype = "cf_sql_integer" } ]); - } else if (qRating.TaskRatingDirection == "worker_rates_customer") { + } else if (qRating.Direction == "worker_rates_customer") { queryExecute(" UPDATE TaskRatings SET - TaskRatingPrepared = ?, - TaskRatingCompletedScope = ?, - TaskRatingRespectful = ?, - TaskRatingWouldAutoAssign = ?, - TaskRatingCompletedOn = NOW() - WHERE TaskRatingID = ? + Prepared = ?, + CompletedScope = ?, + Respectful = ?, + WouldAutoAssign = ?, + CompletedOn = NOW() + WHERE ID = ? ", [ { value = structKeyExists(data,"prepared") ? (data.prepared ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"prepared") }, { value = structKeyExists(data,"completedScope") ? (data.completedScope ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"completedScope") }, { value = structKeyExists(data,"respectful") ? (data.respectful ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"respectful") }, { value = structKeyExists(data,"wouldAutoAssign") ? (data.wouldAutoAssign ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"wouldAutoAssign") }, - { value = qRating.TaskRatingID, cfsqltype = "cf_sql_integer" } + { value = qRating.ID, cfsqltype = "cf_sql_integer" } ]); } diff --git a/api/servicepoints/delete.cfm b/api/servicepoints/delete.cfm index 3638d9c..2b2c8e2 100644 --- a/api/servicepoints/delete.cfm +++ b/api/servicepoints/delete.cfm @@ -49,17 +49,17 @@ servicePointId = int(data.ServicePointID); UPDATE ServicePoints - SET ServicePointIsActive = 0 + SET IsActive = 0 WHERE ServicePointID = - AND ServicePointBusinessID = + AND BusinessID = - SELECT ServicePointID, ServicePointIsActive + SELECT ID, IsActive FROM ServicePoints - WHERE ServicePointID = - AND ServicePointBusinessID = + WHERE ID = + AND BusinessID = LIMIT 1 diff --git a/api/servicepoints/get.cfm b/api/servicepoints/get.cfm index fd54b7c..6808a37 100644 --- a/api/servicepoints/get.cfm +++ b/api/servicepoints/get.cfm @@ -37,16 +37,16 @@ servicePointId = int(data.ServicePointID); SELECT - ServicePointID, - ServicePointBusinessID, - ServicePointName, - ServicePointCode, - ServicePointTypeID, - ServicePointIsActive, + ID, + BusinessID, + Name, + Code, + TypeID, + IsActive, SortOrder FROM ServicePoints - WHERE ServicePointID = - AND ServicePointBusinessID = + WHERE ID = + AND BusinessID = LIMIT 1 @@ -56,12 +56,12 @@ servicePointId = int(data.ServicePointID); diff --git a/api/servicepoints/list.cfm b/api/servicepoints/list.cfm index f8e6f5f..eb13235 100644 --- a/api/servicepoints/list.cfm +++ b/api/servicepoints/list.cfm @@ -57,31 +57,31 @@ if (structKeyExists(data, "onlyActive")) { SELECT - ServicePointID, - ServicePointName, - ServicePointTypeID, - ServicePointCode, - ServicePointDescription, - ServicePointSortOrder, - ServicePointIsActive + ID, + Name, + TypeID, + Code, + Description, + SortOrder, + IsActive FROM ServicePoints - WHERE ServicePointBusinessID = + WHERE BusinessID = - AND ServicePointIsActive = 1 + AND IsActive = 1 - ORDER BY ServicePointSortOrder, ServicePointName + ORDER BY SortOrder, Name diff --git a/api/servicepoints/reassign_all.cfm b/api/servicepoints/reassign_all.cfm index 34cde69..ff50a49 100644 --- a/api/servicepoints/reassign_all.cfm +++ b/api/servicepoints/reassign_all.cfm @@ -7,11 +7,11 @@ UPDATE ServicePoints - SET ServicePointBusinessID = + SET BusinessID = - SELECT COUNT(*) AS cnt FROM ServicePoints WHERE ServicePointBusinessID = + SELECT COUNT(*) AS cnt FROM ServicePoints WHERE BusinessID = #serializeJSON({ "OK": true, "MESSAGE": "All service points reassigned to BusinessID #targetBusinessID#", "COUNT": qCount.cnt })# diff --git a/api/servicepoints/save.cfm b/api/servicepoints/save.cfm index 29a818b..ebf8069 100644 --- a/api/servicepoints/save.cfm +++ b/api/servicepoints/save.cfm @@ -34,8 +34,8 @@ if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || apiAbort({ OK=false, ERROR="no_business_selected" }); } -if (!structKeyExists(data, "ServicePointName") || len(normStr(data.ServicePointName)) EQ 0) { - apiAbort({ OK=false, ERROR="missing_name", MESSAGE="ServicePointName is required" }); +if (!structKeyExists(data, "Name") || len(normStr(data.Name)) EQ 0) { + apiAbort({ OK=false, ERROR="missing_name", MESSAGE="Name is required" }); } servicePointId = 0; @@ -43,10 +43,10 @@ if (structKeyExists(data, "ServicePointID") && isNumeric(data.ServicePointID) && servicePointId = int(data.ServicePointID); } -spName = normStr(data.ServicePointName); -spCode = structKeyExists(data, "ServicePointCode") ? normStr(data.ServicePointCode) : ""; -spTypeID = structKeyExists(data, "ServicePointTypeID") && isNumeric(data.ServicePointTypeID) ? int(data.ServicePointTypeID) : 1; -sortOrder = structKeyExists(data, "ServicePointSortOrder") && isNumeric(data.ServicePointSortOrder) ? int(data.ServicePointSortOrder) : 0; +spName = normStr(data.Name); +spCode = structKeyExists(data, "Code") ? normStr(data.Code) : ""; +spTypeID = structKeyExists(data, "TypeID") && isNumeric(data.TypeID) ? int(data.TypeID) : 1; +sortOrder = structKeyExists(data, "SortOrder") && isNumeric(data.SortOrder) ? int(data.SortOrder) : 0; isActive = 1; if (structKeyExists(data, "IsActive")) { @@ -61,21 +61,21 @@ if (structKeyExists(data, "IsActive")) { UPDATE ServicePoints SET - ServicePointName = , - ServicePointCode = , - ServicePointTypeID = , - ServicePointIsActive = , - ServicePointSortOrder = + Name = , + Code = , + TypeID = , + IsActive = , + SortOrder = WHERE ServicePointID = - AND ServicePointBusinessID = + AND BusinessID = - SELECT ServicePointID + SELECT ID FROM ServicePoints - WHERE ServicePointID = - AND ServicePointBusinessID = + WHERE ID = + AND BusinessID = LIMIT 1 @@ -88,12 +88,12 @@ if (structKeyExists(data, "IsActive")) { INSERT INTO ServicePoints ( - ServicePointBusinessID, - ServicePointName, - ServicePointCode, - ServicePointTypeID, - ServicePointIsActive, - ServicePointSortOrder + BusinessID, + Name, + Code, + TypeID, + IsActive, + SortOrder ) VALUES ( , , @@ -113,27 +113,27 @@ if (structKeyExists(data, "IsActive")) { SELECT - ServicePointID, - ServicePointBusinessID, - ServicePointName, - ServicePointCode, - ServicePointTypeID, - ServicePointIsActive, - ServicePointSortOrder + ID, + BusinessID, + Name, + Code, + TypeID, + IsActive, + SortOrder FROM ServicePoints - WHERE ServicePointID = - AND ServicePointBusinessID = + WHERE ID = + AND BusinessID = LIMIT 1 #serializeJSON({ OK=true, ERROR="", SERVICEPOINT=servicePoint })# diff --git a/api/setup/checkDuplicate.cfm b/api/setup/checkDuplicate.cfm index 1a69d06..fdb1a09 100644 --- a/api/setup/checkDuplicate.cfm +++ b/api/setup/checkDuplicate.cfm @@ -18,7 +18,7 @@ * Returns: * { * "OK": true, - * "duplicates": [ { BusinessID, BusinessName, Address } ] + * "duplicates": [ { BusinessID, Name, Address } ] * } */ @@ -45,24 +45,24 @@ try { // Match by name (case-insensitive) OR by address components qDuplicates = queryExecute(" SELECT DISTINCT - b.BusinessID, - b.BusinessName, - a.AddressLine1, - a.AddressCity, - s.tt_StateAbbreviation as AddressState, - a.AddressZIPCode + b.ID, + b.Name, + a.Line1, + a.City, + s.Abbreviation as AddressState, + a.ZIPCode FROM Businesses b - LEFT JOIN Addresses a ON a.AddressBusinessID = b.BusinessID - LEFT JOIN tt_States s ON s.tt_StateID = a.AddressStateID + LEFT JOIN Addresses a ON a.BusinessID = b.ID + LEFT JOIN tt_States s ON s.ID = a.StateID WHERE - LOWER(b.BusinessName) = LOWER(:bizName) + LOWER(b.Name) = LOWER(:bizName) OR ( - LOWER(a.AddressLine1) = LOWER(:addressLine1) - AND LOWER(a.AddressCity) = LOWER(:city) - AND a.AddressLine1 != '' - AND a.AddressCity != '' + LOWER(a.Line1) = LOWER(:addressLine1) + AND LOWER(a.City) = LOWER(:city) + AND a.Line1 != '' + AND a.City != '' ) - ORDER BY b.BusinessName + ORDER BY b.Name ", { bizName: bizName, addressLine1: addressLine1, @@ -71,14 +71,14 @@ try { for (i = 1; i <= qDuplicates.recordCount; i++) { addressParts = []; - if (len(qDuplicates.AddressLine1[i])) arrayAppend(addressParts, qDuplicates.AddressLine1[i]); - if (len(qDuplicates.AddressCity[i])) arrayAppend(addressParts, qDuplicates.AddressCity[i]); + if (len(qDuplicates.Line1[i])) arrayAppend(addressParts, qDuplicates.Line1[i]); + if (len(qDuplicates.City[i])) arrayAppend(addressParts, qDuplicates.City[i]); if (len(qDuplicates.AddressState[i])) arrayAppend(addressParts, qDuplicates.AddressState[i]); - if (len(qDuplicates.AddressZIPCode[i])) arrayAppend(addressParts, qDuplicates.AddressZIPCode[i]); + if (len(qDuplicates.ZIPCode[i])) arrayAppend(addressParts, qDuplicates.ZIPCode[i]); arrayAppend(response.duplicates, { "BusinessID": qDuplicates.BusinessID[i], - "BusinessName": qDuplicates.BusinessName[i], + "Name": qDuplicates.Name[i], "Address": arrayToList(addressParts, ", ") }); } diff --git a/api/setup/importBusiness.cfm b/api/setup/importBusiness.cfm index 0f05ba0..460933d 100644 --- a/api/setup/importBusiness.cfm +++ b/api/setup/importBusiness.cfm @@ -11,7 +11,7 @@ * - Business record with contact info * - Categories as Items (ParentID=0) * - Menu items as children of categories - * - Modifier templates linked via ItemTemplateLinks + * - Modifier templates linked via lt_ItemID_TemplateItemID * - Modifier options as children of templates * * POST JSON structure: @@ -93,7 +93,7 @@ try { response.steps.append("Step 1: Creating business record..."); qCheck = queryExecute(" - SELECT BusinessID FROM Businesses WHERE BusinessName = :name + SELECT ID FROM Businesses WHERE Name = :name ", { name: biz.name }, { datasource: "payfrit" }); if (qCheck.recordCount > 0) { @@ -102,7 +102,7 @@ try { response.warnings.append("Existing business found - will add to existing menu"); } else if (!dryRun) { queryExecute(" - INSERT INTO Businesses (BusinessName, BusinessUserID, BusinessAddressID, BusinessDeliveryZipCodes, BusinessAddedOn) VALUES (:name, :ownerID, 0, '', NOW()) + INSERT INTO Businesses (Name, UserID, AddressID, BusinessDeliveryZipCodes, AddedOn) VALUES (:name, :ownerID, 0, '', NOW()) ", { name: biz.name, ownerID: ownerUserID }, { datasource: "payfrit" }); @@ -130,23 +130,23 @@ try { if (!dryRun) { // Check if template already exists for this business qTmpl = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemBusinessID = :bizID - AND ItemName = :name - AND ItemParentItemID = 0 - AND ItemID IN (SELECT TemplateItemID FROM ItemTemplateLinks) + SELECT ID FROM Items + WHERE BusinessID = :bizID + AND Name = :name + AND ParentItemID = 0 + AND ItemID IN (SELECT TemplateItemID FROM lt_ItemID_TemplateItemID) ", { bizID: BusinessID, name: templateName }, { datasource: "payfrit" }); if (qTmpl.recordCount > 0) { templateItemID = qTmpl.ItemID; response.steps.append("Template exists: " & templateName & " (ID: " & templateItemID & ")"); } else { - // Create template as Item at ParentID=0, with ItemIsCollapsible=1 to mark it as a template + // Create template as Item at ParentID=0, with IsCollapsible=1 to mark it as a template // This ensures the API filter excludes it from categories queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemName, ItemParentItemID, ItemPrice, - ItemIsActive, ItemRequiresChildSelection, ItemMaxNumSelectionReq, ItemSortOrder, ItemIsCollapsible + BusinessID, Name, ParentItemID, Price, + IsActive, RequiresChildSelection, MaxNumSelectionReq, SortOrder, IsCollapsible ) VALUES ( :bizID, :name, 0, 0, 1, :required, :maxSelect, 0, 1 ) @@ -173,15 +173,15 @@ try { optDefault = structKeyExists(opt, "isDefault") && opt.isDefault == true; qOpt = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemBusinessID = :bizID AND ItemName = :name AND ItemParentItemID = :parentID + SELECT ID FROM Items + WHERE BusinessID = :bizID AND Name = :name AND ParentItemID = :parentID ", { bizID: BusinessID, name: optName, parentID: templateItemID }, { datasource: "payfrit" }); if (qOpt.recordCount == 0) { queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemName, ItemParentItemID, ItemPrice, - ItemIsActive, ItemIsCheckedByDefault, ItemSortOrder + BusinessID, Name, ParentItemID, Price, + IsActive, IsCheckedByDefault, SortOrder ) VALUES ( :bizID, :name, :parentID, :price, 1, :isDefault, :sortOrder ) @@ -215,11 +215,11 @@ try { if (!dryRun) { // Check if category exists (Item at ParentID=0, not a template) qCat = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemBusinessID = :bizID - AND ItemName = :name - AND ItemParentItemID = 0 - AND ItemID NOT IN (SELECT TemplateItemID FROM ItemTemplateLinks) + SELECT ID FROM Items + WHERE BusinessID = :bizID + AND Name = :name + AND ParentItemID = 0 + AND ItemID NOT IN (SELECT TemplateItemID FROM lt_ItemID_TemplateItemID) ", { bizID: BusinessID, name: catName }, { datasource: "payfrit" }); if (qCat.recordCount > 0) { @@ -228,8 +228,8 @@ try { } else { queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemName, ItemParentItemID, ItemPrice, - ItemIsActive, ItemSortOrder + BusinessID, Name, ParentItemID, Price, + IsActive, SortOrder ) VALUES ( :bizID, :name, 0, 0, 1, :sortOrder ) @@ -272,17 +272,17 @@ try { if (!dryRun) { // Check if item exists qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemBusinessID = :bizID AND ItemName = :name AND ItemParentItemID = :parentID + SELECT ID FROM Items + WHERE BusinessID = :bizID AND Name = :name AND ParentItemID = :parentID ", { bizID: BusinessID, name: itemName, parentID: categoryItemID }, { datasource: "payfrit" }); if (qItem.recordCount > 0) { - menuItemID = qItem.ItemID; + menuItemID = qItem.ID; } else { queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemName, ItemDescription, ItemParentItemID, - ItemPrice, ItemIsActive, ItemSortOrder + BusinessID, Name, Description, ParentItemID, + Price, IsActive, SortOrder ) VALUES ( :bizID, :name, :desc, :parentID, :price, 1, :sortOrder ) @@ -308,13 +308,13 @@ try { // Check if link exists qLink = queryExecute(" - SELECT 1 FROM ItemTemplateLinks + SELECT 1 FROM lt_ItemID_TemplateItemID WHERE ItemID = :itemID AND TemplateItemID = :templateID ", { itemID: menuItemID, templateID: templateItemID }, { datasource: "payfrit" }); if (qLink.recordCount == 0) { queryExecute(" - INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder) + INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder) VALUES (:itemID, :templateID, :sortOrder) ", { itemID: menuItemID, diff --git a/api/setup/reimportBigDeans.cfm b/api/setup/reimportBigDeans.cfm index 24ea666..6dfe0e8 100644 --- a/api/setup/reimportBigDeans.cfm +++ b/api/setup/reimportBigDeans.cfm @@ -16,9 +16,9 @@ actions = []; // ============================================================ if (!dryRun) { // Delete template links first - queryExecute("DELETE FROM ItemTemplateLinks WHERE ItemID IN (SELECT ItemID FROM Items WHERE ItemBusinessID = :bizId)", { bizId: bizId }); + queryExecute("DELETE FROM lt_ItemID_TemplateItemID WHERE ItemID IN (SELECT ID FROM Items WHERE BusinessID = :bizId)", { bizId: bizId }); // Delete all items - queryExecute("DELETE FROM Items WHERE ItemBusinessID = :bizId", { bizId: bizId }); + queryExecute("DELETE FROM Items WHERE BusinessID = :bizId", { bizId: bizId }); } arrayAppend(actions, { step: "CLEAR", message: dryRun ? "Would clear existing data" : "Cleared existing data" }); @@ -29,11 +29,11 @@ arrayAppend(actions, { step: "CLEAR", message: dryRun ? "Would clear existing da // Helper function to insert item and return ID function insertItem(name, description, parentId, price, isActive, isCheckedByDefault, requiresChild, maxSelections, isCollapsible, sortOrder) { if (dryRun) return 0; - // Note: ItemIsActive is BIT(1) type, use b'1' or b'0' syntax + // Note: IsActive is BIT(1) type, use b'1' or b'0' syntax queryExecute(" - INSERT INTO Items (ItemBusinessID, ItemName, ItemDescription, ItemParentItemID, ItemPrice, - ItemIsActive, ItemIsCheckedByDefault, ItemRequiresChildSelection, - ItemMaxNumSelectionReq, ItemIsCollapsible, ItemSortOrder, ItemAddedOn) + INSERT INTO Items (BusinessID, Name, Description, ParentItemID, Price, + IsActive, IsCheckedByDefault, RequiresChildSelection, + MaxNumSelectionReq, IsCollapsible, SortOrder, AddedOn) VALUES (:bizId, :name, :desc, :parentId, :price, b'#isActive#', :isDefault, :reqChild, :maxSel, :isCollapse, :sort, NOW()) ", { bizId: bizId, name: name, desc: description, parentId: parentId, price: price, @@ -49,7 +49,7 @@ function insertItem(name, description, parentId, price, isActive, isCheckedByDef function linkTemplate(menuItemId, templateId, sortOrder) { if (dryRun) return; queryExecute(" - INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder) + INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder) VALUES (:itemId, :templateId, :sort) ", { itemId: menuItemId, templateId: templateId, sort: sortOrder }); } @@ -316,16 +316,16 @@ arrayAppend(actions, { step: "ITEMS", category: "Hot Dogs & Such", count: 3 }); // Count totals if (!dryRun) { - qCount = queryExecute("SELECT COUNT(*) as cnt FROM Items WHERE ItemBusinessID = :bizId", { bizId: bizId }); + qCount = queryExecute("SELECT COUNT(*) as cnt FROM Items WHERE BusinessID = :bizId", { bizId: bizId }); totalItems = qCount.cnt; - qTemplateCount = queryExecute("SELECT COUNT(*) as cnt FROM Items WHERE ItemBusinessID = :bizId AND ItemParentItemID = 0 AND ItemIsCollapsible = 1", { bizId: bizId }); + qTemplateCount = queryExecute("SELECT COUNT(*) as cnt FROM Items WHERE BusinessID = :bizId AND ParentItemID = 0 AND IsCollapsible = 1", { bizId: bizId }); templateCount = qTemplateCount.cnt; qLinkCount = queryExecute(" - SELECT COUNT(*) as cnt FROM ItemTemplateLinks tl - JOIN Items i ON i.ItemID = tl.ItemID - WHERE i.ItemBusinessID = :bizId + SELECT COUNT(*) as cnt FROM lt_ItemID_TemplateItemID tl + JOIN Items i ON i.ID = tl.ItemID + WHERE i.BusinessID = :bizId ", { bizId: bizId }); linkCount = qLinkCount.cnt; } else { diff --git a/api/setup/saveWizard.cfm b/api/setup/saveWizard.cfm index d80833c..06a4040 100644 --- a/api/setup/saveWizard.cfm +++ b/api/setup/saveWizard.cfm @@ -71,7 +71,7 @@ try { response.steps.append("State value received: '" & state & "' (len: " & len(state) & ")"); if (len(state)) { qState = queryExecute(" - SELECT tt_StateID FROM tt_States WHERE tt_StateAbbreviation = :abbr + SELECT tt_StateID FROM tt_States WHERE Abbreviation = :abbr ", { abbr: uCase(state) }, { datasource: "payfrit" }); response.steps.append("State lookup for '" & uCase(state) & "' found " & qState.recordCount & " records"); @@ -82,7 +82,7 @@ try { } queryExecute(" - INSERT INTO Addresses (AddressLine1, AddressCity, AddressStateID, AddressZIPCode, AddressUserID, AddressTypeID, AddressAddedOn) + INSERT INTO Addresses (Line1, City, StateID, ZIPCode, UserID, AddressTypeID, AddedOn) VALUES (:line1, :city, :stateID, :zip, :userID, :typeID, NOW()) ", { line1: len(addressLine1) ? addressLine1 : "Address pending", @@ -103,7 +103,7 @@ try { // Create new business with address link and phone queryExecute(" - INSERT INTO Businesses (BusinessName, BusinessPhone, BusinessUserID, BusinessAddressID, BusinessDeliveryZipCodes, BusinessCommunityMealType, BusinessTaxRate, BusinessAddedOn) + INSERT INTO Businesses (Name, Phone, UserID, AddressID, BusinessDeliveryZipCodes, CommunityMealType, TaxRate, AddedOn) VALUES (:name, :phone, :userId, :addressId, :deliveryZips, :communityMealType, :taxRate, NOW()) ", { name: bizName, @@ -121,7 +121,7 @@ try { // Update address with business ID link queryExecute(" - UPDATE Addresses SET AddressBusinessID = :businessID WHERE AddressID = :addressID + UPDATE Addresses SET BusinessID = :businessID WHERE ID = :addressID ", { businessID: businessId, addressID: addressId @@ -141,7 +141,7 @@ try { for (tt = 1; tt <= arrayLen(defaultTaskTypes); tt++) { taskType = defaultTaskTypes[tt]; queryExecute(" - INSERT INTO tt_TaskTypes (tt_TaskTypeName, tt_TaskTypeDescription, tt_TaskTypeIcon, tt_TaskTypeColor, tt_TaskTypeBusinessID, tt_TaskTypeSortOrder) + INSERT INTO tt_TaskTypes (Name, Description, Icon, Color, BusinessID, SortOrder) VALUES (:name, :description, :icon, :color, :businessID, :sortOrder) ", { name: { value: taskType.name, cfsqltype: "cf_sql_varchar" }, @@ -173,7 +173,7 @@ try { // Insert hours record for this day queryExecute(" - INSERT INTO Hours (HoursBusinessID, HoursDayID, HoursOpenTime, HoursClosingTime) + INSERT INTO Hours (BusinessID, DayID, OpenTime, ClosingTime) VALUES (:bizID, :dayID, :openTime, :closeTime) ", { bizID: businessId, @@ -188,14 +188,14 @@ try { } else { // Verify existing business exists qBiz = queryExecute(" - SELECT BusinessID, BusinessName FROM Businesses WHERE BusinessID = :id + SELECT ID, Name FROM Businesses WHERE ID = :id ", { id: businessId }, { datasource: "payfrit" }); if (qBiz.recordCount == 0) { throw(message="Business not found: " & businessId); } - response.steps.append("Found existing business: " & qBiz.BusinessName); + response.steps.append("Found existing business: " & qBiz.Name); } // Build modifier template map @@ -220,23 +220,23 @@ try { // Check if template already exists for this business qTmpl = queryExecute(" - SELECT i.ItemID FROM Items i - WHERE i.ItemBusinessID = :bizID - AND i.ItemName = :name - AND i.ItemParentItemID = 0 - AND i.ItemCategoryID = 0 + SELECT i.ID FROM Items i + WHERE i.BusinessID = :bizID + AND i.Name = :name + AND i.ParentItemID = 0 + AND i.CategoryID = 0 ", { bizID: businessId, name: tmplName }, { datasource: "payfrit" }); if (qTmpl.recordCount > 0) { templateItemID = qTmpl.ItemID; response.steps.append("Template exists: " & tmplName & " (ID: " & templateItemID & ")"); } else { - // Create template as Item with ItemCategoryID=0 to mark as template + // Create template as Item with CategoryID=0 to mark as template queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemName, ItemParentItemID, ItemCategoryID, ItemPrice, - ItemIsActive, ItemRequiresChildSelection, ItemMaxNumSelectionReq, - ItemSortOrder + BusinessID, Name, ParentItemID, CategoryID, Price, + IsActive, RequiresChildSelection, MaxNumSelectionReq, + SortOrder ) VALUES ( :bizID, :name, 0, 0, 0, 1, :required, 1, 0 ) @@ -267,15 +267,15 @@ try { optPrice = structKeyExists(opt, "price") && isSimpleValue(opt.price) ? val(opt.price) : 0; qOpt = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemBusinessID = :bizID AND ItemName = :name AND ItemParentItemID = :parentID + SELECT ID FROM Items + WHERE BusinessID = :bizID AND Name = :name AND ParentItemID = :parentID ", { bizID: businessId, name: optName, parentID: templateItemID }, { datasource: "payfrit" }); if (qOpt.recordCount == 0) { queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemName, ItemParentItemID, ItemCategoryID, - ItemPrice, ItemIsActive, ItemSortOrder + BusinessID, Name, ParentItemID, CategoryID, + Price, IsActive, SortOrder ) VALUES ( :bizID, :name, :parentID, 0, :price, 1, :sortOrder ) @@ -295,8 +295,8 @@ try { if (providedMenuId > 0) { menuID = providedMenuId; // Look up the menu name for logging - qMenuName = queryExecute("SELECT MenuName FROM Menus WHERE MenuID = :id", { id: menuID }, { datasource: "payfrit" }); - menuName = qMenuName.recordCount > 0 ? qMenuName.MenuName : "Menu " & menuID; + qName = queryExecute("SELECT Name FROM Menus WHERE ID = :id", { id: menuID }, { datasource: "payfrit" }); + menuName = qName.recordCount > 0 ? qName.Name : "Menu " & menuID; response.steps.append("Using provided menu: " & menuName & " (ID: " & menuID & ")"); } else { // Create a Menu record for this business (or get existing menu with same name) @@ -319,9 +319,9 @@ try { // Validate menu hours fall within business operating hours if (len(menuStartTime) && len(menuEndTime)) { qHours = queryExecute(" - SELECT MIN(HoursOpenTime) as earliestOpen, MAX(HoursClosingTime) as latestClose + SELECT MIN(OpenTime) as earliestOpen, MAX(ClosingTime) as latestClose FROM Hours - WHERE HoursBusinessID = :bizID + WHERE BusinessID = :bizID ", { bizID: businessId }, { datasource: "payfrit" }); if (qHours.recordCount > 0 && !isNull(qHours.earliestOpen) && !isNull(qHours.latestClose)) { @@ -336,17 +336,17 @@ try { } qMenu = queryExecute(" - SELECT MenuID FROM Menus - WHERE MenuBusinessID = :bizID AND MenuName = :name AND MenuIsActive = 1 + SELECT ID FROM Menus + WHERE BusinessID = :bizID AND Name = :name AND IsActive = 1 ", { bizID: businessId, name: menuName }, { datasource: "payfrit" }); if (qMenu.recordCount > 0) { - menuID = qMenu.MenuID; + menuID = qMenu.ID; // 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 + UPDATE Menus SET StartTime = :startTime, EndTime = :endTime + WHERE ID = :menuID ", { menuID: menuID, startTime: menuStartTime, @@ -359,7 +359,7 @@ try { } else { queryExecute(" INSERT INTO Menus ( - MenuBusinessID, MenuName, MenuDaysActive, MenuStartTime, MenuEndTime, MenuSortOrder, MenuIsActive, MenuAddedOn + BusinessID, Name, DaysActive, StartTime, EndTime, SortOrder, IsActive, AddedOn ) VALUES ( :bizID, :name, 127, :startTime, :endTime, 0, 1, NOW() ) @@ -394,8 +394,8 @@ try { // Check if category exists in Categories table for this menu qCat = queryExecute(" - SELECT CategoryID FROM Categories - WHERE CategoryBusinessID = :bizID AND CategoryName = :name AND CategoryMenuID = :menuID + SELECT ID FROM Categories + WHERE BusinessID = :bizID AND Name = :name AND MenuID = :menuID ", { bizID: businessId, name: catName, menuID: menuID }, { datasource: "payfrit" }); if (qCat.recordCount > 0) { @@ -405,7 +405,7 @@ try { // Create category in Categories table with MenuID queryExecute(" INSERT INTO Categories ( - CategoryBusinessID, CategoryMenuID, CategoryName, CategorySortOrder + BusinessID, MenuID, Name, SortOrder ) VALUES ( :bizID, :menuID, :name, :sortOrder ) @@ -483,20 +483,20 @@ try { // Check if item exists qItem = queryExecute(" - SELECT ItemID FROM Items - WHERE ItemBusinessID = :bizID - AND ItemName = :name - AND ItemCategoryID = :catID + SELECT ID FROM Items + WHERE BusinessID = :bizID + AND Name = :name + AND CategoryID = :catID ", { bizID: businessId, name: itemName, catID: categoryID }, { datasource: "payfrit" }); if (qItem.recordCount > 0) { - menuItemID = qItem.ItemID; + menuItemID = qItem.ID; // Update existing item queryExecute(" UPDATE Items SET - ItemDescription = :desc, - ItemPrice = :price, - ItemSortOrder = :sortOrder + Description = :desc, + Price = :price, + SortOrder = :sortOrder WHERE ItemID = :id ", { desc: itemDesc, @@ -507,8 +507,8 @@ try { } else { queryExecute(" INSERT INTO Items ( - ItemBusinessID, ItemName, ItemDescription, ItemParentItemID, - ItemCategoryID, ItemPrice, ItemIsActive, ItemSortOrder + BusinessID, Name, Description, ParentItemID, + CategoryID, Price, IsActive, SortOrder ) VALUES ( :bizID, :name, :desc, 0, :catID, :price, 1, :sortOrder ) @@ -544,13 +544,13 @@ try { // Check if link exists qLink = queryExecute(" - SELECT 1 FROM ItemTemplateLinks + SELECT 1 FROM lt_ItemID_TemplateItemID WHERE ItemID = :itemID AND TemplateItemID = :templateID ", { itemID: menuItemID, templateID: templateItemID }, { datasource: "payfrit" }); if (qLink.recordCount == 0) { queryExecute(" - INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder) + INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder) VALUES (:itemID, :templateID, :sortOrder) ", { itemID: menuItemID, diff --git a/api/stations/list.cfm b/api/stations/list.cfm index 62d8520..b47750a 100644 --- a/api/stations/list.cfm +++ b/api/stations/list.cfm @@ -35,20 +35,20 @@ diff --git a/api/stripe/createPaymentIntent.cfm b/api/stripe/createPaymentIntent.cfm index 536384a..52ae950 100644 --- a/api/stripe/createPaymentIntent.cfm +++ b/api/stripe/createPaymentIntent.cfm @@ -62,9 +62,9 @@ try { // Get business Stripe account qBusiness = queryExecute(" - SELECT BusinessStripeAccountID, BusinessStripeOnboardingComplete, BusinessName + SELECT StripeAccountID, StripeOnboardingComplete, Name FROM Businesses - WHERE BusinessID = :businessID + WHERE ID = :businessID ", { businessID: businessID }, { datasource: "payfrit" }); if (qBusiness.recordCount == 0) { @@ -75,18 +75,18 @@ try { // Get order's delivery fee (if delivery order) qOrder = queryExecute(" - SELECT OrderDeliveryFee, OrderTypeID + SELECT DeliveryFee, OrderTypeID FROM Orders - WHERE OrderID = :orderID + WHERE ID = :orderID ", { orderID: orderID }, { datasource: "payfrit" }); deliveryFee = 0; if (qOrder.recordCount > 0 && qOrder.OrderTypeID == 3) { - deliveryFee = val(qOrder.OrderDeliveryFee); + deliveryFee = val(qOrder.DeliveryFee); } // For testing, allow orders even without Stripe Connect setup - hasStripeConnect = qBusiness.BusinessStripeOnboardingComplete == 1 && len(trim(qBusiness.BusinessStripeAccountID)) > 0; + hasStripeConnect = qBusiness.StripeOnboardingComplete == 1 && len(trim(qBusiness.StripeAccountID)) > 0; // ============================================================ // FEE CALCULATION @@ -119,12 +119,12 @@ try { if (hasStripeConnect) { httpService.addParam(type="formfield", name="application_fee_amount", value=totalPlatformFeeCents); - httpService.addParam(type="formfield", name="transfer_data[destination]", value=qBusiness.BusinessStripeAccountID); + httpService.addParam(type="formfield", name="transfer_data[destination]", value=qBusiness.StripeAccountID); } httpService.addParam(type="formfield", name="metadata[order_id]", value=orderID); httpService.addParam(type="formfield", name="metadata[business_id]", value=businessID); - httpService.addParam(type="formfield", name="description", value="Order ###orderID# at #qBusiness.BusinessName#"); + httpService.addParam(type="formfield", name="description", value="Order ###orderID# at #qBusiness.Name#"); if (customerEmail != "") { httpService.addParam(type="formfield", name="receipt_email", value=customerEmail); @@ -141,6 +141,23 @@ try { // Fees are calculated dynamically, not stored in DB + // Link PaymentIntent to worker payout ledger (if a ledger row exists for this order's task) + try { + queryExecute(" + UPDATE WorkPayoutLedgers wpl + INNER JOIN Tasks t ON t.TaskID = wpl.TaskID AND t.OrderID = :orderID + SET wpl.StripePaymentIntentID = :piID + WHERE wpl.Status = 'pending_charge' + AND wpl.StripePaymentIntentID IS NULL + ", { + orderID: orderID, + piID: piData.id + }, { datasource: "payfrit" }); + } catch (any e) { + // Non-fatal: ledger row may not exist yet (task not completed before payment) + writeLog(file="stripe_webhooks", text="Ledger link skipped for order #orderID#: #e.message#"); + } + response["OK"] = true; response["CLIENT_SECRET"] = piData.client_secret; response["PAYMENT_INTENT_ID"] = piData.id; diff --git a/api/stripe/onboard.cfm b/api/stripe/onboard.cfm index 6d13b3c..c59e3b9 100644 --- a/api/stripe/onboard.cfm +++ b/api/stripe/onboard.cfm @@ -32,9 +32,9 @@ try { // Check if business already has a Stripe account qBusiness = queryExecute(" - SELECT BusinessStripeAccountID, BusinessName, BusinessEmail + SELECT StripeAccountID, Name, BusinessEmail FROM Businesses - WHERE BusinessID = :businessID + WHERE ID = :businessID ", { businessID: businessID }); if (qBusiness.recordCount == 0) { @@ -43,7 +43,7 @@ try { abort; } - stripeAccountID = qBusiness.BusinessStripeAccountID; + stripeAccountID = qBusiness.StripeAccountID; // Create new connected account if none exists if (stripeAccountID == "" || isNull(stripeAccountID)) { @@ -58,7 +58,7 @@ try { httpService.addParam(type="formfield", name="email", value=qBusiness.BusinessEmail); httpService.addParam(type="formfield", name="capabilities[card_payments][requested]", value="true"); httpService.addParam(type="formfield", name="capabilities[transfers][requested]", value="true"); - httpService.addParam(type="formfield", name="business_profile[name]", value=qBusiness.BusinessName); + httpService.addParam(type="formfield", name="business_profile[name]", value=qBusiness.Name); result = httpService.send().getPrefix(); accountData = deserializeJSON(result.fileContent); @@ -74,8 +74,8 @@ try { // Save to database queryExecute(" UPDATE Businesses - SET BusinessStripeAccountID = :stripeAccountID, - BusinessStripeOnboardingStarted = NOW() + SET StripeAccountID = :stripeAccountID, + StripeOnboardingStarted = NOW() WHERE BusinessID = :businessID ", { stripeAccountID: stripeAccountID, diff --git a/api/stripe/status.cfm b/api/stripe/status.cfm index 532d09c..3e9bb4e 100644 --- a/api/stripe/status.cfm +++ b/api/stripe/status.cfm @@ -23,9 +23,9 @@ try { // Get business Stripe info qBusiness = queryExecute(" - SELECT BusinessStripeAccountID, BusinessStripeOnboardingComplete + SELECT StripeAccountID, StripeOnboardingComplete FROM Businesses - WHERE BusinessID = :businessID + WHERE ID = :businessID ", { businessID: businessID }); if (qBusiness.recordCount == 0) { @@ -34,7 +34,7 @@ try { abort; } - stripeAccountID = qBusiness.BusinessStripeAccountID; + stripeAccountID = qBusiness.StripeAccountID; if (stripeAccountID == "" || isNull(stripeAccountID)) { response["OK"] = true; @@ -73,10 +73,10 @@ try { accountStatus = "active"; // Mark as complete in database if not already - if (!qBusiness.BusinessStripeOnboardingComplete) { + if (!qBusiness.StripeOnboardingComplete) { queryExecute(" UPDATE Businesses - SET BusinessStripeOnboardingComplete = 1 + SET StripeOnboardingComplete = 1 WHERE BusinessID = :businessID ", { businessID: businessID }); } @@ -96,8 +96,8 @@ try { } else { // No Stripe key, just return what we have in DB response["OK"] = true; - response["CONNECTED"] = qBusiness.BusinessStripeOnboardingComplete == 1; - response["ACCOUNT_STATUS"] = qBusiness.BusinessStripeOnboardingComplete == 1 ? "active" : "unknown"; + response["CONNECTED"] = qBusiness.StripeOnboardingComplete == 1; + response["ACCOUNT_STATUS"] = qBusiness.StripeOnboardingComplete == 1 ? "active" : "unknown"; response["STRIPE_ACCOUNT_ID"] = stripeAccountID; } diff --git a/api/stripe/webhook.cfm b/api/stripe/webhook.cfm index e12097d..639e32d 100644 --- a/api/stripe/webhook.cfm +++ b/api/stripe/webhook.cfm @@ -52,14 +52,83 @@ try { // Note: Task is created later when order status changes to Ready (3) in updateStatus.cfm queryExecute(" UPDATE Orders - SET OrderPaymentStatus = 'paid', + SET PaymentStatus = 'paid', OrderPaymentCompletedOn = NOW(), - OrderStatusID = CASE WHEN OrderStatusID = 0 THEN 1 ELSE OrderStatusID END + StatusID = CASE WHEN StatusID = 0 THEN 1 ELSE StatusID END WHERE OrderID = :orderID ", { orderID: orderID }); writeLog(file="stripe_webhooks", text="Order #orderID# marked as paid"); } + + // === WORKER PAYOUT TRANSFER === + // Find ledger row for this PaymentIntent + try { + qLedger = queryExecute(" + SELECT wpl.ID, wpl.UserID, wpl.TaskID, wpl.NetTransferCents, + wpl.StripeTransferID, wpl.Status + FROM WorkPayoutLedgers wpl + WHERE wpl.StripePaymentIntentID = :piID + LIMIT 1 + ", { piID: paymentIntentID }); + + if (qLedger.recordCount > 0 && isNull(qLedger.StripeTransferID) && qLedger.Status == "pending_charge") { + // Mark as charged + queryExecute(" + UPDATE WorkPayoutLedgers SET Status = 'charged', UpdatedAt = NOW() + WHERE ID = :ledgerID + ", { ledgerID: qLedger.ID }); + + // Look up worker's Stripe Connected Account + qWorker = queryExecute(" + SELECT StripeConnectedAccountID FROM Users WHERE ID = :userID + ", { userID: qLedger.UserID }); + + workerAccountID = qWorker.recordCount > 0 ? (qWorker.StripeConnectedAccountID ?: "") : ""; + + if (len(trim(workerAccountID)) > 0 && qLedger.NetTransferCents > 0) { + // Create Stripe Transfer — regardless of payoutsEnabled (Stripe holds funds) + stripeSecretKey = application.stripeSecretKey ?: ""; + httpTransfer = new http(); + httpTransfer.setMethod("POST"); + httpTransfer.setUrl("https://api.stripe.com/v1/transfers"); + httpTransfer.setUsername(stripeSecretKey); + httpTransfer.setPassword(""); + httpTransfer.addParam(type="formfield", name="amount", value=qLedger.NetTransferCents); + httpTransfer.addParam(type="formfield", name="currency", value="usd"); + httpTransfer.addParam(type="formfield", name="destination", value=workerAccountID); + httpTransfer.addParam(type="formfield", name="metadata[user_id]", value=qLedger.UserID); + httpTransfer.addParam(type="formfield", name="metadata[task_id]", value=qLedger.TaskID); + httpTransfer.addParam(type="formfield", name="metadata[ledger_id]", value=qLedger.ID); + httpTransfer.addParam(type="formfield", name="metadata[activation_withheld_cents]", value=0); + + transferResult = httpTransfer.send().getPrefix(); + transferData = deserializeJSON(transferResult.fileContent); + + if (structKeyExists(transferData, "id")) { + queryExecute(" + UPDATE WorkPayoutLedgers + SET StripeTransferID = :transferID, Status = 'transferred', UpdatedAt = NOW() + WHERE ID = :ledgerID + ", { transferID: transferData.id, ledgerID: qLedger.ID }); + + writeLog(file="stripe_webhooks", text="Transfer #transferData.id# created for ledger #qLedger.ID#"); + } else { + writeLog(file="stripe_webhooks", text="Transfer failed for ledger #qLedger.ID#: #transferData.error.message ?: 'unknown'#"); + } + } else if (qLedger.NetTransferCents == 0) { + // Nothing to transfer (entire amount withheld for activation) + queryExecute(" + UPDATE WorkPayoutLedgers SET Status = 'transferred', UpdatedAt = NOW() + WHERE ID = :ledgerID + ", { ledgerID: qLedger.ID }); + } + // else: no connected account yet — stays 'charged', transfer deferred + } + } catch (any transferErr) { + writeLog(file="stripe_webhooks", text="Worker transfer error: #transferErr.message#"); + } + break; case "payment_intent.payment_failed": @@ -71,7 +140,7 @@ try { if (orderID > 0) { queryExecute(" UPDATE Orders - SET OrderPaymentStatus = 'failed', + SET PaymentStatus = 'failed', OrderPaymentError = :failureMessage WHERE OrderID = :orderID ", { @@ -91,14 +160,14 @@ try { if (paymentIntentID != "") { qOrder = queryExecute(" - SELECT OrderID FROM Orders + SELECT ID FROM Orders WHERE OrderStripePaymentIntentID = :paymentIntentID ", { paymentIntentID: paymentIntentID }); if (qOrder.recordCount > 0) { queryExecute(" UPDATE Orders - SET OrderPaymentStatus = 'refunded', + SET PaymentStatus = 'refunded', OrderRefundAmount = :refundAmount, OrderRefundedOn = NOW() WHERE OrderStripePaymentIntentID = :paymentIntentID @@ -119,27 +188,27 @@ try { if (paymentIntentID != "") { qOrder = queryExecute(" - SELECT OrderID, OrderBusinessID FROM Orders + SELECT ID, BusinessID FROM Orders WHERE OrderStripePaymentIntentID = :paymentIntentID ", { paymentIntentID: paymentIntentID }); if (qOrder.recordCount > 0) { queryExecute(" UPDATE Orders - SET OrderPaymentStatus = 'disputed' + SET PaymentStatus = 'disputed' WHERE OrderStripePaymentIntentID = :paymentIntentID ", { paymentIntentID: paymentIntentID }); // Create a task for the dispute queryExecute(" - INSERT INTO Tasks (TaskBusinessID, TaskCategoryID, TaskTitle, TaskDetails, TaskCreatedOn, TaskStatusID, TaskSourceType, TaskSourceID) - VALUES (:businessID, 4, 'Payment Dispute', 'Order ###qOrder.OrderID# has been disputed. Review immediately.', NOW(), 0, 'dispute', :orderID) + INSERT INTO Tasks (BusinessID, CategoryID, Title, Details, CreatedOn, StatusID, SourceType, SourceID) + VALUES (:businessID, 4, 'Payment Dispute', 'Order ###qOrder.ID# has been disputed. Review immediately.', NOW(), 0, 'dispute', :orderID) ", { - businessID: qOrder.OrderBusinessID, - orderID: qOrder.OrderID + businessID: qOrder.BusinessID, + orderID: qOrder.ID }); - writeLog(file="stripe_webhooks", text="Dispute created for order #qOrder.OrderID#"); + writeLog(file="stripe_webhooks", text="Dispute created for order #qOrder.ID#"); } } break; @@ -150,14 +219,61 @@ try { chargesEnabled = eventData.charges_enabled ?: false; payoutsEnabled = eventData.payouts_enabled ?: false; + // Business accounts if (chargesEnabled && payoutsEnabled) { queryExecute(" UPDATE Businesses - SET BusinessStripeOnboardingComplete = 1 - WHERE BusinessStripeAccountID = :accountID + SET StripeOnboardingComplete = 1 + WHERE StripeAccountID = :accountID ", { accountID: accountID }); - writeLog(file="stripe_webhooks", text="Account #accountID# is now fully active"); + writeLog(file="stripe_webhooks", text="Business account #accountID# is now fully active"); + } + + // Worker accounts — update StripePayoutsEnabled for tier derivation + try { + qWorkerAcct = queryExecute(" + SELECT ID FROM Users + WHERE StripeConnectedAccountID = :accountID + LIMIT 1 + ", { accountID: accountID }); + + if (qWorkerAcct.recordCount > 0) { + queryExecute(" + UPDATE Users + SET StripePayoutsEnabled = :payoutsEnabled + WHERE StripeConnectedAccountID = :accountID + ", { + payoutsEnabled: payoutsEnabled ? 1 : 0, + accountID: accountID + }); + + writeLog(file="stripe_webhooks", text="Worker user #qWorkerAcct.ID# payoutsEnabled=#payoutsEnabled#"); + } + } catch (any workerErr) { + writeLog(file="stripe_webhooks", text="Worker account update error: #workerErr.message#"); + } + + break; + + case "checkout.session.completed": + // Activation early unlock payment completed + try { + sessionMetadata = eventData.metadata ?: {}; + metaType = sessionMetadata.type ?: ""; + metaUserID = val(sessionMetadata.user_id ?: 0); + + if (metaType == "activation_unlock" && metaUserID > 0) { + queryExecute(" + UPDATE Users + SET ActivationBalanceCents = ActivationCapCents + WHERE ID = :userID + ", { userID: metaUserID }); + + writeLog(file="stripe_webhooks", text="Activation completed via payment for user #metaUserID#"); + } + } catch (any checkoutErr) { + writeLog(file="stripe_webhooks", text="Checkout session error: #checkoutErr.message#"); } break; diff --git a/api/tasks/accept.cfm b/api/tasks/accept.cfm index 2cef886..b17d0e9 100644 --- a/api/tasks/accept.cfm +++ b/api/tasks/accept.cfm @@ -37,26 +37,26 @@ - + 0) { userQuery = queryExecute(" - SELECT UserFirstName FROM Users WHERE UserID = :userID + SELECT FirstName FROM Users WHERE ID = :userID ", { userID: { value: userID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); - if (userQuery.recordCount && len(trim(userQuery.UserFirstName))) { - userName = userQuery.UserFirstName; + if (userQuery.recordCount && len(trim(userQuery.FirstName))) { + userName = userQuery.FirstName; } } @@ -63,14 +63,14 @@ try { taskTypeCategoryID = 0; if (taskTypeID > 0) { typeQuery = queryExecute(" - SELECT tt_TaskTypeName, tt_TaskTypeCategoryID FROM tt_TaskTypes WHERE tt_TaskTypeID = :typeID + SELECT Name, TaskCategoryID FROM tt_TaskTypes WHERE tt_TaskTypeID = :typeID ", { typeID: { value: taskTypeID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); if (typeQuery.recordCount) { - if (len(trim(typeQuery.tt_TaskTypeName))) { - taskTypeName = typeQuery.tt_TaskTypeName; + if (len(trim(typeQuery.Name))) { + taskTypeName = typeQuery.Name; } - if (!isNull(typeQuery.tt_TaskTypeCategoryID) && isNumeric(typeQuery.tt_TaskTypeCategoryID) && typeQuery.tt_TaskTypeCategoryID > 0) { - taskTypeCategoryID = typeQuery.tt_TaskTypeCategoryID; + if (!isNull(typeQuery.TaskCategoryID) && isNumeric(typeQuery.TaskCategoryID) && typeQuery.TaskCategoryID > 0) { + taskTypeCategoryID = typeQuery.TaskCategoryID; } } } @@ -105,36 +105,36 @@ try { } else { // Fallback: look up or create a "Service" category for this business catQuery = queryExecute(" - SELECT TaskCategoryID FROM TaskCategories - WHERE TaskCategoryBusinessID = :businessID AND TaskCategoryName = 'Service' + SELECT ID FROM TaskCategories + WHERE BusinessID = :businessID AND Name = 'Service' LIMIT 1 ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); if (catQuery.recordCount == 0) { // Create the category queryExecute(" - INSERT INTO TaskCategories (TaskCategoryBusinessID, TaskCategoryName, TaskCategoryColor) + INSERT INTO TaskCategories (BusinessID, Name, Color) VALUES (:businessID, 'Service', '##FF9800') ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); catResult = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" }); categoryID = catResult.newID; } else { - categoryID = catQuery.TaskCategoryID; + categoryID = catQuery.ID; } } // Insert task queryExecute(" INSERT INTO Tasks ( - TaskBusinessID, - TaskCategoryID, - TaskOrderID, + BusinessID, + CategoryID, + OrderID, TaskTypeID, - TaskTitle, - TaskDetails, - TaskClaimedByUserID, - TaskAddedOn + Title, + Details, + ClaimedByUserID, + CreatedOn ) VALUES ( :businessID, :categoryID, diff --git a/api/tasks/complete.cfm b/api/tasks/complete.cfm index c30eac2..455d773 100644 --- a/api/tasks/complete.cfm +++ b/api/tasks/complete.cfm @@ -45,11 +45,11 @@ @@ -59,23 +59,23 @@ - + - + - + - - - + + + @@ -104,30 +104,88 @@ - + + ", [ { value = qTask.OrderID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/api/tasks/completeChat.cfm b/api/tasks/completeChat.cfm index 795cfd8..7cd9d2a 100644 --- a/api/tasks/completeChat.cfm +++ b/api/tasks/completeChat.cfm @@ -36,9 +36,9 @@ @@ -51,14 +51,14 @@ - + diff --git a/api/tasks/create.cfm b/api/tasks/create.cfm index 05d251f..edeb522 100644 --- a/api/tasks/create.cfm +++ b/api/tasks/create.cfm @@ -31,14 +31,14 @@ try { // Get task type info for display taskTypeQuery = queryExecute(" - SELECT tt_TaskTypeName, tt_TaskTypeColor, tt_TaskTypeIcon + SELECT Name, Color, Icon FROM tt_TaskTypes WHERE tt_TaskTypeID = :taskTypeID ", { taskTypeID: taskTypeID }, { datasource: "payfrit" }); taskTitle = message; - if (taskTypeQuery.recordCount && len(taskTypeQuery.tt_TaskTypeName)) { - taskTitle = taskTypeQuery.tt_TaskTypeName; + if (taskTypeQuery.recordCount && len(taskTypeQuery.Name)) { + taskTitle = taskTypeQuery.Name; } // Use message as details @@ -47,14 +47,14 @@ try { // Insert service bell task queryExecute(" INSERT INTO Tasks ( - TaskBusinessID, + BusinessID, TaskTypeID, - TaskCategoryID, - TaskOrderID, - TaskTitle, - TaskDetails, - TaskAddedOn, - TaskClaimedByUserID + CategoryID, + OrderID, + Title, + Details, + CreatedOn, + ClaimedByUserID ) VALUES ( :businessID, :taskTypeID, @@ -84,10 +84,10 @@ try { itemName = ""; if (itemID > 0) { itemQuery = queryExecute(" - SELECT ItemName FROM Items WHERE ItemID = :itemID + SELECT Name FROM Items WHERE ID = :itemID ", { itemID: itemID }); if (itemQuery.recordCount) { - itemName = itemQuery.ItemName; + itemName = itemQuery.Name; } } @@ -107,14 +107,14 @@ try { // Insert legacy task queryExecute(" INSERT INTO Tasks ( - TaskBusinessID, + BusinessID, TaskItemID, TaskType, TaskDescription, TaskInstructions, TaskPYTReward, TaskStatus, - TaskCreatedOn + CreatedOn ) VALUES ( :businessID, :itemID, diff --git a/api/tasks/createChat.cfm b/api/tasks/createChat.cfm index ebf142c..af02596 100644 --- a/api/tasks/createChat.cfm +++ b/api/tasks/createChat.cfm @@ -39,27 +39,27 @@ try { // In that case, we use userID to match existing chats // Check for existing open chat at this service point - // An open chat is one where TaskTypeID=2 (Chat) and TaskCompletedOn IS NULL + // An open chat is one where TaskTypeID=2 (Chat) and CompletedOn IS NULL forceNew = structKeyExists(data, "ForceNew") && data.ForceNew == true; if (!forceNew) { // Look for any active chat for this business // Check by: order match, service point match, OR user match (for remote chats) existingChat = queryExecute(" - SELECT t.TaskID, t.TaskAddedOn, - (SELECT MAX(cm.CreatedOn) FROM ChatMessages cm WHERE cm.TaskID = t.TaskID) as LastMessageTime + SELECT t.ID, t.CreatedOn, + (SELECT MAX(cm.CreatedOn) FROM ChatMessages cm WHERE cm.TaskID = t.ID) as LastMessageTime FROM Tasks t - LEFT JOIN ChatMessages cm2 ON cm2.TaskID = t.TaskID AND cm2.SenderUserID = :userID - WHERE t.TaskBusinessID = :businessID + LEFT JOIN ChatMessages cm2 ON cm2.TaskID = t.ID AND cm2.SenderUserID = :userID + WHERE t.BusinessID = :businessID AND t.TaskTypeID = 2 - AND t.TaskCompletedOn IS NULL + AND t.CompletedOn IS NULL AND ( - (t.TaskOrderID = :orderID AND :orderID > 0) - OR (t.TaskSourceType = 'servicepoint' AND t.TaskSourceID = :servicePointID AND :servicePointID > 0) - OR (t.TaskSourceType = 'user' AND t.TaskSourceID = :userID AND :userID > 0) + (t.OrderID = :orderID AND :orderID > 0) + OR (t.SourceType = 'servicepoint' AND t.SourceID = :servicePointID AND :servicePointID > 0) + OR (t.SourceType = 'user' AND t.SourceID = :userID AND :userID > 0) OR (cm2.SenderUserID = :userID AND :userID > 0) ) - ORDER BY t.TaskAddedOn DESC + ORDER BY t.CreatedOn DESC LIMIT 1 ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" }, @@ -72,21 +72,21 @@ try { // Check if chat is stale (more than 30 minutes since last message, or 30 min since creation if no messages) lastActivity = existingChat.LastMessageTime; if (isNull(lastActivity) || !isDate(lastActivity)) { - lastActivity = existingChat.TaskAddedOn; + lastActivity = existingChat.CreatedOn; } chatAge = dateDiff("n", lastActivity, now()); if (chatAge > 30) { // Auto-close stale chat queryExecute(" - UPDATE Tasks SET TaskCompletedOn = NOW() + UPDATE Tasks SET CompletedOn = NOW() WHERE TaskID = :taskID - ", { taskID: { value: existingChat.TaskID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); + ", { taskID: { value: existingChat.ID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); } else { // Return existing chat apiAbort({ "OK": true, - "TaskID": existingChat.TaskID, + "TaskID": existingChat.ID, "MESSAGE": "Rejoined existing chat", "EXISTING": true }); @@ -98,19 +98,19 @@ try { tableName = ""; if (servicePointID > 0) { spQuery = queryExecute(" - SELECT ServicePointName FROM ServicePoints WHERE ServicePointID = :spID + SELECT Name FROM ServicePoints WHERE ID = :spID ", { spID: { value: servicePointID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); - tableName = spQuery.recordCount ? spQuery.ServicePointName : "Table ##" & servicePointID; + tableName = spQuery.recordCount ? spQuery.Name : "Table ##" & servicePointID; } // Get user name if available userName = ""; if (userID > 0) { userQuery = queryExecute(" - SELECT UserFirstName FROM Users WHERE UserID = :userID + SELECT FirstName FROM Users WHERE ID = :userID ", { userID: { value: userID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); - if (userQuery.recordCount && len(trim(userQuery.UserFirstName))) { - userName = userQuery.UserFirstName; + if (userQuery.recordCount && len(trim(userQuery.FirstName))) { + userName = userQuery.FirstName; } } @@ -137,22 +137,22 @@ try { // Look up or create a "Chat" category for this business catQuery = queryExecute(" - SELECT TaskCategoryID FROM TaskCategories - WHERE TaskCategoryBusinessID = :businessID AND TaskCategoryName = 'Chat' + SELECT ID FROM TaskCategories + WHERE BusinessID = :businessID AND Name = 'Chat' LIMIT 1 ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); if (catQuery.recordCount == 0) { // Create the category (blue color for chat) queryExecute(" - INSERT INTO TaskCategories (TaskCategoryBusinessID, TaskCategoryName, TaskCategoryColor) + INSERT INTO TaskCategories (BusinessID, Name, Color) VALUES (:businessID, 'Chat', '##2196F3') ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); catResult = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" }); categoryID = catResult.newID; } else { - categoryID = catQuery.TaskCategoryID; + categoryID = catQuery.ID; } // Determine source type and ID based on dine-in vs remote @@ -167,16 +167,16 @@ try { // Insert task with TaskTypeID = 2 (Chat) queryExecute(" INSERT INTO Tasks ( - TaskBusinessID, - TaskCategoryID, - TaskOrderID, + BusinessID, + CategoryID, + OrderID, TaskTypeID, - TaskTitle, - TaskDetails, - TaskClaimedByUserID, - TaskSourceType, - TaskSourceID, - TaskAddedOn + Title, + Details, + ClaimedByUserID, + SourceType, + SourceID, + CreatedOn ) VALUES ( :businessID, :categoryID, @@ -206,7 +206,7 @@ try { // If there's an initial message, save it if (len(initialMessage) && userID > 0) { queryExecute(" - INSERT INTO ChatMessages (TaskID, SenderUserID, SenderType, MessageText) + INSERT INTO ChatMessages (TaskID, SenderUserID, SenderType, MessageBody) VALUES (:taskID, :userID, 'customer', :message) ", { taskID: { value: taskID, cfsqltype: "cf_sql_integer" }, diff --git a/api/tasks/deleteCategory.cfm b/api/tasks/deleteCategory.cfm index e36dea9..5e8c311 100644 --- a/api/tasks/deleteCategory.cfm +++ b/api/tasks/deleteCategory.cfm @@ -51,8 +51,8 @@ try { // Verify ownership qCheck = queryExecute(" - SELECT TaskCategoryID FROM TaskCategories - WHERE TaskCategoryID = :id AND TaskCategoryBusinessID = :businessID + SELECT ID FROM TaskCategories + WHERE ID = :id AND BusinessID = :businessID ", { id: { value: categoryID, cfsqltype: "cf_sql_integer" }, businessID: { value: businessID, cfsqltype: "cf_sql_integer" } @@ -65,7 +65,7 @@ try { // Check if any tasks use this category qTasks = queryExecute(" SELECT COUNT(*) as cnt FROM Tasks - WHERE TaskCategoryID = :id + WHERE CategoryID = :id ", { id: { value: categoryID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); @@ -73,8 +73,8 @@ try { if (qTasks.cnt > 0) { // Soft delete - just deactivate queryExecute(" - UPDATE TaskCategories SET TaskCategoryIsActive = 0 - WHERE TaskCategoryID = :id + UPDATE TaskCategories SET IsActive = 0 + WHERE ID = :id ", { id: { value: categoryID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); @@ -86,7 +86,7 @@ try { } else { // Hard delete - no tasks use it queryExecute(" - DELETE FROM TaskCategories WHERE TaskCategoryID = :id + DELETE FROM TaskCategories WHERE ID = :id ", { id: { value: categoryID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); diff --git a/api/tasks/deleteType.cfm b/api/tasks/deleteType.cfm index 69218a7..2ba1bbe 100644 --- a/api/tasks/deleteType.cfm +++ b/api/tasks/deleteType.cfm @@ -46,7 +46,7 @@ try { // Verify task type exists and belongs to this business qCheck = queryExecute(" - SELECT tt_TaskTypeID, tt_TaskTypeBusinessID + SELECT tt_TaskTypeID, BusinessID FROM tt_TaskTypes WHERE tt_TaskTypeID = :taskTypeID ", { @@ -57,7 +57,7 @@ try { apiAbort({ "OK": false, "ERROR": "not_found", "MESSAGE": "Task type not found" }); } - if (isNull(qCheck.tt_TaskTypeBusinessID) || qCheck.tt_TaskTypeBusinessID != businessID) { + if (isNull(qCheck.BusinessID) || qCheck.BusinessID != businessID) { apiAbort({ "OK": false, "ERROR": "not_authorized", "MESSAGE": "Task type does not belong to this business" }); } @@ -65,7 +65,7 @@ try { queryExecute(" DELETE FROM tt_TaskTypes WHERE tt_TaskTypeID = :taskTypeID - AND tt_TaskTypeBusinessID = :businessID + AND BusinessID = :businessID ", { taskTypeID: { value: taskTypeID, cfsqltype: "cf_sql_integer" }, businessID: { value: businessID, cfsqltype: "cf_sql_integer" } diff --git a/api/tasks/expireStaleChats.cfm b/api/tasks/expireStaleChats.cfm index fe9c637..b2d8737 100644 --- a/api/tasks/expireStaleChats.cfm +++ b/api/tasks/expireStaleChats.cfm @@ -16,16 +16,16 @@ try { // Find open chat tasks that are stale // A chat is stale if: // 1. TaskTypeID = 2 (Chat) - // 2. TaskCompletedOn IS NULL (not closed) + // 2. CompletedOn IS NULL (not closed) // 3. No messages in the last 20 minutes AND task is older than 20 minutes staleChats = queryExecute(" - SELECT t.TaskID, t.TaskAddedOn, - (SELECT MAX(cm.CreatedOn) FROM ChatMessages cm WHERE cm.TaskID = t.TaskID) as LastMessageOn + SELECT t.ID, t.CreatedOn, + (SELECT MAX(cm.CreatedOn) FROM ChatMessages cm WHERE cm.TaskID = t.ID) as LastMessageOn FROM Tasks t WHERE t.TaskTypeID = 2 - AND t.TaskCompletedOn IS NULL - AND t.TaskAddedOn < DATE_SUB(NOW(), INTERVAL 20 MINUTE) + AND t.CompletedOn IS NULL + AND t.CreatedOn < DATE_SUB(NOW(), INTERVAL 20 MINUTE) ", {}, { datasource: "payfrit" }); expiredCount = 0; @@ -48,12 +48,12 @@ try { if (shouldExpire) { queryExecute(" - UPDATE Tasks SET TaskCompletedOn = NOW() + UPDATE Tasks SET CompletedOn = NOW() WHERE TaskID = :taskID - ", { taskID: { value: chat.TaskID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); + ", { taskID: { value: chat.ID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); expiredCount++; - arrayAppend(expiredIds, chat.TaskID); + arrayAppend(expiredIds, chat.ID); } } diff --git a/api/tasks/getDetails.cfm b/api/tasks/getDetails.cfm index a35c34c..567d619 100644 --- a/api/tasks/getDetails.cfm +++ b/api/tasks/getDetails.cfm @@ -37,35 +37,35 @@ @@ -73,9 +73,9 @@ - - - + + + @@ -95,44 +95,44 @@ - + + ", [ { value = qTask.ServicePointID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })> - + @@ -140,34 +140,34 @@ diff --git a/api/tasks/listAllTypes.cfm b/api/tasks/listAllTypes.cfm index a1c7138..602a385 100644 --- a/api/tasks/listAllTypes.cfm +++ b/api/tasks/listAllTypes.cfm @@ -46,15 +46,15 @@ try { q = queryExecute(" SELECT tt_TaskTypeID as TaskTypeID, - tt_TaskTypeName as TaskTypeName, - tt_TaskTypeDescription as TaskTypeDescription, - tt_TaskTypeIcon as TaskTypeIcon, - tt_TaskTypeColor as TaskTypeColor, - tt_TaskTypeSortOrder as SortOrder, - tt_TaskTypeCategoryID as CategoryID + Name as TaskTypeName, + Description as TaskTypeDescription, + Icon as TaskTypeIcon, + Color as TaskTypeColor, + SortOrder as SortOrder, + TaskCategoryID as CategoryID FROM tt_TaskTypes - WHERE tt_TaskTypeBusinessID = :businessID - ORDER BY tt_TaskTypeSortOrder, tt_TaskTypeID + WHERE BusinessID = :businessID + ORDER BY SortOrder, tt_TaskTypeID ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); diff --git a/api/tasks/listCategories.cfm b/api/tasks/listCategories.cfm index 04f58d9..1bd0c27 100644 --- a/api/tasks/listCategories.cfm +++ b/api/tasks/listCategories.cfm @@ -48,13 +48,13 @@ try { // Get Task Categories (separate from Services/Task Types) qCategories = queryExecute(" SELECT - TaskCategoryID, - TaskCategoryName, - TaskCategoryColor + ID, + Name, + Color FROM TaskCategories - WHERE TaskCategoryBusinessID = :businessID - AND TaskCategoryIsActive = 1 - ORDER BY TaskCategoryName + WHERE BusinessID = :businessID + AND IsActive = 1 + ORDER BY Name ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); @@ -62,9 +62,9 @@ try { categories = []; for (row in qCategories) { arrayAppend(categories, { - "TaskCategoryID": row.TaskCategoryID, - "TaskCategoryName": row.TaskCategoryName, - "TaskCategoryColor": row.TaskCategoryColor + "TaskCategoryID": row.ID, + "Name": row.Name, + "Color": row.Color }); } diff --git a/api/tasks/listMine.cfm b/api/tasks/listMine.cfm index 03d0176..e71a5d8 100644 --- a/api/tasks/listMine.cfm +++ b/api/tasks/listMine.cfm @@ -37,28 +37,28 @@ - + - + - + - + - + - = DATE_SUB(CURDATE(), INTERVAL 7 DAY)")> + = DATE_SUB(CURDATE(), INTERVAL 7 DAY)")> @@ -66,29 +66,29 @@ @@ -96,35 +96,35 @@ - - - - + + + + - + - - + + - + - + - + @@ -56,25 +56,25 @@ @@ -82,29 +82,29 @@ - - - - + + + + - + - + 0) { // UPDATE existing category qCheck = queryExecute(" - SELECT TaskCategoryID FROM TaskCategories - WHERE TaskCategoryID = :id AND TaskCategoryBusinessID = :businessID + SELECT ID FROM TaskCategories + WHERE ID = :id AND BusinessID = :businessID ", { id: { value: categoryID, cfsqltype: "cf_sql_integer" }, businessID: { value: businessID, cfsqltype: "cf_sql_integer" } @@ -79,9 +79,9 @@ try { queryExecute(" UPDATE TaskCategories SET - TaskCategoryName = :name, - TaskCategoryColor = :color - WHERE TaskCategoryID = :id + Name = :name, + Color = :color + WHERE ID = :id ", { name: { value: categoryName, cfsqltype: "cf_sql_varchar" }, color: { value: categoryColor, cfsqltype: "cf_sql_varchar" }, @@ -97,7 +97,7 @@ try { } else { // INSERT new category queryExecute(" - INSERT INTO TaskCategories (TaskCategoryBusinessID, TaskCategoryName, TaskCategoryColor) + INSERT INTO TaskCategories (BusinessID, Name, Color) VALUES (:businessID, :name, :color) ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" }, diff --git a/api/tasks/saveType.cfm b/api/tasks/saveType.cfm index 56c4853..75e9aa2 100644 --- a/api/tasks/saveType.cfm +++ b/api/tasks/saveType.cfm @@ -97,7 +97,7 @@ try { qCheck = queryExecute(" SELECT tt_TaskTypeID FROM tt_TaskTypes WHERE tt_TaskTypeID = :taskTypeID - AND tt_TaskTypeBusinessID = :businessID + AND BusinessID = :businessID ", { taskTypeID: { value: taskTypeID, cfsqltype: "cf_sql_integer" }, businessID: { value: businessID, cfsqltype: "cf_sql_integer" } @@ -109,11 +109,11 @@ try { queryExecute(" UPDATE tt_TaskTypes - SET tt_TaskTypeName = :taskTypeName, - tt_TaskTypeDescription = :taskTypeDescription, - tt_TaskTypeIcon = :taskTypeIcon, - tt_TaskTypeColor = :taskTypeColor, - tt_TaskTypeCategoryID = :categoryID + SET Name = :taskTypeName, + Description = :taskTypeDescription, + Icon = :taskTypeIcon, + Color = :taskTypeColor, + TaskCategoryID = :categoryID WHERE tt_TaskTypeID = :taskTypeID ", { taskTypeName: { value: taskTypeName, cfsqltype: "cf_sql_varchar" }, @@ -132,7 +132,7 @@ try { } else { // INSERT new task type queryExecute(" - INSERT INTO tt_TaskTypes (tt_TaskTypeName, tt_TaskTypeDescription, tt_TaskTypeIcon, tt_TaskTypeColor, tt_TaskTypeBusinessID, tt_TaskTypeCategoryID) + INSERT INTO tt_TaskTypes (Name, Description, Icon, Color, BusinessID, TaskCategoryID) VALUES (:taskTypeName, :taskTypeDescription, :taskTypeIcon, :taskTypeColor, :businessID, :categoryID) ", { taskTypeName: { value: taskTypeName, cfsqltype: "cf_sql_varchar" }, diff --git a/api/tasks/seedCategories.cfm b/api/tasks/seedCategories.cfm index 09d9b30..b48f60b 100644 --- a/api/tasks/seedCategories.cfm +++ b/api/tasks/seedCategories.cfm @@ -47,7 +47,7 @@ try { // Check if categories already exist qCheck = queryExecute(" SELECT COUNT(*) AS cnt FROM TaskCategories - WHERE TaskCategoryBusinessID = :businessID + WHERE BusinessID = :businessID ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); @@ -55,10 +55,10 @@ try { if (qCheck.cnt > 0) { // Categories already exist, just return them qCategories = queryExecute(" - SELECT TaskCategoryID, TaskCategoryName, TaskCategoryColor + SELECT ID, Name, Color FROM TaskCategories - WHERE TaskCategoryBusinessID = :businessID AND TaskCategoryIsActive = 1 - ORDER BY TaskCategoryName + WHERE BusinessID = :businessID AND IsActive = 1 + ORDER BY Name ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); @@ -66,9 +66,9 @@ try { categories = []; for (row in qCategories) { arrayAppend(categories, { - "TaskCategoryID": row.TaskCategoryID, - "TaskCategoryName": row.TaskCategoryName, - "TaskCategoryColor": row.TaskCategoryColor + "TaskCategoryID": row.ID, + "Name": row.Name, + "Color": row.Color }); } @@ -93,7 +93,7 @@ try { // Insert defaults for (cat in defaults) { queryExecute(" - INSERT INTO TaskCategories (TaskCategoryBusinessID, TaskCategoryName, TaskCategoryColor) + INSERT INTO TaskCategories (BusinessID, Name, Color) VALUES (:businessID, :name, :color) ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" }, @@ -104,10 +104,10 @@ try { // Return the created categories qCategories = queryExecute(" - SELECT TaskCategoryID, TaskCategoryName, TaskCategoryColor + SELECT ID, Name, Color FROM TaskCategories - WHERE TaskCategoryBusinessID = :businessID AND TaskCategoryIsActive = 1 - ORDER BY TaskCategoryName + WHERE BusinessID = :businessID AND IsActive = 1 + ORDER BY Name ", { businessID: { value: businessID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); @@ -115,9 +115,9 @@ try { categories = []; for (row in qCategories) { arrayAppend(categories, { - "TaskCategoryID": row.TaskCategoryID, - "TaskCategoryName": row.TaskCategoryName, - "TaskCategoryColor": row.TaskCategoryColor + "TaskCategoryID": row.ID, + "Name": row.Name, + "Color": row.Color }); } diff --git a/api/tasks/setup.cfm b/api/tasks/setup.cfm index 7142665..e623fb6 100644 --- a/api/tasks/setup.cfm +++ b/api/tasks/setup.cfm @@ -4,22 +4,22 @@ - + - + = 4) { - maskedPhone = "***-***-" & right(user.UserPhone, 4); + if (len(trim(user.ContactNumber)) >= 4) { + maskedPhone = "***-***-" & right(user.ContactNumber, 4); } arrayAppend(users, { "UserID": user.UserID, - "Name": trim(user.UserFirstName & " " & user.UserLastName), - "Email": user.UserEmail, + "Name": trim(user.FirstName & " " & user.LastName), + "Email": user.EmailAddress, "Phone": maskedPhone, "AvatarUrl": len(trim(user.UserAvatarPath)) ? "https://biz.payfrit.com/uploads/" & user.UserAvatarPath : "" }); diff --git a/api/workers/createAccount.cfm b/api/workers/createAccount.cfm new file mode 100644 index 0000000..2d9d7ba --- /dev/null +++ b/api/workers/createAccount.cfm @@ -0,0 +1,94 @@ + + + + + +/** + * Create or reuse Stripe Connect Express account for worker. + */ + +response = { "OK": false }; + +try { + requestData = deserializeJSON(toString(getHttpRequestData().content)); + userID = val(requestData.UserID ?: 0); + + if (userID == 0 && structKeyExists(request, "UserID")) { + userID = val(request.UserID); + } + + if (userID == 0) { + response["ERROR"] = "missing_params"; + response["MESSAGE"] = "UserID is required."; + writeOutput(serializeJSON(response)); + abort; + } + + qUser = queryExecute(" + SELECT StripeConnectedAccountID, EmailAddress, FirstName, LastName + FROM Users WHERE ID = :userID + ", { userID: userID }, { datasource: "payfrit" }); + + if (qUser.recordCount == 0) { + response["ERROR"] = "user_not_found"; + writeOutput(serializeJSON(response)); + abort; + } + + existingAccountID = qUser.StripeConnectedAccountID ?: ""; + + if (len(trim(existingAccountID)) > 0) { + // Already has an account + response["OK"] = true; + response["ACCOUNT_ID"] = existingAccountID; + response["CREATED"] = false; + writeOutput(serializeJSON(response)); + abort; + } + + // Create new Stripe Connect Express account + stripeSecretKey = application.stripeSecretKey ?: ""; + + httpService = new http(); + httpService.setMethod("POST"); + httpService.setUrl("https://api.stripe.com/v1/accounts"); + httpService.setUsername(stripeSecretKey); + httpService.setPassword(""); + + httpService.addParam(type="formfield", name="type", value="express"); + httpService.addParam(type="formfield", name="country", value="US"); + + userEmail = qUser.EmailAddress ?: ""; + if (len(trim(userEmail)) > 0) { + httpService.addParam(type="formfield", name="email", value=userEmail); + } + + httpService.addParam(type="formfield", name="capabilities[transfers][requested]", value="true"); + httpService.addParam(type="formfield", name="metadata[user_id]", value=userID); + + result = httpService.send().getPrefix(); + acctData = deserializeJSON(result.fileContent); + + if (structKeyExists(acctData, "error")) { + response["ERROR"] = acctData.error.message; + writeOutput(serializeJSON(response)); + abort; + } + + newAccountID = acctData.id; + + // Save to Users table + queryExecute(" + UPDATE Users SET StripeConnectedAccountID = :acctID WHERE ID = :userID + ", { acctID: newAccountID, userID: userID }, { datasource: "payfrit" }); + + response["OK"] = true; + response["ACCOUNT_ID"] = newAccountID; + response["CREATED"] = true; + +} catch (any e) { + response["ERROR"] = e.message; +} + +writeOutput(serializeJSON(response)); + diff --git a/api/workers/earlyUnlock.cfm b/api/workers/earlyUnlock.cfm new file mode 100644 index 0000000..41cd975 --- /dev/null +++ b/api/workers/earlyUnlock.cfm @@ -0,0 +1,85 @@ + + + + + +/** + * Create Stripe Checkout Session for activation early unlock. + * Worker pays remaining activation balance via card. + */ + +response = { "OK": false }; + +try { + requestData = deserializeJSON(toString(getHttpRequestData().content)); + userID = val(requestData.UserID ?: 0); + + if (userID == 0 && structKeyExists(request, "UserID")) { + userID = val(request.UserID); + } + + if (userID == 0) { + response["ERROR"] = "missing_params"; + response["MESSAGE"] = "UserID is required."; + writeOutput(serializeJSON(response)); + abort; + } + + qUser = queryExecute(" + SELECT ActivationBalanceCents, ActivationCapCents + FROM Users WHERE ID = :userID + ", { userID: userID }, { datasource: "payfrit" }); + + if (qUser.recordCount == 0) { + response["ERROR"] = "user_not_found"; + writeOutput(serializeJSON(response)); + abort; + } + + remainingCents = val(qUser.ActivationCapCents) - val(qUser.ActivationBalanceCents); + + if (remainingCents <= 0) { + response["OK"] = true; + response["ALREADY_COMPLETE"] = true; + writeOutput(serializeJSON(response)); + abort; + } + + // Create Stripe Checkout Session + stripeSecretKey = application.stripeSecretKey ?: ""; + + httpService = new http(); + httpService.setMethod("POST"); + httpService.setUrl("https://api.stripe.com/v1/checkout/sessions"); + httpService.setUsername(stripeSecretKey); + httpService.setPassword(""); + + httpService.addParam(type="formfield", name="mode", value="payment"); + httpService.addParam(type="formfield", name="line_items[0][price_data][unit_amount]", value=remainingCents); + httpService.addParam(type="formfield", name="line_items[0][price_data][currency]", value="usd"); + httpService.addParam(type="formfield", name="line_items[0][price_data][product_data][name]", value="Payfrit Activation"); + httpService.addParam(type="formfield", name="line_items[0][quantity]", value="1"); + httpService.addParam(type="formfield", name="success_url", value="https://biz.payfrit.com/works/activation?success=1"); + httpService.addParam(type="formfield", name="cancel_url", value="https://biz.payfrit.com/works/activation?cancel=1"); + httpService.addParam(type="formfield", name="metadata[user_id]", value=userID); + httpService.addParam(type="formfield", name="metadata[type]", value="activation_unlock"); + + result = httpService.send().getPrefix(); + sessionData = deserializeJSON(result.fileContent); + + if (structKeyExists(sessionData, "error")) { + response["ERROR"] = sessionData.error.message; + writeOutput(serializeJSON(response)); + abort; + } + + response["OK"] = true; + response["CHECKOUT_URL"] = sessionData.url; + response["AMOUNT_DUE_CENTS"] = remainingCents; + +} catch (any e) { + response["ERROR"] = e.message; +} + +writeOutput(serializeJSON(response)); + diff --git a/api/workers/ledger.cfm b/api/workers/ledger.cfm new file mode 100644 index 0000000..6dbc153 --- /dev/null +++ b/api/workers/ledger.cfm @@ -0,0 +1,72 @@ + + + + + +/** + * Read-only worker earnings/payout ledger. + */ + +response = { "OK": false }; + +try { + requestData = deserializeJSON(toString(getHttpRequestData().content)); + userID = val(requestData.UserID ?: 0); + + if (userID == 0 && structKeyExists(request, "UserID")) { + userID = val(request.UserID); + } + + if (userID == 0) { + response["ERROR"] = "missing_params"; + response["MESSAGE"] = "UserID is required."; + writeOutput(serializeJSON(response)); + abort; + } + + // Get ledger entries (most recent first) + qLedger = queryExecute(" + SELECT TaskID, GrossEarningsCents, ActivationWithheldCents, + NetTransferCents, Status, CreatedAt + FROM WorkPayoutLedgers + WHERE UserID = :userID + ORDER BY CreatedAt DESC + LIMIT 100 + ", { userID: userID }, { datasource: "payfrit" }); + + // Get totals + qTotals = queryExecute(" + SELECT + COALESCE(SUM(GrossEarningsCents), 0) AS TotalGrossCents, + COALESCE(SUM(ActivationWithheldCents), 0) AS TotalWithheldCents, + COALESCE(SUM(CASE WHEN Status = 'transferred' THEN NetTransferCents ELSE 0 END), 0) AS TotalTransferredCents + FROM WorkPayoutLedgers + WHERE UserID = :userID + ", { userID: userID }, { datasource: "payfrit" }); + + ledgerEntries = []; + for (row in qLedger) { + arrayAppend(ledgerEntries, { + "TaskID": row.TaskID, + "GrossEarningsCents": row.GrossEarningsCents, + "ActivationWithheldCents": row.ActivationWithheldCents, + "NetTransferCents": row.NetTransferCents, + "Status": row.Status, + "CreatedAt": dateTimeFormat(row.CreatedAt, "yyyy-MM-dd'T'HH:nn:ss") + }); + } + + response["OK"] = true; + response["LEDGER"] = ledgerEntries; + response["TOTALS"] = { + "TotalGrossCents": val(qTotals.TotalGrossCents), + "TotalWithheldCents": val(qTotals.TotalWithheldCents), + "TotalTransferredCents": val(qTotals.TotalTransferredCents) + }; + +} catch (any e) { + response["ERROR"] = e.message; +} + +writeOutput(serializeJSON(response)); + diff --git a/api/workers/myBusinesses.cfm b/api/workers/myBusinesses.cfm index 1915381..0bda0a5 100644 --- a/api/workers/myBusinesses.cfm +++ b/api/workers/myBusinesses.cfm @@ -36,17 +36,17 @@ @@ -54,11 +54,11 @@ diff --git a/api/workers/onboardingLink.cfm b/api/workers/onboardingLink.cfm new file mode 100644 index 0000000..7ca0b91 --- /dev/null +++ b/api/workers/onboardingLink.cfm @@ -0,0 +1,77 @@ + + + + + +/** + * Generate Stripe-hosted onboarding link for worker's connected account. + */ + +response = { "OK": false }; + +try { + requestData = deserializeJSON(toString(getHttpRequestData().content)); + userID = val(requestData.UserID ?: 0); + + if (userID == 0 && structKeyExists(request, "UserID")) { + userID = val(request.UserID); + } + + if (userID == 0) { + response["ERROR"] = "missing_params"; + response["MESSAGE"] = "UserID is required."; + writeOutput(serializeJSON(response)); + abort; + } + + qUser = queryExecute(" + SELECT StripeConnectedAccountID FROM Users WHERE ID = :userID + ", { userID: userID }, { datasource: "payfrit" }); + + if (qUser.recordCount == 0) { + response["ERROR"] = "user_not_found"; + writeOutput(serializeJSON(response)); + abort; + } + + accountID = qUser.StripeConnectedAccountID ?: ""; + + if (len(trim(accountID)) == 0) { + response["ERROR"] = "no_stripe_account"; + response["MESSAGE"] = "Create a Stripe account first."; + writeOutput(serializeJSON(response)); + abort; + } + + // Create Account Link for onboarding + stripeSecretKey = application.stripeSecretKey ?: ""; + + httpService = new http(); + httpService.setMethod("POST"); + httpService.setUrl("https://api.stripe.com/v1/account_links"); + httpService.setUsername(stripeSecretKey); + httpService.setPassword(""); + + httpService.addParam(type="formfield", name="account", value=accountID); + httpService.addParam(type="formfield", name="refresh_url", value="https://biz.payfrit.com/works/tier?refresh=1"); + httpService.addParam(type="formfield", name="return_url", value="https://biz.payfrit.com/works/tier?return=1"); + httpService.addParam(type="formfield", name="type", value="account_onboarding"); + + result = httpService.send().getPrefix(); + linkData = deserializeJSON(result.fileContent); + + if (structKeyExists(linkData, "error")) { + response["ERROR"] = linkData.error.message; + writeOutput(serializeJSON(response)); + abort; + } + + response["OK"] = true; + response["ONBOARDING_URL"] = linkData.url; + +} catch (any e) { + response["ERROR"] = e.message; +} + +writeOutput(serializeJSON(response)); + diff --git a/api/workers/tierStatus.cfm b/api/workers/tierStatus.cfm new file mode 100644 index 0000000..6756097 --- /dev/null +++ b/api/workers/tierStatus.cfm @@ -0,0 +1,72 @@ + + + + + +/** + * Worker Tier + Activation Status + * Returns cached DB state. No Stripe polling. + * Tier is derived: payoutsEnabled ? 1 : 0 + */ + +response = { "OK": false }; + +try { + requestData = deserializeJSON(toString(getHttpRequestData().content)); + userID = val(requestData.UserID ?: 0); + + // Fallback to auth header + if (userID == 0 && structKeyExists(request, "UserID")) { + userID = val(request.UserID); + } + + if (userID == 0) { + response["ERROR"] = "missing_params"; + response["MESSAGE"] = "UserID is required."; + writeOutput(serializeJSON(response)); + abort; + } + + qUser = queryExecute(" + SELECT StripeConnectedAccountID, StripePayoutsEnabled, + ActivationBalanceCents, ActivationCapCents + FROM Users WHERE ID = :userID + ", { userID: userID }, { datasource: "payfrit" }); + + if (qUser.recordCount == 0) { + response["ERROR"] = "user_not_found"; + writeOutput(serializeJSON(response)); + abort; + } + + payoutsEnabled = qUser.StripePayoutsEnabled == 1; + hasAccount = len(trim(qUser.StripeConnectedAccountID ?: "")) > 0; + balanceCents = val(qUser.ActivationBalanceCents); + capCents = val(qUser.ActivationCapCents); + remainingCents = capCents - balanceCents; + if (remainingCents < 0) remainingCents = 0; + isComplete = (remainingCents == 0); + progressPercent = capCents > 0 ? round((balanceCents / capCents) * 100) : 100; + if (progressPercent > 100) progressPercent = 100; + + response["OK"] = true; + response["TIER"] = payoutsEnabled ? 1 : 0; + response["STRIPE"] = { + "HasAccount": hasAccount, + "PayoutsEnabled": payoutsEnabled, + "SetupIncomplete": hasAccount && !payoutsEnabled + }; + response["ACTIVATION"] = { + "BalanceCents": balanceCents, + "CapCents": capCents, + "RemainingCents": remainingCents, + "IsComplete": isComplete, + "ProgressPercent": progressPercent + }; + +} catch (any e) { + response["ERROR"] = e.message; +} + +writeOutput(serializeJSON(response)); + diff --git a/confirm.cfm b/confirm.cfm index fe32e31..7fc8b23 100644 --- a/confirm.cfm +++ b/confirm.cfm @@ -6,11 +6,11 @@ - SELECT UserID + SELECT ID FROM Users - WHERE UserUUID = '#url.UUID#' + WHERE UUID = '#url.UUID#' AND - UserIsEmailVerified = 0 + IsEmailVerified = 0 @@ -18,14 +18,14 @@ UPDATE Users SET IsEmailVerified = 1 - WHERE UserID = '#get_user.UserID#' + WHERE UserID = '#get_user.ID#' - + @@ -47,9 +47,9 @@ - SELECT UserID + SELECT ID FROM Users - WHERE UserUUID = '#url.UUID#' + WHERE UUID = '#url.UUID#' AND IsEmailVerified = 1 diff --git a/confirm_email.cfm b/confirm_email.cfm index e5f281a..896421e 100644 --- a/confirm_email.cfm +++ b/confirm_email.cfm @@ -6,28 +6,27 @@ - SELECT UserID, UserEmailAddress - FROM Users - WHERE UserUUID = '#url.UUID#' + ID AS UserID + WHERE UUID = '#url.UUID#' AND - UserIsEmailVerified = 0 + IsEmailVerified = 0 AND - UserIsContactVerified > 0 + IsContactVerified > 0 UPDATE Users - SET UserIsEmailVerified = 1 - WHERE UserID = '#get_user.UserID#' + SET IsEmailVerified = 1 + WHERE UserID = '#get_user.ID#' - + @@ -35,7 +34,7 @@ @@ -49,20 +48,19 @@ - SELECT UserID, UserContactNumber - FROM Users - WHERE UserUUID = '#url.UUID#' + ID AS UserID + WHERE UUID = '#url.UUID#' AND - UserIsEmailVerified = 0 + IsEmailVerified = 0 AND - UserIsContactVerified = 0 + IsContactVerified = 0 UPDATE Users - SET UserIsEmailVerified = 1 + SET IsEmailVerified = 1 WHERE UserID = '#get_confirmed_customer.UserID#' @@ -72,11 +70,11 @@ UPDATE Users - SET UserMobileVerifyCode = '#customer_OPT_confirm#' + SET MobileVerifyCode = '#customer_OPT_confirm#' WHERE UserID = #get_confirmed_customer.UserID# - we sent a six-digit code to #get_confirmed_customer.UserContactNumber#, please input that code here:

+ we sent a six-digit code to #get_confirmed_customer.ContactNumber#, please input that code here:

-
+ - ack order + ack order - +
- SELECT I.ItemName, OL.OrderLineItemQuantity, OL.OrderLineItemRemark, O.OrderAddedOn, OL.OrderLineItemID, O.OrderID, O.OrderRemarks, C.CategoryName + SELECT I.Name, OL.Quantity, OL.Remark, O.AddedOn, OL.ID, O.ID, O.Remarks, C.Name FROM Orders O, OrderLineItems OL, Items I, Categories C - WHERE O.OrderStatusID = 1 + WHERE O.StatusID = 1 AND - OL.OrderLineItemItemID = I.ItemID + OL.ItemID = I.ID AND - OL.OrderLineItemIsDeleted = 0 + OL.IsDeleted = 0 AND - OL.OrderLineItemParentOrderLineItemID = 0 + OL.ParentOrderLineItemID = 0 AND - I.ItemCategoryID = C.CategoryID + I.CategoryID = C.ID AND - O.OrderID = #get_orders.OrderID# + O.ID = #get_orders.ID# AND - O.OrderID = OL.OrderLineItemOrderID + O.ID = OL.OrderID -
+
- ORDER ON: #dateformat(get_line_items.OrderAddedOn,"YYYY-MM-DD")# @ #timeformat(get_line_items.OrderAddedOn,"HH:NN:SS")#
- (#get_line_items.OrderLineItemQuantity#) #CategoryName# : #get_line_items.ItemName#
- ORDER NOTES: #get_line_items.OrderRemarks#
+ ORDER ON: #dateformat(get_line_items.AddedOn,"YYYY-MM-DD")# @ #timeformat(get_line_items.AddedOn,"HH:NN:SS")#
+ (#get_line_items.Quantity#) #Name# : #get_line_items.Name#
+ ORDER NOTES: #get_line_items.Remarks#
- SELECT I.ItemName, I.ItemID, I.ItemPrice, I.ItemParentItemID, O.OrderLineItemParentOrderLineItemID, O.OrderLineItemRemark + SELECT I.Name, I.ID, I.Price, I.ParentItemID, O.ParentOrderLineItemID, O.Remark FROM OrderLineItems O, Items I - WHERE OrderLineItemOrderID = #get_line_items.OrderID# + WHERE OrderID = #get_line_items.OrderID# AND - O.OrderLineItemItemID = I.ItemID + O.ItemID = I.ID AND - OrderLineItemParentOrderLineItemID = #get_line_items.OrderLineItemID# - ORDER BY OrderLineItemAddedOn DESC + ParentOrderLineItemID = #get_line_items.OrderLineItemID# + ORDER BY AddedOn DESC - SELECT ItemName + SELECT Name FROM Items - WHERE ItemID = #get_child_line_items.ItemParentItemID# + WHERE ID = #get_child_line_items.ParentItemID# -   #get_parent_item_Name.ItemName# : #get_child_line_items.ItemName#
-   ITEM NOTES: #get_line_items.OrderLineItemRemark# +   #get_parent_item_Name.Name# : #get_child_line_items.Name#
+   ITEM NOTES: #get_line_items.Remark#
@@ -213,57 +213,57 @@ Kitchen items being prepared:
- SELECT O.OrderID + SELECT O.ID FROM Orders O, Businesses B - WHERE O.OrderStatusID = 2 + WHERE O.StatusID = 2 AND - O.OrderBusinessID = B.BusinessID + O.BusinessID = B.ID AND - B.BusinessID = #request.BusinessID# - ORDER BY O.OrderAddedOn ASC + B.ID = #request.BusinessID# + ORDER BY O.AddedOn ASC
-
+
-
+ - ready order + ready order - +
- SELECT I.ItemName, OL.OrderLineItemQuantity, O.OrderAddedOn, OL.OrderLineItemID + SELECT I.Name, OL.Quantity, O.AddedOn, OL.ID FROM Orders O, OrderLineItems OL, Items I - WHERE O.OrderStatusID = 2 + WHERE O.StatusID = 2 AND - OL.OrderLineItemStatusID = 2 + OL.StatusID = 2 AND - OL.OrderLineItemItemID = I.ItemID + OL.ItemID = I.ID AND - OL.OrderLineItemIsDeleted = 0 + OL.IsDeleted = 0 AND - O.OrderID = #get_orders.OrderID# + O.ID = #get_orders.ID# AND - O.OrderID = OL.OrderLineItemOrderID + O.ID = OL.OrderID -
+
-
(#get_line_items.OrderLineItemQuantity#) #get_line_items.ItemName# #dateformat(get_line_items.OrderAddedOn,"YYYY-MM-DD")# @ #timeformat(get_line_items.OrderAddedOn,"HH:NN:SS")# +
(#get_line_items.Quantity#) #get_line_items.Name# #dateformat(get_line_items.AddedOn,"YYYY-MM-DD")# @ #timeformat(get_line_items.AddedOn,"HH:NN:SS")# -
+ - Become + Become - +
@@ -479,12 +479,12 @@ - SELECT B.BusinessName + SELECT B.Name FROM Businesses B - WHERE B.BusinessID = #request.BusinessID# + WHERE B.ID = #request.BusinessID# - You are logged in as

#get_biz_name.BusinessName#

+ You are logged in as

#get_biz_name.Name#

@@ -494,28 +494,28 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + - SELECT B.*, A.Addressline1, A.Addressline2, A.AddressCity, A.AddressStateID, A.AddressZIPCode + SELECT B.*, A.Addressline1, A.Addressline2, A.City, A.StateID, A.ZIPCode FROM Businesses B, Addresses A - WHERE B.BusinessID = #request.BusinessID# + WHERE B.ID = #request.BusinessID# AND - A.AddressBusinessID = B.BusinessID + A.BusinessID = B.ID AND A.AddressTypeID = 2 @@ -524,19 +524,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -546,32 +546,32 @@ - + - + - + - + - + - + @@ -598,7 +598,7 @@ Business Name: - + @@ -606,7 +606,7 @@ Address Line 1: - + @@ -614,7 +614,7 @@ Address Line 2: - + @@ -622,11 +622,11 @@ City: - + - SELECT tt_StateID, tt_StateName + SELECT tt_StateID, Name FROM tt_States WHERE tt_StateCountryID = 1 ORDER BY tt_StateSortOrder @@ -636,10 +636,10 @@ Select State: - - >#tt_StateName# + >#Name# @@ -649,7 +649,7 @@ ZIP Code: - + @@ -657,7 +657,7 @@ Sales Tax Rate: - % + % @@ -679,7 +679,7 @@ Hiring? - checked> + checked> @@ -687,7 +687,7 @@ Business Radius: - mi + mi @@ -695,7 +695,7 @@ Business Delivery ZIP Codes: - + @@ -703,7 +703,7 @@ Demo Mode? - checked> + checked> @@ -711,7 +711,7 @@ Private? - checked> + checked> @@ -734,8 +734,8 @@
- -
+ +
-
+ - Edit + Edit - - + +
@@ -1957,19 +1957,19 @@ -
+ - Inactivate + Inactivate - +
@@ -1985,25 +1985,25 @@ - #ItemName# + #Name# -
+ - Edit + Edit - - + +
@@ -2011,19 +2011,19 @@ -
+ - Activate + Activate - +
@@ -2068,44 +2068,44 @@ - + - - - - - - - - - - - - + + + + + + + + + + + + SELECT * FROM Items - WHERE ItemID = #form.ItemID# + WHERE ID = #form.ItemID# - - - - - - - - - - - + + + + + + + + + + + @@ -2115,17 +2115,17 @@ - + - + - @@ -2142,7 +2142,7 @@ - Add Edit Item

+ Add Edit Item

@@ -2152,25 +2152,25 @@ Item Name: - + - + - SELECT CategoryID, CategoryName + SELECT ID, Name FROM Categories - WHERE CategoryBusinessID = #request.BusinessID# - ORDER BY CategorySortOrder + WHERE BusinessID = #request.BusinessID# + ORDER BY SortOrder Select Category: - - >#get_categories.CategoryName# + >#get_categories.Name# @@ -2181,7 +2181,7 @@ Item Description: - + @@ -2189,7 +2189,7 @@ Item Price: - + @@ -2198,7 +2198,7 @@ Item Is Active? - checked tabindex="5"> + checked tabindex="5"> @@ -2206,7 +2206,7 @@ Item Is Checked By Default? - checked> + checked> @@ -2214,7 +2214,7 @@ Item requires child selection? - checked tabindex="7"> + checked tabindex="7"> @@ -2223,14 +2223,14 @@ - - - - - - - + + + + + + @@ -2240,7 +2240,7 @@ Item children are collapsed? - checked tabindex="9"> + checked tabindex="9"> @@ -2248,7 +2248,7 @@ Item sort order - + @@ -2256,7 +2256,7 @@ - + @@ -2270,9 +2270,9 @@ - -

-
+ +

+
-      +      - edit + edit - +     -
+ - no coll + no coll - +
    -
+ - delete + delete - +
    -
+ - clone
+ clone
- +
-
+ -      Name: Price: Default? checked> add child here +      Name: Price: Default? checked> add child here - - + +

- +
@@ -3108,96 +3108,96 @@ - #get_items.ItemName# - #dollarformat(get_items.ItemPrice)#
+ #get_items.Name# - #dollarformat(get_items.Price)#
-     
+      - edit + edit - +
    -
+ - no coll + no coll - +
    -
+ - delete + delete - +
    -
+ - clone
+ clone
- +
-
+ -      Name: Price: Default? checked> add child here +      Name: Price: Default? checked> add child here - - + +

- + @@ -3212,12 +3212,12 @@
- Name: Price: Add New Top-Level Item to #get_business_categories.CategoryName# + Name: Price: Add New Top-Level Item to #get_business_categories.Name# - +


@@ -3226,26 +3226,26 @@ - - - + + + INSERT INTO Items ( - ItemName, - ItemPrice, - ItemIsCheckedByDefault, - ItemCategoryID, - ItemParentItemID, - ItemAddedOn + Name, + Price, + IsCheckedByDefault, + CategoryID, + ParentItemID, + AddedOn ) VALUES ( - '#form.ItemName#', - #form.ItemPrice#, - #form.ItemIsCheckedByDefault#, - #form.ItemCategoryID#, + '#form.Name#', + #form.Price#, + #form.IsCheckedByDefault#, + #form.CategoryID#, #form.ParentItemID#, #createODBCDateTime(now())# ) @@ -3268,7 +3268,7 @@ UPDATE Items - SET ItemIsActive = 0 + SET IsActive = 0 WHERE ItemID=#form.ItemID# @@ -3311,22 +3311,22 @@ SELECT U.*, A.* FROM Users U, Addresses A - WHERE U.UserID = #request.UserID# + WHERE U.ID = #request.UserID# AND - A.AddressUserID = U.UserID + A.UserID = U.ID AND A.AddressTypeID = 1 - - - - - - - + + + + + + + @@ -3336,27 +3336,27 @@ - + - + - + - + - + @@ -3400,7 +3400,7 @@ First Name: - + @@ -3408,7 +3408,7 @@ Last Name: - + @@ -3416,7 +3416,7 @@ Address Line 1: - + @@ -3424,7 +3424,7 @@ Address Line 2: - + @@ -3432,11 +3432,11 @@ City: - + - SELECT tt_StateID, tt_StateName + SELECT tt_StateID, Name FROM tt_States WHERE tt_StateCountryID = 1 ORDER BY tt_StateSortOrder @@ -3446,10 +3446,10 @@ Select State: - - >#tt_StateName# + >#Name# @@ -3459,7 +3459,7 @@ ZIP Code: - + @@ -3473,8 +3473,8 @@ - -
+ +
-
+ - + - delete

+ delete

- +

-
+ - Name:Price:add child here + Name:Price:add child here - +
@@ -124,7 +124,7 @@
- Name:
Price:
Add Base Item + Name:
Price:
Add Base Item @@ -138,15 +138,15 @@ INSERT INTO Items ( - ItemName, - ItemPrice, - ItemParentItemID, - ItemAddedOn + Name, + Price, + ParentItemID, + AddedOn ) VALUES ( - '#form.ItemName#', - '#form.ItemPrice#', + '#form.Name#', + '#form.Price#', '#form.chip#', #createODBCDateTime(now())# ) @@ -174,10 +174,10 @@ INSERT INTO Items ( - ItemName, - ItemPrice, - ItemParentItemID, - ItemAddedOn + Name, + Price, + ParentItemID, + AddedOn ) VALUES ( @@ -204,7 +204,7 @@ DELETE FROM Items - WHERE ItemID=#chip# + WHERE ID=#chip# diff --git a/test_infinite.cfm b/test_infinite.cfm index 1665c82..ccb0183 100644 --- a/test_infinite.cfm +++ b/test_infinite.cfm @@ -45,16 +45,16 @@

Current menu

- SELECT ItemName, ItemPrice, ItemID + SELECT Name, Price, ItemID FROM Items - WHERE ItemParentItemID = 0 + WHERE ParentItemID = 0 - #get_items.ItemName# - #dollarformat(get_items.ItemPrice)#
+ #get_items.Name# - #dollarformat(get_items.Price)#
- +
@@ -63,63 +63,63 @@

Edit menu

- SELECT ItemName, ItemPrice, ItemID + SELECT Name, Price, ItemID FROM Items - WHERE ItemParentItemID = 0 + WHERE ParentItemID = 0 - #get_items.ItemName# - #dollarformat(get_items.ItemPrice)# + #get_items.Name# - #dollarformat(get_items.Price)# - + - Edit + Edit - + -
+ - delete
+ delete
- +
-
+ - Name:Price:add here + Name:Price:add here - +

@@ -140,7 +140,7 @@
- Name:Price:Add Main Item + Name:Price:Add Main Item @@ -155,15 +155,15 @@ INSERT INTO Items ( - ItemName, - ItemPrice, - ItemParentItemID, - ItemAddedOn + Name, + Price, + ParentItemID, + AddedOn ) VALUES ( - '#form.ItemName#', - '#form.ItemPrice#', + '#form.Name#', + '#form.Price#', '#form.chip#', #createODBCDateTime(now())# ) @@ -185,7 +185,7 @@ DELETE FROM Items - WHERE ItemID=#chip# + WHERE ID=#chip# diff --git a/yelpforexes.com/Application.cfm b/yelpforexes.com/Application.cfm index 1e27592..37d7c64 100644 --- a/yelpforexes.com/Application.cfm +++ b/yelpforexes.com/Application.cfm @@ -28,9 +28,9 @@ - SELECT UserFirstName, UserBalance, UserProfileImage + SELECT FirstName, Balance, UserProfileImage FROM Users - WHERE UserID = #request.UserID# + WHERE ID = #request.UserID# @@ -363,7 +363,7 @@
- Hi, #check_user.UserFirstName#
#dollarformat(check_user.UserBalance)#YFE User

+ Hi, #check_user.FirstName#
#dollarformat(check_user.Balance)#YFE User

diff --git a/yelpforexes.com/Application.cfm.2020-07-10.bup.cfm b/yelpforexes.com/Application.cfm.2020-07-10.bup.cfm index 3e3b9e9..580db22 100644 --- a/yelpforexes.com/Application.cfm.2020-07-10.bup.cfm +++ b/yelpforexes.com/Application.cfm.2020-07-10.bup.cfm @@ -28,17 +28,17 @@ INSERT INTO VisitorTracking ( - VisitorTrackingPageMode, - VisitorTrackingUserID, - VisitorTrackingCfID, - VisitorTrackingHttpReferer, - VisitorTrackingHttpUserAgent, - VisitorTrackingRequestUrl, - VisitorTrackingLocalIPAddress, - VisitorTrackingRemoteAddress, - VisitorTrackingRemoteHost, - VisitorTrackingRemoteUser, - VisitorTrackingAddedOn + PageMode, + UserID, + CfID, + HttpReferer, + HttpUserAgent, + RequestUrl, + LocalIPAddress, + RemoteAddress, + RemoteHost, + RemoteUser, + AddedOn ) VALUES ( '#form.mode#', @@ -58,9 +58,9 @@ - SELECT UserFirstName + SELECT FirstName FROM Users - WHERE UserID = #request.UserID# + WHERE ID = #request.UserID# @@ -122,7 +122,7 @@ - Hi, #check_user.UserFirstName#Yelp For Exes User + Hi, #check_user.FirstName#Yelp For Exes User diff --git a/yelpforexes.com/UserWasReviewed.cfm b/yelpforexes.com/UserWasReviewed.cfm index 20bf334..1f848fe 100644 --- a/yelpforexes.com/UserWasReviewed.cfm +++ b/yelpforexes.com/UserWasReviewed.cfm @@ -2,7 +2,7 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/yelpforexes.com/_process.cfm b/yelpforexes.com/_process.cfm index be55822..8e556ae 100644 --- a/yelpforexes.com/_process.cfm +++ b/yelpforexes.com/_process.cfm @@ -116,13 +116,13 @@ - SELECT A.CartID, A.AddedOn, A.Quantity, A.SpecialRemark, B.BusinessName, B.UserID, C.ItemName, A.Price, D.UserFirstName, D.LaerFirstName, D.Balance + SELECT A.CartID, A.AddedOn, A.Quantity, A.SpecialRemark, B.Name, B.UserID, C.Name, A.Price, D.FirstName, D.LaerFirstName, D.Balance FROM dbo.Business_CartMaster A, dbo.BusinessMaster B, dbo.Business_ItemMaster C, Users D WHERE A.UserID = D.UserID AND A.ItemID = C.ItemID AND - B.BusinessID = C.BusinessID + B.ID = C.BusinessID AND C.BusinessID = #form.bizid# AND @@ -170,11 +170,11 @@ - SELECT TOP 1 O.OrderID, M.UserID as person_to_pay_for_orderID, U.Balance + SELECT TOP 1 O.ID, M.UserID as person_to_pay_for_orderID, U.Balance FROM dbo.Business_OrderMaster O, dbo.BusinessMaster M, Users U WHERE O.BusinessID = M.BusinessID AND - M.UserID = U.UserID + M.UserID = U.ID ORDER BY O.AddedOn DESC @@ -185,7 +185,7 @@ ) VALUES ( - #get_last_inserted.OrderID#, + #get_last_inserted.ID#, #get_queued_food.CartID# ) @@ -268,7 +268,7 @@ SELECT balance FROM Users - WHERE UserID = 104 + WHERE ID = 104 @@ -346,7 +346,7 @@ SELECT balance FROM Users - WHERE UserID = 104 + WHERE ID = 104 diff --git a/yelpforexes.com/confirm_email.cfm b/yelpforexes.com/confirm_email.cfm index 478cc69..81a4b68 100644 --- a/yelpforexes.com/confirm_email.cfm +++ b/yelpforexes.com/confirm_email.cfm @@ -6,11 +6,10 @@ - SELECT UserID, UserEmailAddress - FROM Users - WHERE UserUUID = '#url.UUID#' + ID AS UserID + WHERE UUID = '#url.UUID#' AND - UserIsEmailVerified = 0 + IsEmailVerified = 0 AND UserIsMobileVerified = 1 @@ -19,15 +18,15 @@ UPDATE Users - SET UserIsEmailVerified = 1 - WHERE UserID = '#get_user.UserID#' + SET IsEmailVerified = 1 + WHERE UserID = '#get_user.ID#' - + @@ -35,7 +34,7 @@ @@ -49,11 +48,10 @@ - SELECT UserID, UserContactNumber - FROM Users - WHERE UserUUID = '#url.UUID#' + ID AS UserID + WHERE UUID = '#url.UUID#' AND - UserIsEmailVerified = 0 + IsEmailVerified = 0 AND UserIsMobileVerified = 0 @@ -62,7 +60,7 @@ UPDATE Users - SET UserIsEmailVerified = 1 + SET IsEmailVerified = 1 WHERE UserID = '#get_confirmed_customer.UserID#' @@ -72,13 +70,13 @@ UPDATE Users - SET UserMobileVerifyCode = '#customer_OPT_confirm#' + SET MobileVerifyCode = '#customer_OPT_confirm#' WHERE UserID = #get_confirmed_customer.UserID# - + - we just sent a six digit code to #get_confirmed_customer.UserContactNumber#

please input that code here:

+ we just sent a six digit code to #get_confirmed_customer.ContactNumber#

please input that code here: