Compare commits
No commits in common. "1210249f54d2c2175060155d9f6e64f5c6eb5eaf" and "c5ebb24b391ec654a0b2be4b544f4d57866321f8" have entirely different histories.
1210249f54
...
c5ebb24b39
253 changed files with 5508 additions and 11058 deletions
|
|
@ -24,9 +24,9 @@
|
||||||
<cfif request.UserID NEQ 0>
|
<cfif request.UserID NEQ 0>
|
||||||
|
|
||||||
<cfquery name="check_user" datasource="#application.datasource#">
|
<cfquery name="check_user" datasource="#application.datasource#">
|
||||||
SELECT FirstName, Balance, ImageExtension
|
SELECT UserFirstName, UserBalance, UserImageExtension
|
||||||
FROM Users
|
FROM Users
|
||||||
WHERE ID = #request.UserID#
|
WHERE UserID = #request.UserID#
|
||||||
</cfquery>
|
</cfquery>
|
||||||
|
|
||||||
</cfif>
|
</cfif>
|
||||||
|
|
@ -320,8 +320,8 @@
|
||||||
<cfif find("logout.cfm", request.cgiPath) EQ 0>
|
<cfif find("logout.cfm", request.cgiPath) EQ 0>
|
||||||
|
|
||||||
<cfif request.UserID NEQ 0>
|
<cfif request.UserID NEQ 0>
|
||||||
<cfif check_user.ImageExtension gt ""><img src="#application.image_display_prefix#users/thumbs/#request.UserID#.#check_user.ImageExtension#" border="0" alt=""><br></cfif>
|
<cfif check_user.UserImageExtension gt ""><img src="#application.image_display_prefix#users/thumbs/#request.UserID#.#check_user.UserImageExtension#" border="0" alt=""><br></cfif>
|
||||||
Hi, <cfif check_user.FirstName gt "">#check_user.FirstName#<br>#dollarformat(check_user.Balance)#<cfelse>Payfrit User</cfif><br>
|
Hi, <cfif check_user.UserFirstName gt "">#check_user.UserFirstName#<br>#dollarformat(check_user.UserBalance)#<cfelse>Payfrit User</cfif><br>
|
||||||
<cfelse>
|
<cfelse>
|
||||||
|
|
||||||
<form action="#application.wwwrootprefix#index.cfm" method="post" name="login_form" id="login_form">
|
<form action="#application.wwwrootprefix#index.cfm" method="post" name="login_form" id="login_form">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# Payfrit Portal Updates
|
|
||||||
|
|
||||||
## Week of 2026-01-26
|
|
||||||
|
|
||||||
- Fixed saved cart not being detected when entering child business
|
|
||||||
14
_process.cfm
14
_process.cfm
|
|
@ -116,13 +116,13 @@
|
||||||
<cfset cart_total = 0>
|
<cfset cart_total = 0>
|
||||||
|
|
||||||
<CFQUERY name="get_queued_food" datasource="#application.datasource#" dbtype="ODBC">
|
<CFQUERY name="get_queued_food" datasource="#application.datasource#" dbtype="ODBC">
|
||||||
SELECT A.CartID, A.AddedOn, A.Quantity, A.SpecialRemark, B.Name, B.UserID, C.Name, A.Price, D.FirstName, D.LaerFirstName, D.Balance
|
SELECT A.CartID, A.AddedOn, A.Quantity, A.SpecialRemark, B.BusinessName, B.UserID, C.ItemName, A.Price, D.UserFirstName, D.LaerFirstName, D.Balance
|
||||||
FROM dbo.Business_CartMaster A, dbo.BusinessMaster B, dbo.Business_ItemMaster C, Users D
|
FROM dbo.Business_CartMaster A, dbo.BusinessMaster B, dbo.Business_ItemMaster C, Users D
|
||||||
WHERE A.UserID = D.UserID
|
WHERE A.UserID = D.UserID
|
||||||
AND
|
AND
|
||||||
A.ItemID = C.ItemID
|
A.ItemID = C.ItemID
|
||||||
AND
|
AND
|
||||||
B.ID = C.BusinessID
|
B.BusinessID = C.BusinessID
|
||||||
AND
|
AND
|
||||||
C.BusinessID = #form.bizid#
|
C.BusinessID = #form.bizid#
|
||||||
AND
|
AND
|
||||||
|
|
@ -170,11 +170,11 @@
|
||||||
</CFQUERY>
|
</CFQUERY>
|
||||||
|
|
||||||
<CFQUERY name="get_last_inserted" datasource="#application.datasource#" dbtype="ODBC">
|
<CFQUERY name="get_last_inserted" datasource="#application.datasource#" dbtype="ODBC">
|
||||||
SELECT TOP 1 O.ID, M.UserID as person_to_pay_for_orderID, U.Balance
|
SELECT TOP 1 O.OrderID, M.UserID as person_to_pay_for_orderID, U.Balance
|
||||||
FROM dbo.Business_OrderMaster O, dbo.BusinessMaster M, Users U
|
FROM dbo.Business_OrderMaster O, dbo.BusinessMaster M, Users U
|
||||||
WHERE O.BusinessID = M.BusinessID
|
WHERE O.BusinessID = M.BusinessID
|
||||||
AND
|
AND
|
||||||
M.UserID = U.ID
|
M.UserID = U.UserID
|
||||||
ORDER BY O.AddedOn DESC
|
ORDER BY O.AddedOn DESC
|
||||||
</CFQUERY>
|
</CFQUERY>
|
||||||
|
|
||||||
|
|
@ -185,7 +185,7 @@
|
||||||
)
|
)
|
||||||
VALUES
|
VALUES
|
||||||
(
|
(
|
||||||
#get_last_inserted.ID#,
|
#get_last_inserted.OrderID#,
|
||||||
#get_queued_food.CartID#
|
#get_queued_food.CartID#
|
||||||
)
|
)
|
||||||
</CFQUERY>
|
</CFQUERY>
|
||||||
|
|
@ -268,7 +268,7 @@
|
||||||
<CFQUERY name="get_user_104_balance" datasource="#application.datasource#" dbtype="ODBC">
|
<CFQUERY name="get_user_104_balance" datasource="#application.datasource#" dbtype="ODBC">
|
||||||
SELECT balance
|
SELECT balance
|
||||||
FROM Users
|
FROM Users
|
||||||
WHERE ID = 104
|
WHERE UserID = 104
|
||||||
</CFQUERY>
|
</CFQUERY>
|
||||||
|
|
||||||
<CFQUERY name="transfer_fees_to_UserID_104" datasource="#application.datasource#" dbtype="ODBC">
|
<CFQUERY name="transfer_fees_to_UserID_104" datasource="#application.datasource#" dbtype="ODBC">
|
||||||
|
|
@ -346,7 +346,7 @@
|
||||||
<CFQUERY name="get_user_104_balance" datasource="#application.datasource#" dbtype="ODBC">
|
<CFQUERY name="get_user_104_balance" datasource="#application.datasource#" dbtype="ODBC">
|
||||||
SELECT balance
|
SELECT balance
|
||||||
FROM Users
|
FROM Users
|
||||||
WHERE ID = 104
|
WHERE UserID = 104
|
||||||
</CFQUERY>
|
</CFQUERY>
|
||||||
|
|
||||||
<CFQUERY name="transfer_fees_to_UserID_104" datasource="#application.datasource#" dbtype="ODBC">
|
<CFQUERY name="transfer_fees_to_UserID_104" datasource="#application.datasource#" dbtype="ODBC">
|
||||||
|
|
|
||||||
|
|
@ -164,8 +164,8 @@ async function refreshAssignments(){
|
||||||
const tr = document.createElement("tr");
|
const tr = document.createElement("tr");
|
||||||
tr.innerHTML = `
|
tr.innerHTML = `
|
||||||
<td>${a.lt_Beacon_Businesses_ServicePointID}</td>
|
<td>${a.lt_Beacon_Businesses_ServicePointID}</td>
|
||||||
<td>${escapeHtml((a.Name || "") + " (ID " + a.BeaconID + ")")}</td>
|
<td>${escapeHtml((a.BeaconName || "") + " (ID " + a.BeaconID + ")")}</td>
|
||||||
<td>${escapeHtml((a.Name || "") + " (ID " + a.ServicePointID + ")")}</td>
|
<td>${escapeHtml((a.ServicePointName || "") + " (ID " + a.ServicePointID + ")")}</td>
|
||||||
<td>${escapeHtml(a.lt_Beacon_Businesses_ServicePointNotes || "")}</td>
|
<td>${escapeHtml(a.lt_Beacon_Businesses_ServicePointNotes || "")}</td>
|
||||||
<td>${escapeHtml(a.CreatedAt || "")}</td>
|
<td>${escapeHtml(a.CreatedAt || "")}</td>
|
||||||
`;
|
`;
|
||||||
|
|
@ -183,12 +183,12 @@ async function refreshBeacons(assignedBeaconIDs, keepSelectedBeaconID){
|
||||||
setSelectPlaceholder(sel, "-- Select Beacon --");
|
setSelectPlaceholder(sel, "-- Select Beacon --");
|
||||||
|
|
||||||
(out.BEACONS || []).forEach(b => {
|
(out.BEACONS || []).forEach(b => {
|
||||||
const isAssigned = assignedBeaconIDs.has(String(b.ID));
|
const isAssigned = assignedBeaconIDs.has(String(b.BeaconID));
|
||||||
if (HIDE_ASSIGNED_BEACONS && isAssigned) return;
|
if (HIDE_ASSIGNED_BEACONS && isAssigned) return;
|
||||||
|
|
||||||
const opt = document.createElement("option");
|
const opt = document.createElement("option");
|
||||||
opt.value = b.ID;
|
opt.value = b.BeaconID;
|
||||||
opt.textContent = String(b.ID) + " - " + (b.Name || "");
|
opt.textContent = String(b.BeaconID) + " - " + (b.BeaconName || "");
|
||||||
sel.appendChild(opt);
|
sel.appendChild(opt);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -203,12 +203,12 @@ async function refreshServicePoints(assignedServicePointIDs, keepSelectedService
|
||||||
setSelectPlaceholder(sel, "-- Select ServicePoint --");
|
setSelectPlaceholder(sel, "-- Select ServicePoint --");
|
||||||
|
|
||||||
(out.SERVICEPOINTS || []).forEach(sp => {
|
(out.SERVICEPOINTS || []).forEach(sp => {
|
||||||
const isAssigned = assignedServicePointIDs.has(String(sp.ID));
|
const isAssigned = assignedServicePointIDs.has(String(sp.ServicePointID));
|
||||||
if (HIDE_ASSIGNED_SERVICEPOINTS && isAssigned) return;
|
if (HIDE_ASSIGNED_SERVICEPOINTS && isAssigned) return;
|
||||||
|
|
||||||
const opt = document.createElement("option");
|
const opt = document.createElement("option");
|
||||||
opt.value = sp.ID;
|
opt.value = sp.ServicePointID;
|
||||||
opt.textContent = String(sp.ID) + " - " + (sp.Name || "");
|
opt.textContent = String(sp.ServicePointID) + " - " + (sp.ServicePointName || "");
|
||||||
sel.appendChild(opt);
|
sel.appendChild(opt);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h2>Beacons</h2>
|
<h2>Beacons</h2>
|
||||||
<div class="warn">Required: Name</div>
|
<div class="warn">Required: BeaconName</div>
|
||||||
<div class="ok" id="jsStatus">(JS not loaded yet)</div>
|
<div class="ok" id="jsStatus">(JS not loaded yet)</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
@ -38,8 +38,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label>Name (required)</label><br>
|
<label>BeaconName (required)</label><br>
|
||||||
<input id="Name" placeholder="Front Door" required>
|
<input id="BeaconName" placeholder="Front Door" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -160,13 +160,13 @@ function escapeHtml(s){
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadIntoForm(b){
|
function loadIntoForm(b){
|
||||||
document.getElementById("BeaconID").value = b.ID || "";
|
document.getElementById("BeaconID").value = b.BeaconID || "";
|
||||||
document.getElementById("Name").value = b.Name || "";
|
document.getElementById("BeaconName").value = b.BeaconName || "";
|
||||||
document.getElementById("UUID").value = b.UUID || "";
|
document.getElementById("UUID").value = b.UUID || "";
|
||||||
document.getElementById("NamespaceId").value = b.NamespaceId || "";
|
document.getElementById("NamespaceId").value = b.NamespaceId || "";
|
||||||
document.getElementById("InstanceId").value = b.InstanceId || "";
|
document.getElementById("InstanceId").value = b.InstanceId || "";
|
||||||
document.getElementById("IsActive").value = ("" + (b.IsActive ?? 1));
|
document.getElementById("IsActive").value = ("" + (b.IsActive ?? 1));
|
||||||
document.getElementById("DelBeaconID").value = b.ID || "";
|
document.getElementById("DelBeaconID").value = b.BeaconID || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
|
|
@ -180,8 +180,8 @@ async function refresh() {
|
||||||
for (const b of items) {
|
for (const b of items) {
|
||||||
const tr = document.createElement("tr");
|
const tr = document.createElement("tr");
|
||||||
tr.innerHTML = `
|
tr.innerHTML = `
|
||||||
<td>${b.ID}</td>
|
<td>${b.BeaconID}</td>
|
||||||
<td>${escapeHtml(b.Name||"")}</td>
|
<td>${escapeHtml(b.BeaconName||"")}</td>
|
||||||
<td>${escapeHtml(b.UUID||"")}</td>
|
<td>${escapeHtml(b.UUID||"")}</td>
|
||||||
<td>${escapeHtml(b.NamespaceId||"")}</td>
|
<td>${escapeHtml(b.NamespaceId||"")}</td>
|
||||||
<td>${escapeHtml(b.InstanceId||"")}</td>
|
<td>${escapeHtml(b.InstanceId||"")}</td>
|
||||||
|
|
@ -194,15 +194,15 @@ async function refresh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveBeacon() {
|
async function saveBeacon() {
|
||||||
const name = (document.getElementById("Name").value || "").trim();
|
const name = (document.getElementById("BeaconName").value || "").trim();
|
||||||
if (!name) {
|
if (!name) {
|
||||||
show({ OK:false, ERROR:"missing_beacon_name", MESSAGE:"Name is required" });
|
show({ OK:false, ERROR:"missing_beacon_name", MESSAGE:"BeaconName is required" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
BeaconID: valIntOrNull("BeaconID"),
|
BeaconID: valIntOrNull("BeaconID"),
|
||||||
Name: name,
|
BeaconName: name,
|
||||||
UUID: (document.getElementById("UUID").value || "").trim(),
|
UUID: (document.getElementById("UUID").value || "").trim(),
|
||||||
NamespaceId: (document.getElementById("NamespaceId").value || "").trim(),
|
NamespaceId: (document.getElementById("NamespaceId").value || "").trim(),
|
||||||
InstanceId: (document.getElementById("InstanceId").value || "").trim(),
|
InstanceId: (document.getElementById("InstanceId").value || "").trim(),
|
||||||
|
|
|
||||||
|
|
@ -7,16 +7,16 @@
|
||||||
<cfparam name="users_to_email" default="">
|
<cfparam name="users_to_email" default="">
|
||||||
|
|
||||||
<cfquery name="select_users_to_email" datasource="#application.datasource#">
|
<cfquery name="select_users_to_email" datasource="#application.datasource#">
|
||||||
SELECT U.EmailAddress
|
SELECT U.UserEmailAddress
|
||||||
FROM Users U
|
FROM Users U
|
||||||
WHERE UserID in (0,1,2)
|
WHERE UserID in (0,1,2)
|
||||||
</cfquery>
|
</cfquery>
|
||||||
|
|
||||||
<cfoutput query="select_users_to_email">
|
<cfoutput query="select_users_to_email">
|
||||||
|
|
||||||
#EmailAddress#,
|
#UserEmailAddress#,
|
||||||
|
|
||||||
<cfset users_to_email=listappend(users_to_email, #EmailAddress#)>
|
<cfset users_to_email=listappend(users_to_email, #UserEmailAddress#)>
|
||||||
|
|
||||||
</cfoutput><br><br>
|
</cfoutput><br><br>
|
||||||
|
|
||||||
|
|
@ -95,18 +95,18 @@
|
||||||
<cfloop index="the_email_address" list="#users_to_email#">
|
<cfloop index="the_email_address" list="#users_to_email#">
|
||||||
|
|
||||||
<cfquery name="get_user_email" datasource="#application.datasource#">
|
<cfquery name="get_user_email" datasource="#application.datasource#">
|
||||||
SELECT UUID
|
SELECT UserUUID
|
||||||
FROM Users
|
FROM Users
|
||||||
WHERE EmailAddress = '#the_email_address#'
|
WHERE UserEmailAddress = '#the_email_address#'
|
||||||
AND
|
AND
|
||||||
UserIsEmailverified = 1
|
UserIsEmailverified = 1
|
||||||
AND
|
AND
|
||||||
IsContactVerified > 0
|
UserIsContactVerified > 0
|
||||||
</cfquery>
|
</cfquery>
|
||||||
|
|
||||||
<cfset form.this_email_body = form.email_body & "
|
<cfset form.this_email_body = form.email_body & "
|
||||||
|
|
||||||
instant unsubscribe link: https://www.payfrit.com/remove_me.cfm?UUID="&#get_user_email.UUID#>
|
instant unsubscribe link: https://www.payfrit.com/remove_me.cfm?UserUUID="&#get_user_email.UserUUID#>
|
||||||
|
|
||||||
<cfmail to="#the_email_address#" from="admin@payfrit.com" subject="#form.email_subject#" type="HTML">
|
<cfmail to="#the_email_address#" from="admin@payfrit.com" subject="#form.email_subject#" type="HTML">
|
||||||
#HTMLCodeFormat(form.this_email_body)#</cfmail>
|
#HTMLCodeFormat(form.this_email_body)#</cfmail>
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@
|
||||||
<cfif form.mode eq "start">
|
<cfif form.mode eq "start">
|
||||||
|
|
||||||
<CFQUERY name="get_verified_users" datasource="#application.datasource#">
|
<CFQUERY name="get_verified_users" datasource="#application.datasource#">
|
||||||
SELECT U.ID, U.EmailAddress, U.ContactNumber,U.AddedOn
|
SELECT U.UserID, U.UserEmailAddress, U.UserContactNumber,U.UserAddedOn
|
||||||
FROM Users U
|
FROM Users U
|
||||||
WHERE U.IsEmailVerified = 1
|
WHERE U.UserIsEmailVerified = 1
|
||||||
AND
|
AND
|
||||||
U.UserIsCOntactVerified > 0
|
U.UserIsCOntactVerified > 0
|
||||||
AND
|
AND
|
||||||
U.ID > 435
|
U.UserID > 435
|
||||||
ORDER BY U.ID DESC
|
ORDER BY U.UserID DESC
|
||||||
</cfquery>
|
</cfquery>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -48,16 +48,16 @@
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
<td>#EmailAddress#</td>
|
<td>#UserEmailAddress#</td>
|
||||||
<td>#ContactNumber#</td>
|
<td>#UserContactNumber#</td>
|
||||||
<td>#dateformat(AddedOn, "mmmm dd, YYYY")# at #timeformat(AddedOn, "hh:nn tt")#</td>
|
<td>#dateformat(UserAddedOn, "mmmm dd, YYYY")# at #timeformat(UserAddedOn, "hh:nn tt")#</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
<CFQUERY name="get_orders" datasource="#application.datasource#">
|
<CFQUERY name="get_orders" datasource="#application.datasource#">
|
||||||
SELECT O.UUID
|
SELECT O.OrderUUID
|
||||||
FROM Orders O
|
FROM Orders O
|
||||||
WHERE O.UserID = #get_verified_users.ID#
|
WHERE O.OrderUserID = #get_verified_users.UserID#
|
||||||
ORDER BY O.ID DESC
|
ORDER BY O.OrderID DESC
|
||||||
</cfquery>
|
</cfquery>
|
||||||
|
|
||||||
<cfparam name="looper" default="">
|
<cfparam name="looper" default="">
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
|
|
||||||
<cfloop query="get_orders">
|
<cfloop query="get_orders">
|
||||||
<cfset looper=incrementvalue(looper)>
|
<cfset looper=incrementvalue(looper)>
|
||||||
<a href="https://payfr.it/show_order.cfm?UUID=#get_orders.UUID#&is_admin_view=1" target="_blank">#looper#</a>,
|
<a href="https://payfr.it/show_order.cfm?OrderUUID=#get_orders.OrderUUID#&is_admin_view=1" target="_blank">#looper#</a>,
|
||||||
</cfloop>
|
</cfloop>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -79,10 +79,10 @@
|
||||||
<cfelseif form.mode eq "user_traffic">
|
<cfelseif form.mode eq "user_traffic">
|
||||||
|
|
||||||
<CFQUERY name="get_user_traffic" datasource="#application.datasource#">
|
<CFQUERY name="get_user_traffic" datasource="#application.datasource#">
|
||||||
SELECT V.PageMode, V.AddedOn
|
SELECT V.VisitorTrackingPageMode, V.VisitorTrackingAddedOn
|
||||||
FROM VisitorTrackings V
|
FROM VisitorTracking V
|
||||||
WHERE V.UserID = #form.chip#
|
WHERE V.VisitorTrackingUserID = #form.chip#
|
||||||
ORDER BY V.AddedOn DESC
|
ORDER BY V.VisitorTrackingAddedOn DESC
|
||||||
</cfquery>
|
</cfquery>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
|
@ -92,8 +92,8 @@
|
||||||
</tr>
|
</tr>
|
||||||
<cfoutput query="get_user_traffic">
|
<cfoutput query="get_user_traffic">
|
||||||
<tr>
|
<tr>
|
||||||
<td>#PageMode#</td>
|
<td>#VisitorTrackingPageMode#</td>
|
||||||
<td>#AddedOn#</td>
|
<td>#VisitorTrackingAddedOn#</td>
|
||||||
</tr>
|
</tr>
|
||||||
</cfoutput>
|
</cfoutput>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h2>ServicePoints</h2>
|
<h2>ServicePoints</h2>
|
||||||
<div class="warn">Required: Name</div>
|
<div class="warn">Required: ServicePointName</div>
|
||||||
<div class="ok" id="jsStatus">(JS not loaded yet)</div>
|
<div class="ok" id="jsStatus">(JS not loaded yet)</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
@ -38,18 +38,18 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label>Name (required)</label><br>
|
<label>ServicePointName (required)</label><br>
|
||||||
<input id="Name" placeholder="Front Counter" required>
|
<input id="ServicePointName" placeholder="Front Counter" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label>TypeID</label><br>
|
<label>ServicePointTypeID</label><br>
|
||||||
<input id="TypeID" placeholder="0">
|
<input id="ServicePointTypeID" placeholder="0">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label>Code</label><br>
|
<label>ServicePointCode</label><br>
|
||||||
<input id="Code" placeholder="COUNTER">
|
<input id="ServicePointCode" placeholder="COUNTER">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -160,14 +160,14 @@ function escapeHtml(s){
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadIntoForm(sp){
|
function loadIntoForm(sp){
|
||||||
document.getElementById("ServicePointID").value = sp.ID || "";
|
document.getElementById("ServicePointID").value = sp.ServicePointID || "";
|
||||||
document.getElementById("Name").value = sp.Name || "";
|
document.getElementById("ServicePointName").value = sp.ServicePointName || "";
|
||||||
document.getElementById("TypeID").value = (sp.TypeID ?? 0);
|
document.getElementById("ServicePointTypeID").value = (sp.ServicePointTypeID ?? 0);
|
||||||
document.getElementById("Code").value = sp.Code || "";
|
document.getElementById("ServicePointCode").value = sp.ServicePointCode || "";
|
||||||
document.getElementById("Description").value = sp.Description || "";
|
document.getElementById("Description").value = sp.Description || "";
|
||||||
document.getElementById("SortOrder").value = (sp.SortOrder ?? 0);
|
document.getElementById("SortOrder").value = (sp.SortOrder ?? 0);
|
||||||
document.getElementById("IsActive").value = ("" + (sp.IsActive ?? 1));
|
document.getElementById("IsActive").value = ("" + (sp.IsActive ?? 1));
|
||||||
document.getElementById("DelServicePointID").value = sp.ID || "";
|
document.getElementById("DelServicePointID").value = sp.ServicePointID || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
|
|
@ -181,10 +181,10 @@ async function refresh() {
|
||||||
for (const sp of items) {
|
for (const sp of items) {
|
||||||
const tr = document.createElement("tr");
|
const tr = document.createElement("tr");
|
||||||
tr.innerHTML = `
|
tr.innerHTML = `
|
||||||
<td>${sp.ID}</td>
|
<td>${sp.ServicePointID}</td>
|
||||||
<td>${escapeHtml(sp.Name||"")}</td>
|
<td>${escapeHtml(sp.ServicePointName||"")}</td>
|
||||||
<td>${sp.TypeID}</td>
|
<td>${sp.ServicePointTypeID}</td>
|
||||||
<td>${escapeHtml(sp.Code||"")}</td>
|
<td>${escapeHtml(sp.ServicePointCode||"")}</td>
|
||||||
<td>${sp.SortOrder}</td>
|
<td>${sp.SortOrder}</td>
|
||||||
<td>${sp.IsActive}</td>
|
<td>${sp.IsActive}</td>
|
||||||
`;
|
`;
|
||||||
|
|
@ -195,17 +195,17 @@ async function refresh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveSP() {
|
async function saveSP() {
|
||||||
const name = (document.getElementById("Name").value || "").trim();
|
const name = (document.getElementById("ServicePointName").value || "").trim();
|
||||||
if (!name) {
|
if (!name) {
|
||||||
show({ OK:false, ERROR:"missing_servicepoint_name", MESSAGE:"Name is required" });
|
show({ OK:false, ERROR:"missing_servicepoint_name", MESSAGE:"ServicePointName is required" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
ServicePointID: valIntOrNull("ServicePointID"),
|
ServicePointID: valIntOrNull("ServicePointID"),
|
||||||
Name: name,
|
ServicePointName: name,
|
||||||
TypeID: valIntOrZero("TypeID"),
|
ServicePointTypeID: valIntOrZero("ServicePointTypeID"),
|
||||||
Code: (document.getElementById("Code").value || "").trim(),
|
ServicePointCode: (document.getElementById("ServicePointCode").value || "").trim(),
|
||||||
Description: (document.getElementById("Description").value || "").trim(),
|
Description: (document.getElementById("Description").value || "").trim(),
|
||||||
SortOrder: valIntOrZero("SortOrder"),
|
SortOrder: valIntOrZero("SortOrder"),
|
||||||
IsActive: parseInt(document.getElementById("IsActive").value, 10)
|
IsActive: parseInt(document.getElementById("IsActive").value, 10)
|
||||||
|
|
|
||||||
|
|
@ -173,11 +173,6 @@ if (len(request._api_path)) {
|
||||||
|
|
||||||
// Worker app endpoints
|
// Worker app endpoints
|
||||||
if (findNoCase("/api/workers/myBusinesses.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/workers/myBusinesses.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
if (findNoCase("/api/workers/tierStatus.cfm", request._api_path)) request._api_isPublic = true;
|
|
||||||
if (findNoCase("/api/workers/createAccount.cfm", request._api_path)) request._api_isPublic = true;
|
|
||||||
if (findNoCase("/api/workers/onboardingLink.cfm", request._api_path)) request._api_isPublic = true;
|
|
||||||
if (findNoCase("/api/workers/earlyUnlock.cfm", request._api_path)) request._api_isPublic = true;
|
|
||||||
if (findNoCase("/api/workers/ledger.cfm", request._api_path)) request._api_isPublic = true;
|
|
||||||
|
|
||||||
// Portal endpoints
|
// Portal endpoints
|
||||||
if (findNoCase("/api/portal/stats.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/portal/stats.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
|
|
@ -198,7 +193,6 @@ if (len(request._api_path)) {
|
||||||
if (findNoCase("/api/menu/getForBuilder.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/menu/getForBuilder.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
if (findNoCase("/api/menu/saveFromBuilder.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/menu/saveFromBuilder.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
if (findNoCase("/api/menu/updateStations.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/menu/updateStations.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
if (findNoCase("/api/menu/menus.cfm", request._api_path)) request._api_isPublic = true;
|
|
||||||
if (findNoCase("/api/menu/uploadHeader.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/menu/uploadHeader.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
if (findNoCase("/api/menu/listCategories.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/menu/listCategories.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
if (findNoCase("/api/menu/saveCategory.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/menu/saveCategory.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
|
|
@ -265,9 +259,6 @@ if (len(request._api_path)) {
|
||||||
if (findNoCase("/api/ratings/setup.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/ratings/setup.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
if (findNoCase("/api/ratings/submit.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/ratings/submit.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
|
|
||||||
// App info endpoints (public, no auth needed)
|
|
||||||
if (findNoCase("/api/app/about.cfm", request._api_path)) request._api_isPublic = true;
|
|
||||||
|
|
||||||
// Stripe endpoints
|
// Stripe endpoints
|
||||||
if (findNoCase("/api/stripe/onboard.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/stripe/onboard.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
if (findNoCase("/api/stripe/status.cfm", request._api_path)) request._api_isPublic = true;
|
if (findNoCase("/api/stripe/status.cfm", request._api_path)) request._api_isPublic = true;
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,9 @@ try {
|
||||||
|
|
||||||
// Optional fields
|
// Optional fields
|
||||||
line2 = trim(data.Line2 ?: "");
|
line2 = trim(data.Line2 ?: "");
|
||||||
|
label = trim(data.Label ?: "");
|
||||||
setAsDefault = (data.SetAsDefault ?: false) == true;
|
setAsDefault = (data.SetAsDefault ?: false) == true;
|
||||||
|
|
||||||
// Hardcoded to delivery address type
|
|
||||||
typeId = 2;
|
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
if (len(line1) == 0 || len(city) == 0 || stateId <= 0 || len(zipCode) == 0) {
|
if (len(line1) == 0 || len(city) == 0 || stateId <= 0 || len(zipCode) == 0) {
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
|
|
@ -53,17 +51,16 @@ try {
|
||||||
abort;
|
abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If setting as default, clear other defaults first (for same type)
|
// If setting as default, clear other defaults first
|
||||||
if (setAsDefault) {
|
if (setAsDefault) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Addresses
|
UPDATE Addresses
|
||||||
SET AddressIsDefaultDelivery = 0
|
SET AddressIsDefaultDelivery = 0
|
||||||
WHERE UserID = :userId
|
WHERE AddressUserID = :userId
|
||||||
AND (BusinessID = 0 OR BusinessID IS NULL)
|
AND (AddressBusinessID = 0 OR AddressBusinessID IS NULL)
|
||||||
AND AddressTypeID = :typeId
|
AND AddressTypeID LIKE '%2%'
|
||||||
", {
|
", {
|
||||||
userId: { value: userId, cfsqltype: "cf_sql_integer" },
|
userId: { value: userId, cfsqltype: "cf_sql_integer" }
|
||||||
typeId: { value: typeId, cfsqltype: "cf_sql_integer" }
|
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,23 +72,23 @@ try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Addresses (
|
INSERT INTO Addresses (
|
||||||
AddressID,
|
AddressID,
|
||||||
UserID,
|
AddressUserID,
|
||||||
BusinessID,
|
AddressBusinessID,
|
||||||
AddressTypeID,
|
AddressTypeID,
|
||||||
AddressLabel,
|
AddressLabel,
|
||||||
AddressIsDefaultDelivery,
|
AddressIsDefaultDelivery,
|
||||||
Line1,
|
AddressLine1,
|
||||||
Line2,
|
AddressLine2,
|
||||||
City,
|
AddressCity,
|
||||||
StateID,
|
AddressStateID,
|
||||||
ZIPCode,
|
AddressZIPCode,
|
||||||
IsDeleted,
|
AddressIsDeleted,
|
||||||
AddedOn
|
AddressAddedOn
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:addressId,
|
:addressId,
|
||||||
:userId,
|
:userId,
|
||||||
0,
|
0,
|
||||||
:typeId,
|
'2',
|
||||||
:label,
|
:label,
|
||||||
:isDefault,
|
:isDefault,
|
||||||
:line1,
|
:line1,
|
||||||
|
|
@ -105,7 +102,6 @@ try {
|
||||||
", {
|
", {
|
||||||
addressId: { value: newAddressId, cfsqltype: "cf_sql_integer" },
|
addressId: { value: newAddressId, cfsqltype: "cf_sql_integer" },
|
||||||
userId: { value: userId, cfsqltype: "cf_sql_integer" },
|
userId: { value: userId, cfsqltype: "cf_sql_integer" },
|
||||||
typeId: { value: typeId, cfsqltype: "cf_sql_integer" },
|
|
||||||
label: { value: label, cfsqltype: "cf_sql_varchar" },
|
label: { value: label, cfsqltype: "cf_sql_varchar" },
|
||||||
isDefault: { value: setAsDefault ? 1 : 0, cfsqltype: "cf_sql_integer" },
|
isDefault: { value: setAsDefault ? 1 : 0, cfsqltype: "cf_sql_integer" },
|
||||||
line1: { value: line1, cfsqltype: "cf_sql_varchar" },
|
line1: { value: line1, cfsqltype: "cf_sql_varchar" },
|
||||||
|
|
@ -117,7 +113,7 @@ try {
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Get state info for response
|
// Get state info for response
|
||||||
qState = queryExecute("SELECT Abbreviation as StateAbbreviation, Name as StateName FROM tt_States WHERE ID = :stateId", {
|
qState = queryExecute("SELECT tt_StateAbbreviation as StateAbbreviation, tt_StateName as StateName FROM tt_States WHERE tt_StateID = :stateId", {
|
||||||
stateId: { value: stateId, cfsqltype: "cf_sql_integer" }
|
stateId: { value: stateId, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
|
|
@ -128,7 +124,6 @@ try {
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"ADDRESS": {
|
"ADDRESS": {
|
||||||
"AddressID": newAddressId,
|
"AddressID": newAddressId,
|
||||||
"TypeID": typeId,
|
|
||||||
"Label": len(label) ? label : "Address",
|
"Label": len(label) ? label : "Address",
|
||||||
"IsDefault": setAsDefault,
|
"IsDefault": setAsDefault,
|
||||||
"Line1": line1,
|
"Line1": line1,
|
||||||
|
|
|
||||||
|
|
@ -76,11 +76,11 @@ if (addressId <= 0) {
|
||||||
try {
|
try {
|
||||||
// First, get the address details so we can find all matching duplicates
|
// First, get the address details so we can find all matching duplicates
|
||||||
qAddr = queryExecute("
|
qAddr = queryExecute("
|
||||||
SELECT Line1, Line2, City, StateID, ZIPCode
|
SELECT AddressLine1, AddressLine2, AddressCity, AddressStateID, AddressZIPCode
|
||||||
FROM Addresses
|
FROM Addresses
|
||||||
WHERE ID = :addressId
|
WHERE AddressID = :addressId
|
||||||
AND UserID = :userId
|
AND AddressUserID = :userId
|
||||||
AND IsDeleted = 0
|
AND AddressIsDeleted = 0
|
||||||
", {
|
", {
|
||||||
addressId: { value = addressId, cfsqltype = "cf_sql_integer" },
|
addressId: { value = addressId, cfsqltype = "cf_sql_integer" },
|
||||||
userId: { value = userId, cfsqltype = "cf_sql_integer" }
|
userId: { value = userId, cfsqltype = "cf_sql_integer" }
|
||||||
|
|
@ -93,21 +93,21 @@ try {
|
||||||
// Soft-delete ALL addresses that match the same Line1, Line2, City, StateID, ZIPCode
|
// Soft-delete ALL addresses that match the same Line1, Line2, City, StateID, ZIPCode
|
||||||
qDelete = queryExecute("
|
qDelete = queryExecute("
|
||||||
UPDATE Addresses
|
UPDATE Addresses
|
||||||
SET IsDeleted = 1
|
SET AddressIsDeleted = 1
|
||||||
WHERE UserID = :userId
|
WHERE AddressUserID = :userId
|
||||||
AND Line1 = :line1
|
AND AddressLine1 = :line1
|
||||||
AND Line2 = :line2
|
AND AddressLine2 = :line2
|
||||||
AND City = :city
|
AND AddressCity = :city
|
||||||
AND StateID = :stateId
|
AND AddressStateID = :stateId
|
||||||
AND ZIPCode = :zip
|
AND AddressZIPCode = :zip
|
||||||
AND IsDeleted = 0
|
AND AddressIsDeleted = 0
|
||||||
", {
|
", {
|
||||||
userId: { value = userId, cfsqltype = "cf_sql_integer" },
|
userId: { value = userId, cfsqltype = "cf_sql_integer" },
|
||||||
line1: { value = qAddr.Line1, cfsqltype = "cf_sql_varchar", null = !len(qAddr.Line1) },
|
line1: { value = qAddr.AddressLine1, cfsqltype = "cf_sql_varchar", null = !len(qAddr.AddressLine1) },
|
||||||
line2: { value = qAddr.Line2, cfsqltype = "cf_sql_varchar", null = !len(qAddr.Line2) },
|
line2: { value = qAddr.AddressLine2, cfsqltype = "cf_sql_varchar", null = !len(qAddr.AddressLine2) },
|
||||||
city: { value = qAddr.City, cfsqltype = "cf_sql_varchar", null = !len(qAddr.City) },
|
city: { value = qAddr.AddressCity, cfsqltype = "cf_sql_varchar", null = !len(qAddr.AddressCity) },
|
||||||
stateId: { value = qAddr.StateID, cfsqltype = "cf_sql_integer" },
|
stateId: { value = qAddr.AddressStateID, cfsqltype = "cf_sql_integer" },
|
||||||
zip: { value = qAddr.ZIPCode, cfsqltype = "cf_sql_varchar", null = !len(qAddr.ZIPCode) }
|
zip: { value = qAddr.AddressZIPCode, cfsqltype = "cf_sql_varchar", null = !len(qAddr.AddressZIPCode) }
|
||||||
});
|
});
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
|
|
|
||||||
|
|
@ -46,25 +46,26 @@ if (userId <= 0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get user's delivery addresses
|
// Get user's delivery addresses with GROUP BY to show unique addresses only
|
||||||
qAddresses = queryExecute("
|
qAddresses = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
a.ID,
|
MIN(a.AddressID) as AddressID,
|
||||||
a.IsDefaultDelivery,
|
MAX(a.AddressLabel) as AddressLabel,
|
||||||
a.Line1,
|
MAX(a.AddressIsDefaultDelivery) as AddressIsDefaultDelivery,
|
||||||
a.Line2,
|
a.AddressLine1,
|
||||||
a.City,
|
a.AddressLine2,
|
||||||
a.StateID,
|
a.AddressCity,
|
||||||
s.Abbreviation as StateAbbreviation,
|
a.AddressStateID,
|
||||||
s.Name as StateName,
|
MAX(s.tt_StateAbbreviation) as StateAbbreviation,
|
||||||
a.ZIPCode
|
MAX(s.tt_StateName) as StateName,
|
||||||
|
a.AddressZIPCode
|
||||||
FROM Addresses a
|
FROM Addresses a
|
||||||
LEFT JOIN tt_States s ON a.StateID = s.ID
|
LEFT JOIN tt_States s ON a.AddressStateID = s.tt_StateID
|
||||||
WHERE a.UserID = :userId
|
WHERE a.AddressUserID = :userId
|
||||||
AND (a.BusinessID = 0 OR a.BusinessID IS NULL)
|
AND a.AddressTypeID LIKE '%2%'
|
||||||
AND a.AddressTypeID = 2
|
AND a.AddressIsDeleted = 0
|
||||||
AND a.IsDeleted = 0
|
GROUP BY a.AddressLine1, a.AddressLine2, a.AddressCity, a.AddressStateID, a.AddressZIPCode
|
||||||
ORDER BY a.IsDefaultDelivery DESC, a.ID DESC
|
ORDER BY MAX(a.AddressIsDefaultDelivery) DESC, MIN(a.AddressID) DESC
|
||||||
", {
|
", {
|
||||||
userId: { value = userId, cfsqltype = "cf_sql_integer" }
|
userId: { value = userId, cfsqltype = "cf_sql_integer" }
|
||||||
});
|
});
|
||||||
|
|
@ -72,15 +73,17 @@ try {
|
||||||
addresses = [];
|
addresses = [];
|
||||||
for (row in qAddresses) {
|
for (row in qAddresses) {
|
||||||
arrayAppend(addresses, {
|
arrayAppend(addresses, {
|
||||||
"AddressID": row.ID,
|
"AddressID": row.AddressID,
|
||||||
"IsDefault": row.IsDefaultDelivery == 1,
|
"Label": len(row.AddressLabel) ? row.AddressLabel : "Address",
|
||||||
"Line1": row.Line1,
|
"IsDefault": row.AddressIsDefaultDelivery == 1,
|
||||||
"Line2": row.Line2 ?: "",
|
"Line1": row.AddressLine1,
|
||||||
"City": row.City,
|
"Line2": row.AddressLine2 ?: "",
|
||||||
"StateID": row.StateID,
|
"City": row.AddressCity,
|
||||||
|
"StateID": row.AddressStateID,
|
||||||
"StateAbbr": row.StateAbbreviation ?: "",
|
"StateAbbr": row.StateAbbreviation ?: "",
|
||||||
"ZIPCode": row.ZIPCode,
|
"StateName": row.StateName ?: "",
|
||||||
"DisplayText": row.Line1 & (len(row.Line2) ? ", " & row.Line2 : "") & ", " & row.City & ", " & (row.StateAbbreviation ?: "") & " " & row.ZIPCode
|
"ZIPCode": row.AddressZIPCode,
|
||||||
|
"DisplayText": row.AddressLine1 & (len(row.AddressLine2) ? ", " & row.AddressLine2 : "") & ", " & row.AddressCity & ", " & (row.StateAbbreviation ?: "") & " " & row.AddressZIPCode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +96,8 @@ try {
|
||||||
apiAbort({
|
apiAbort({
|
||||||
"OK": false,
|
"OK": false,
|
||||||
"ERROR": "server_error",
|
"ERROR": "server_error",
|
||||||
"MESSAGE": e.message
|
"MESSAGE": e.message,
|
||||||
|
"LINE": e.tagContext[1].line ?: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</cfscript>
|
</cfscript>
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,11 @@ try {
|
||||||
|
|
||||||
// Verify address belongs to user
|
// Verify address belongs to user
|
||||||
qCheck = queryExecute("
|
qCheck = queryExecute("
|
||||||
SELECT ID
|
SELECT AddressID
|
||||||
FROM Addresses
|
FROM Addresses
|
||||||
WHERE ID = :addressId
|
WHERE AddressID = :addressId
|
||||||
AND UserID = :userId
|
AND AddressUserID = :userId
|
||||||
AND IsDeleted = 0
|
AND AddressIsDeleted = 0
|
||||||
", {
|
", {
|
||||||
addressId: { value: addressId, cfsqltype: "cf_sql_integer" },
|
addressId: { value: addressId, cfsqltype: "cf_sql_integer" },
|
||||||
userId: { value: userId, cfsqltype: "cf_sql_integer" }
|
userId: { value: userId, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -64,8 +64,8 @@ try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Addresses
|
UPDATE Addresses
|
||||||
SET AddressIsDefaultDelivery = 0
|
SET AddressIsDefaultDelivery = 0
|
||||||
WHERE UserID = :userId
|
WHERE AddressUserID = :userId
|
||||||
AND (BusinessID = 0 OR BusinessID IS NULL)
|
AND (AddressBusinessID = 0 OR AddressBusinessID IS NULL)
|
||||||
AND AddressTypeID LIKE '%2%'
|
AND AddressTypeID LIKE '%2%'
|
||||||
", {
|
", {
|
||||||
userId: { value: userId, cfsqltype: "cf_sql_integer" }
|
userId: { value: userId, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -75,7 +75,7 @@ try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Addresses
|
UPDATE Addresses
|
||||||
SET AddressIsDefaultDelivery = 1
|
SET AddressIsDefaultDelivery = 1
|
||||||
WHERE ID = :addressId
|
WHERE AddressID = :addressId
|
||||||
", {
|
", {
|
||||||
addressId: { value: addressId, cfsqltype: "cf_sql_integer" }
|
addressId: { value: addressId, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
<cfscript>
|
<cfscript>
|
||||||
try {
|
try {
|
||||||
qStates = queryExecute("
|
qStates = queryExecute("
|
||||||
SELECT tt_StateID as StateID, Abbreviation as StateAbbreviation, Name as StateName
|
SELECT tt_StateID as StateID, tt_StateAbbreviation as StateAbbreviation, tt_StateName as StateName
|
||||||
FROM tt_States
|
FROM tt_States
|
||||||
ORDER BY Name
|
ORDER BY tt_StateName
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
states = [];
|
states = [];
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfsetting enablecfoutputonly="true">
|
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
||||||
<cfheader name="Cache-Control" value="max-age=3600">
|
|
||||||
|
|
||||||
<cfscript>
|
|
||||||
/**
|
|
||||||
* Get list of address types
|
|
||||||
* GET: /api/addresses/types.cfm
|
|
||||||
* Returns: { OK: true, TYPES: [{ ID: 1, Label: "Billing" }, ...] }
|
|
||||||
*/
|
|
||||||
|
|
||||||
try {
|
|
||||||
qTypes = queryExecute("
|
|
||||||
SELECT tt_AddressTypeID as ID, tt_AddressType as Label
|
|
||||||
FROM tt_AddressTypes
|
|
||||||
ORDER BY tt_AddressTypeID
|
|
||||||
", {}, { datasource: "payfrit" });
|
|
||||||
|
|
||||||
types = [];
|
|
||||||
for (row in qTypes) {
|
|
||||||
arrayAppend(types, {
|
|
||||||
"ID": row.ID,
|
|
||||||
"Label": row.Label
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"TYPES": types
|
|
||||||
}));
|
|
||||||
|
|
||||||
} catch (any e) {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": false,
|
|
||||||
"ERROR": "server_error",
|
|
||||||
"MESSAGE": e.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
||||||
|
|
||||||
<cfscript>
|
|
||||||
// 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 = 'IsActive'
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
if (qCheck.recordCount == 0) {
|
|
||||||
queryExecute("
|
|
||||||
ALTER TABLE TaskCategories
|
|
||||||
ADD COLUMN IsActive TINYINT(1) NOT NULL DEFAULT 1
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"MESSAGE": "Column IsActive added to TaskCategories"
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"MESSAGE": "Column already exists"
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} catch (any e) {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": false,
|
|
||||||
"ERROR": e.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -8,9 +8,9 @@
|
||||||
* Add Schedule Fields to Categories Table
|
* Add Schedule Fields to Categories Table
|
||||||
*
|
*
|
||||||
* Adds time-based scheduling fields:
|
* Adds time-based scheduling fields:
|
||||||
* - ScheduleStart: TIME - Start time when category is available (e.g., 06:00:00 for breakfast)
|
* - CategoryScheduleStart: 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)
|
* - CategoryScheduleEnd: 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
|
* - CategoryScheduleDays: 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.
|
* Run this once to migrate the schema.
|
||||||
*/
|
*/
|
||||||
|
|
@ -24,38 +24,38 @@ try {
|
||||||
FROM INFORMATION_SCHEMA.COLUMNS
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
WHERE TABLE_SCHEMA = 'payfrit'
|
WHERE TABLE_SCHEMA = 'payfrit'
|
||||||
AND TABLE_NAME = 'Categories'
|
AND TABLE_NAME = 'Categories'
|
||||||
AND COLUMN_NAME IN ('ScheduleStart', 'ScheduleEnd', 'ScheduleDays')
|
AND COLUMN_NAME IN ('CategoryScheduleStart', 'CategoryScheduleEnd', 'CategoryScheduleDays')
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
existingCols = valueList(qCheck.COLUMN_NAME);
|
existingCols = valueList(qCheck.COLUMN_NAME);
|
||||||
|
|
||||||
added = [];
|
added = [];
|
||||||
|
|
||||||
// Add ScheduleStart if not exists
|
// Add CategoryScheduleStart if not exists
|
||||||
if (!listFindNoCase(existingCols, "ScheduleStart")) {
|
if (!listFindNoCase(existingCols, "CategoryScheduleStart")) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Categories
|
ALTER TABLE Categories
|
||||||
ADD COLUMN ScheduleStart TIME NULL
|
ADD COLUMN CategoryScheduleStart TIME NULL
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
arrayAppend(added, "ScheduleStart");
|
arrayAppend(added, "CategoryScheduleStart");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add ScheduleEnd if not exists
|
// Add CategoryScheduleEnd if not exists
|
||||||
if (!listFindNoCase(existingCols, "ScheduleEnd")) {
|
if (!listFindNoCase(existingCols, "CategoryScheduleEnd")) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Categories
|
ALTER TABLE Categories
|
||||||
ADD COLUMN ScheduleEnd TIME NULL
|
ADD COLUMN CategoryScheduleEnd TIME NULL
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
arrayAppend(added, "ScheduleEnd");
|
arrayAppend(added, "CategoryScheduleEnd");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add ScheduleDays if not exists
|
// Add CategoryScheduleDays if not exists
|
||||||
if (!listFindNoCase(existingCols, "ScheduleDays")) {
|
if (!listFindNoCase(existingCols, "CategoryScheduleDays")) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Categories
|
ALTER TABLE Categories
|
||||||
ADD COLUMN ScheduleDays VARCHAR(20) NULL
|
ADD COLUMN CategoryScheduleDays VARCHAR(20) NULL
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
arrayAppend(added, "ScheduleDays");
|
arrayAppend(added, "CategoryScheduleDays");
|
||||||
}
|
}
|
||||||
|
|
||||||
response["OK"] = true;
|
response["OK"] = true;
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ try {
|
||||||
|
|
||||||
// Find the Fountain Soda item we created
|
// Find the Fountain Soda item we created
|
||||||
qFountain = queryExecute("
|
qFountain = queryExecute("
|
||||||
SELECT ID, Name FROM Items
|
SELECT ItemID, ItemName FROM Items
|
||||||
WHERE BusinessID = :bizId AND Name = 'Fountain Soda'
|
WHERE ItemBusinessID = :bizId AND ItemName = 'Fountain Soda'
|
||||||
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qFountain.recordCount == 0) {
|
if (qFountain.recordCount == 0) {
|
||||||
|
|
@ -31,13 +31,13 @@ try {
|
||||||
// Update Fountain Soda to require child selection and be collapsible
|
// Update Fountain Soda to require child selection and be collapsible
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET RequiresChildSelection = 1, IsCollapsible = 1
|
SET ItemRequiresChildSelection = 1, ItemIsCollapsible = 1
|
||||||
WHERE ItemID = :itemId
|
WHERE ItemID = :itemId
|
||||||
", { itemId: fountainId }, { datasource: "payfrit" });
|
", { itemId: fountainId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Check if modifiers already exist
|
// Check if modifiers already exist
|
||||||
qExisting = queryExecute("
|
qExisting = queryExecute("
|
||||||
SELECT COUNT(*) as cnt FROM Items WHERE ParentItemID = :parentId
|
SELECT COUNT(*) as cnt FROM Items WHERE ItemParentItemID = :parentId
|
||||||
", { parentId: fountainId }, { datasource: "payfrit" });
|
", { parentId: fountainId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qExisting.cnt > 0) {
|
if (qExisting.cnt > 0) {
|
||||||
|
|
@ -53,10 +53,10 @@ try {
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Items (
|
INSERT INTO Items (
|
||||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||||
Name, Description, Price, IsActive,
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||||
SortOrder, IsCollapsible, RequiresChildSelection,
|
ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection,
|
||||||
MaxNumSelectionReq, AddedOn
|
ItemMaxNumSelectionReq, ItemAddedOn
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:itemId, :bizId, 0, :parentId,
|
:itemId, :bizId, 0, :parentId,
|
||||||
'Size', 'Choose your size', 0, 1,
|
'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" });
|
qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Items (
|
INSERT INTO Items (
|
||||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||||
Name, Description, Price, IsActive,
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||||
SortOrder, IsCollapsible, IsCheckedByDefault,
|
ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault,
|
||||||
AddedOn
|
ItemAddedOn
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:itemId, :bizId, 0, :parentId,
|
:itemId, :bizId, 0, :parentId,
|
||||||
:name, '', :price, 1,
|
:name, '', :price, 1,
|
||||||
|
|
@ -108,10 +108,10 @@ try {
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Items (
|
INSERT INTO Items (
|
||||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||||
Name, Description, Price, IsActive,
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||||
SortOrder, IsCollapsible, RequiresChildSelection,
|
ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection,
|
||||||
MaxNumSelectionReq, AddedOn
|
ItemMaxNumSelectionReq, ItemAddedOn
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:itemId, :bizId, 0, :parentId,
|
:itemId, :bizId, 0, :parentId,
|
||||||
'Flavor', 'Choose your drink', 0, 1,
|
'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" });
|
qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Items (
|
INSERT INTO Items (
|
||||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||||
Name, Description, Price, IsActive,
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||||
SortOrder, IsCollapsible, IsCheckedByDefault,
|
ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault,
|
||||||
AddedOn
|
ItemAddedOn
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:itemId, :bizId, 0, :parentId,
|
:itemId, :bizId, 0, :parentId,
|
||||||
:name, '', 0, 1,
|
:name, '', 0, 1,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<cfscript>
|
<cfscript>
|
||||||
/**
|
/**
|
||||||
* Add CategoryID column to Items table
|
* Add ItemCategoryID column to Items table
|
||||||
*/
|
*/
|
||||||
|
|
||||||
response = { "OK": false };
|
response = { "OK": false };
|
||||||
|
|
@ -17,30 +17,30 @@ try {
|
||||||
FROM INFORMATION_SCHEMA.COLUMNS
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
WHERE TABLE_SCHEMA = 'payfrit'
|
WHERE TABLE_SCHEMA = 'payfrit'
|
||||||
AND TABLE_NAME = 'Items'
|
AND TABLE_NAME = 'Items'
|
||||||
AND COLUMN_NAME = 'CategoryID'
|
AND COLUMN_NAME = 'ItemCategoryID'
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qCheck.recordCount > 0) {
|
if (qCheck.recordCount > 0) {
|
||||||
response["OK"] = true;
|
response["OK"] = true;
|
||||||
response["MESSAGE"] = "CategoryID column already exists";
|
response["MESSAGE"] = "ItemCategoryID column already exists";
|
||||||
} else {
|
} else {
|
||||||
// Add the column
|
// Add the column
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Items
|
ALTER TABLE Items
|
||||||
ADD COLUMN CategoryID INT NULL DEFAULT 0 AFTER ParentItemID
|
ADD COLUMN ItemCategoryID INT NULL DEFAULT 0 AFTER ItemParentItemID
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Add index for performance
|
// Add index for performance
|
||||||
try {
|
try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
CREATE INDEX idx_items_categoryid ON Items(CategoryID)
|
CREATE INDEX idx_items_categoryid ON Items(ItemCategoryID)
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
} catch (any indexErr) {
|
} catch (any indexErr) {
|
||||||
// Index might already exist
|
// Index might already exist
|
||||||
}
|
}
|
||||||
|
|
||||||
response["OK"] = true;
|
response["OK"] = true;
|
||||||
response["MESSAGE"] = "CategoryID column added successfully";
|
response["MESSAGE"] = "ItemCategoryID column added successfully";
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
try {
|
try {
|
||||||
// Check if columns already exist
|
// Check if columns already exist
|
||||||
checkCols = queryExecute(
|
checkCols = queryExecute(
|
||||||
"SHOW COLUMNS FROM Addresses LIKE 'Latitude'",
|
"SHOW COLUMNS FROM Addresses LIKE 'AddressLat'",
|
||||||
[],
|
[],
|
||||||
{ datasource = "payfrit" }
|
{ datasource = "payfrit" }
|
||||||
);
|
);
|
||||||
|
|
@ -15,8 +15,8 @@ try {
|
||||||
// Add the columns
|
// Add the columns
|
||||||
queryExecute(
|
queryExecute(
|
||||||
"ALTER TABLE Addresses
|
"ALTER TABLE Addresses
|
||||||
ADD COLUMN Latitude DECIMAL(10,7) NULL,
|
ADD COLUMN AddressLat DECIMAL(10,7) NULL,
|
||||||
ADD COLUMN Longitude DECIMAL(10,7) NULL",
|
ADD COLUMN AddressLng DECIMAL(10,7) NULL",
|
||||||
[],
|
[],
|
||||||
{ datasource = "payfrit" }
|
{ datasource = "payfrit" }
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
||||||
|
|
||||||
<cfscript>
|
|
||||||
// Add CategoryID column to tt_TaskTypes (Services) table
|
|
||||||
try {
|
|
||||||
// Check if column exists
|
|
||||||
qCheck = queryExecute("
|
|
||||||
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = 'payfrit'
|
|
||||||
AND TABLE_NAME = 'tt_TaskTypes'
|
|
||||||
AND COLUMN_NAME = 'TaskCategoryID'
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
if (qCheck.recordCount == 0) {
|
|
||||||
queryExecute("
|
|
||||||
ALTER TABLE tt_TaskTypes
|
|
||||||
ADD COLUMN TaskCategoryID INT NULL
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"MESSAGE": "Column TaskCategoryID added to tt_TaskTypes"
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"MESSAGE": "Column already exists"
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} catch (any e) {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": false,
|
|
||||||
"ERROR": e.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||||
|
|
||||||
<cfscript>
|
<cfscript>
|
||||||
// Add SourceType and SourceID columns to Tasks table
|
// Add TaskSourceType and TaskSourceID columns to Tasks table
|
||||||
// These are needed for chat persistence feature
|
// These are needed for chat persistence feature
|
||||||
|
|
||||||
result = { "OK": true, "STEPS": [] };
|
result = { "OK": true, "STEPS": [] };
|
||||||
|
|
@ -15,30 +15,30 @@ try {
|
||||||
FROM INFORMATION_SCHEMA.COLUMNS
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
WHERE TABLE_SCHEMA = 'payfrit'
|
WHERE TABLE_SCHEMA = 'payfrit'
|
||||||
AND TABLE_NAME = 'Tasks'
|
AND TABLE_NAME = 'Tasks'
|
||||||
AND COLUMN_NAME IN ('SourceType', 'SourceID')
|
AND COLUMN_NAME IN ('TaskSourceType', 'TaskSourceID')
|
||||||
", [], { datasource: "payfrit" });
|
", [], { datasource: "payfrit" });
|
||||||
|
|
||||||
existingCols = valueList(cols.COLUMN_NAME);
|
existingCols = valueList(cols.COLUMN_NAME);
|
||||||
arrayAppend(result.STEPS, "Existing columns: #existingCols#");
|
arrayAppend(result.STEPS, "Existing columns: #existingCols#");
|
||||||
|
|
||||||
// Add SourceType if missing
|
// Add TaskSourceType if missing
|
||||||
if (!listFindNoCase(existingCols, "SourceType")) {
|
if (!listFindNoCase(existingCols, "TaskSourceType")) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Tasks ADD COLUMN SourceType VARCHAR(50) NULL
|
ALTER TABLE Tasks ADD COLUMN TaskSourceType VARCHAR(50) NULL
|
||||||
", [], { datasource: "payfrit" });
|
", [], { datasource: "payfrit" });
|
||||||
arrayAppend(result.STEPS, "Added SourceType column");
|
arrayAppend(result.STEPS, "Added TaskSourceType column");
|
||||||
} else {
|
} else {
|
||||||
arrayAppend(result.STEPS, "SourceType already exists");
|
arrayAppend(result.STEPS, "TaskSourceType already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add SourceID if missing
|
// Add TaskSourceID if missing
|
||||||
if (!listFindNoCase(existingCols, "SourceID")) {
|
if (!listFindNoCase(existingCols, "TaskSourceID")) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Tasks ADD COLUMN SourceID INT NULL
|
ALTER TABLE Tasks ADD COLUMN TaskSourceID INT NULL
|
||||||
", [], { datasource: "payfrit" });
|
", [], { datasource: "payfrit" });
|
||||||
arrayAppend(result.STEPS, "Added SourceID column");
|
arrayAppend(result.STEPS, "Added TaskSourceID column");
|
||||||
} else {
|
} else {
|
||||||
arrayAppend(result.STEPS, "SourceID already exists");
|
arrayAppend(result.STEPS, "TaskSourceID already exists");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify columns now exist
|
// Verify columns now exist
|
||||||
|
|
@ -47,7 +47,7 @@ try {
|
||||||
FROM INFORMATION_SCHEMA.COLUMNS
|
FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
WHERE TABLE_SCHEMA = 'payfrit'
|
WHERE TABLE_SCHEMA = 'payfrit'
|
||||||
AND TABLE_NAME = 'Tasks'
|
AND TABLE_NAME = 'Tasks'
|
||||||
AND COLUMN_NAME IN ('SourceType', 'SourceID')
|
AND COLUMN_NAME IN ('TaskSourceType', 'TaskSourceID')
|
||||||
", [], { datasource: "payfrit" });
|
", [], { datasource: "payfrit" });
|
||||||
|
|
||||||
result.COLUMNS = [];
|
result.COLUMNS = [];
|
||||||
|
|
|
||||||
|
|
@ -6,49 +6,49 @@
|
||||||
// Show all beacons with their current business/service point assignments
|
// Show all beacons with their current business/service point assignments
|
||||||
q = queryExecute("
|
q = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
b.ID,
|
b.BeaconID,
|
||||||
b.UUID,
|
b.BeaconUUID,
|
||||||
b.Name,
|
b.BeaconName,
|
||||||
sp_link.BusinessID,
|
lt.BusinessID,
|
||||||
sp_link.ID,
|
lt.ServicePointID,
|
||||||
biz.Name,
|
biz.BusinessName,
|
||||||
sp.Name
|
sp.ServicePointName
|
||||||
FROM Beacons b
|
FROM Beacons b
|
||||||
LEFT JOIN ServicePoints sp_link ON sp_link.BeaconID = b.ID
|
LEFT JOIN lt_Beacon_Businesses_ServicePoints lt ON lt.BeaconID = b.BeaconID
|
||||||
LEFT JOIN Businesses biz ON biz.ID = sp_link.BusinessID
|
LEFT JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||||
LEFT JOIN ServicePoints sp ON sp.ID = sp_link.ID
|
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||||
WHERE b.IsActive = 1
|
WHERE b.BeaconIsActive = 1
|
||||||
ORDER BY b.ID
|
ORDER BY b.BeaconID
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
rows = [];
|
rows = [];
|
||||||
for (row in q) {
|
for (row in q) {
|
||||||
arrayAppend(rows, {
|
arrayAppend(rows, {
|
||||||
"BeaconID": row.ID,
|
"BeaconID": row.BeaconID,
|
||||||
"UUID": row.UUID,
|
"BeaconUUID": row.BeaconUUID,
|
||||||
"Name": row.Name ?: "",
|
"BeaconName": row.BeaconName ?: "",
|
||||||
"BusinessID": row.BusinessID ?: 0,
|
"BusinessID": row.BusinessID ?: 0,
|
||||||
"Name": row.Name ?: "",
|
"BusinessName": row.BusinessName ?: "",
|
||||||
"ServicePointID": row.ServicePointID ?: 0,
|
"ServicePointID": row.ServicePointID ?: 0,
|
||||||
"Name": row.Name ?: ""
|
"ServicePointName": row.ServicePointName ?: ""
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also get service points for reference
|
// Also get service points for reference
|
||||||
spQuery = queryExecute("
|
spQuery = queryExecute("
|
||||||
SELECT sp.ID, sp.Name, sp.BusinessID, b.Name
|
SELECT sp.ServicePointID, sp.ServicePointName, sp.ServicePointBusinessID, b.BusinessName
|
||||||
FROM ServicePoints sp
|
FROM ServicePoints sp
|
||||||
JOIN Businesses b ON b.ID = sp.BusinessID
|
JOIN Businesses b ON b.BusinessID = sp.ServicePointBusinessID
|
||||||
ORDER BY sp.BusinessID, sp.ID
|
ORDER BY sp.ServicePointBusinessID, sp.ServicePointID
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
servicePoints = [];
|
servicePoints = [];
|
||||||
for (sp in spQuery) {
|
for (sp in spQuery) {
|
||||||
arrayAppend(servicePoints, {
|
arrayAppend(servicePoints, {
|
||||||
"ServicePointID": sp.ID,
|
"ServicePointID": sp.ServicePointID,
|
||||||
"Name": sp.Name,
|
"ServicePointName": sp.ServicePointName,
|
||||||
"BusinessID": sp.BusinessID,
|
"BusinessID": sp.ServicePointBusinessID,
|
||||||
"Name": sp.Name
|
"BusinessName": sp.BusinessName
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,16 @@
|
||||||
<cfscript>
|
<cfscript>
|
||||||
// Check Big Dean's owner
|
// Check Big Dean's owner
|
||||||
q = queryExecute("
|
q = queryExecute("
|
||||||
SELECT b.ID, b.Name, b.UserID
|
SELECT b.BusinessID, b.BusinessName, b.BusinessUserID
|
||||||
FROM Businesses b
|
FROM Businesses b
|
||||||
WHERE b.ID = 27
|
WHERE b.BusinessID = 27
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Get users
|
// Get users
|
||||||
users = queryExecute("
|
users = queryExecute("
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM Users
|
FROM Users
|
||||||
ORDER BY ID
|
ORDER BY UserID
|
||||||
LIMIT 20
|
LIMIT 20
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
|
|
@ -23,9 +23,9 @@ colNames = users.getColumnNames();
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"BigDeans": {
|
"BigDeans": {
|
||||||
"BusinessID": q.ID,
|
"BusinessID": q.BusinessID,
|
||||||
"Name": q.Name,
|
"BusinessName": q.BusinessName,
|
||||||
"UserID": q.UserID
|
"BusinessUserID": q.BusinessUserID
|
||||||
},
|
},
|
||||||
"UserColumns": colNames,
|
"UserColumns": colNames,
|
||||||
"UserCount": users.recordCount
|
"UserCount": users.recordCount
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ if (!len(phone)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
q = queryExecute("
|
q = queryExecute("
|
||||||
SELECT ID, FirstName, LastName, EmailAddress, ContactNumber, IsContactVerified
|
SELECT UserID, UserFirstName, UserLastName, UserEmail, UserPhone, UserIsContactVerified
|
||||||
FROM Users
|
FROM Users
|
||||||
WHERE ContactNumber = :phone OR EmailAddress = :phone
|
WHERE UserPhone = :phone OR UserEmail = :phone
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
", { phone: phone }, { datasource: "payfrit" });
|
", { phone: phone }, { datasource: "payfrit" });
|
||||||
|
|
||||||
|
|
@ -25,11 +25,11 @@ if (q.recordCount EQ 0) {
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"UserID": q.ID,
|
"UserID": q.UserID,
|
||||||
"FirstName": q.FirstName,
|
"FirstName": q.UserFirstName,
|
||||||
"LastName": q.LastName,
|
"LastName": q.UserLastName,
|
||||||
"Email": q.EmailAddress,
|
"Email": q.UserEmail,
|
||||||
"Phone": q.ContactNumber,
|
"Phone": q.UserPhone,
|
||||||
"Verified": q.IsContactVerified
|
"Verified": q.UserIsContactVerified
|
||||||
}));
|
}));
|
||||||
</cfscript>
|
</cfscript>
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@
|
||||||
<cfscript>
|
<cfscript>
|
||||||
/**
|
/**
|
||||||
* Cleanup Lazy Daisy Beacons
|
* Cleanup Lazy Daisy Beacons
|
||||||
* - Unassigns beacons 7, 8, 9 from service points
|
* - Removes duplicate beacons created by setupBeaconTables
|
||||||
* - Deletes beacons 7, 8, 9
|
|
||||||
* - Updates original beacons with proper names
|
* - Updates original beacons with proper names
|
||||||
*/
|
*/
|
||||||
response = { "OK": false, "steps": [] };
|
response = { "OK": false, "steps": [] };
|
||||||
|
|
@ -14,50 +13,52 @@ response = { "OK": false, "steps": [] };
|
||||||
try {
|
try {
|
||||||
lazyDaisyID = 37;
|
lazyDaisyID = 37;
|
||||||
|
|
||||||
// Unassign beacons 7, 8, 9 from any service points
|
// Delete duplicate assignments for beacons 7, 8, 9
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE ServicePoints
|
DELETE FROM lt_Beacon_Businesses_ServicePoints
|
||||||
SET BeaconID = NULL, AssignedByUserID = NULL
|
|
||||||
WHERE BeaconID IN (7, 8, 9) AND BusinessID = :bizId
|
WHERE BeaconID IN (7, 8, 9) AND BusinessID = :bizId
|
||||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Unassigned beacons 7, 8, 9 from service points");
|
response.steps.append("Deleted duplicate assignments for beacons 7, 8, 9");
|
||||||
|
|
||||||
// Delete duplicate beacons 7, 8, 9
|
// Delete duplicate beacons 7, 8, 9
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM Beacons
|
DELETE FROM Beacons
|
||||||
WHERE ID IN (7, 8, 9) AND BusinessID = :bizId
|
WHERE BeaconID IN (7, 8, 9) AND BeaconBusinessID = :bizId
|
||||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Deleted duplicate beacons 7, 8, 9");
|
response.steps.append("Deleted duplicate beacons 7, 8, 9");
|
||||||
|
|
||||||
// Update original beacons with names based on their service point assignments
|
// 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("
|
queryExecute("
|
||||||
UPDATE Beacons SET Name = 'Beacon - Table 1'
|
UPDATE Beacons SET BeaconName = 'Beacon - Table 1'
|
||||||
WHERE ID = 4 AND BusinessID = :bizId
|
WHERE BeaconID = 4 AND BeaconBusinessID = :bizId
|
||||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Updated Beacon 4 name to 'Beacon - Table 1'");
|
response.steps.append("Updated Beacon 4 name to 'Beacon - Table 1'");
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Beacons SET Name = 'Beacon - Table 2'
|
UPDATE Beacons SET BeaconName = 'Beacon - Table 2'
|
||||||
WHERE ID = 5 AND BusinessID = :bizId
|
WHERE BeaconID = 5 AND BeaconBusinessID = :bizId
|
||||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Updated Beacon 5 name to 'Beacon - Table 2'");
|
response.steps.append("Updated Beacon 5 name to 'Beacon - Table 2'");
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Beacons SET Name = 'Beacon - Table 3'
|
UPDATE Beacons SET BeaconName = 'Beacon - Table 3'
|
||||||
WHERE ID = 6 AND BusinessID = :bizId
|
WHERE BeaconID = 6 AND BeaconBusinessID = :bizId
|
||||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Updated Beacon 6 name to 'Beacon - Table 3'");
|
response.steps.append("Updated Beacon 6 name to 'Beacon - Table 3'");
|
||||||
|
|
||||||
// Get final status
|
// Get final status
|
||||||
qFinal = queryExecute("
|
qFinal = queryExecute("
|
||||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
SELECT lt.BeaconID, b.BeaconUUID, b.BeaconName, lt.BusinessID, biz.BusinessName, lt.ServicePointID, sp.ServicePointName
|
||||||
b.Name AS BeaconName, b.UUID, sp.Name AS ServicePointName,
|
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||||
biz.Name AS BusinessName
|
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||||
FROM ServicePoints sp
|
JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
WHERE lt.BusinessID = :bizId
|
||||||
WHERE sp.BusinessID = :bizId AND sp.BeaconID IS NOT NULL
|
ORDER BY lt.BeaconID
|
||||||
ORDER BY sp.BeaconID
|
|
||||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
beacons = [];
|
beacons = [];
|
||||||
|
|
@ -65,9 +66,8 @@ try {
|
||||||
arrayAppend(beacons, {
|
arrayAppend(beacons, {
|
||||||
"BeaconID": qFinal.BeaconID[i],
|
"BeaconID": qFinal.BeaconID[i],
|
||||||
"BeaconName": qFinal.BeaconName[i],
|
"BeaconName": qFinal.BeaconName[i],
|
||||||
"UUID": qFinal.UUID[i],
|
"UUID": qFinal.BeaconUUID[i],
|
||||||
"BusinessName": qFinal.BusinessName[i],
|
"BusinessName": qFinal.BusinessName[i],
|
||||||
"ServicePointID": qFinal.ServicePointID[i],
|
|
||||||
"ServicePointName": qFinal.ServicePointName[i]
|
"ServicePointName": qFinal.ServicePointName[i]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@
|
||||||
* Cleanup Categories - Final step after migration verification
|
* Cleanup Categories - Final step after migration verification
|
||||||
*
|
*
|
||||||
* This script:
|
* This script:
|
||||||
* 1. Verifies all Items have BusinessID set
|
* 1. Verifies all Items have ItemBusinessID set
|
||||||
* 2. Finds orphan items (ParentID=0, no children, not in links)
|
* 2. Finds orphan items (ParentID=0, no children, not in links)
|
||||||
* 3. Drops CategoryID column
|
* 3. Drops ItemCategoryID column
|
||||||
* 4. Drops IsModifierTemplate column (derived from lt_ItemID_TemplateItemID now)
|
* 4. Drops ItemIsModifierTemplate column (derived from ItemTemplateLinks now)
|
||||||
* 5. Drops Categories table
|
* 5. Drops Categories table
|
||||||
*
|
*
|
||||||
* Query param: ?confirm=YES to actually execute (otherwise shows verification only)
|
* Query param: ?confirm=YES to actually execute (otherwise shows verification only)
|
||||||
|
|
@ -30,7 +30,7 @@ try {
|
||||||
// Verification Step 1: Check for items without BusinessID
|
// Verification Step 1: Check for items without BusinessID
|
||||||
qNoBusinessID = queryExecute("
|
qNoBusinessID = queryExecute("
|
||||||
SELECT COUNT(*) as cnt FROM Items
|
SELECT COUNT(*) as cnt FROM Items
|
||||||
WHERE BusinessID IS NULL OR BusinessID = 0
|
WHERE ItemBusinessID IS NULL OR ItemBusinessID = 0
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
response.verification["itemsWithoutBusinessID"] = qNoBusinessID.cnt;
|
response.verification["itemsWithoutBusinessID"] = qNoBusinessID.cnt;
|
||||||
|
|
@ -46,38 +46,38 @@ try {
|
||||||
qCategoryItems = queryExecute("
|
qCategoryItems = queryExecute("
|
||||||
SELECT COUNT(DISTINCT p.ItemID) as cnt
|
SELECT COUNT(DISTINCT p.ItemID) as cnt
|
||||||
FROM Items p
|
FROM Items p
|
||||||
INNER JOIN Items c ON c.ParentItemID = p.ItemID
|
INNER JOIN Items c ON c.ItemParentItemID = p.ItemID
|
||||||
WHERE p.ParentItemID = 0
|
WHERE p.ItemParentItemID = 0
|
||||||
AND p.BusinessID > 0
|
AND p.ItemBusinessID > 0
|
||||||
AND NOT EXISTS (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = p.ItemID
|
SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = p.ItemID
|
||||||
)
|
)
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
response.verification["categoryItemsCreated"] = qCategoryItems.cnt;
|
response.verification["categoryItemsCreated"] = qCategoryItems.cnt;
|
||||||
|
|
||||||
// Verification Step 4: Check templates exist (in lt_ItemID_TemplateItemID)
|
// Verification Step 4: Check templates exist (in ItemTemplateLinks)
|
||||||
qTemplates = queryExecute("
|
qTemplates = queryExecute("
|
||||||
SELECT COUNT(DISTINCT tl.TemplateItemID) as cnt
|
SELECT COUNT(DISTINCT tl.TemplateItemID) as cnt
|
||||||
FROM lt_ItemID_TemplateItemID tl
|
FROM ItemTemplateLinks tl
|
||||||
INNER JOIN Items t ON t.ItemID = tl.TemplateItemID
|
INNER JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
response.verification["templatesInLinks"] = qTemplates.cnt;
|
response.verification["templatesInLinks"] = qTemplates.cnt;
|
||||||
|
|
||||||
// Verification Step 5: Find orphans at ParentID=0
|
// Verification Step 5: Find orphans at ParentID=0
|
||||||
// Orphan = ParentID=0, no children pointing to it, not in lt_ItemID_TemplateItemID
|
// Orphan = ParentID=0, no children pointing to it, not in ItemTemplateLinks
|
||||||
qOrphans = queryExecute("
|
qOrphans = queryExecute("
|
||||||
SELECT i.ID, i.Name, i.BusinessID
|
SELECT i.ItemID, i.ItemName, i.ItemBusinessID
|
||||||
FROM Items i
|
FROM Items i
|
||||||
WHERE i.ParentItemID = 0
|
WHERE i.ItemParentItemID = 0
|
||||||
AND NOT EXISTS (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM Items child WHERE child.ParentItemID = i.ID
|
SELECT 1 FROM Items child WHERE child.ItemParentItemID = i.ItemID
|
||||||
)
|
)
|
||||||
AND NOT EXISTS (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = i.ID
|
SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = i.ItemID
|
||||||
)
|
)
|
||||||
ORDER BY i.BusinessID, i.Name
|
ORDER BY i.ItemBusinessID, i.ItemName
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
response.verification["orphanCount"] = qOrphans.recordCount;
|
response.verification["orphanCount"] = qOrphans.recordCount;
|
||||||
|
|
@ -85,8 +85,8 @@ try {
|
||||||
for (orphan in qOrphans) {
|
for (orphan in qOrphans) {
|
||||||
arrayAppend(response.orphans, {
|
arrayAppend(response.orphans, {
|
||||||
"ItemID": orphan.ItemID,
|
"ItemID": orphan.ItemID,
|
||||||
"Name": orphan.Name,
|
"ItemName": orphan.ItemName,
|
||||||
"BusinessID": orphan.BusinessID
|
"BusinessID": orphan.ItemBusinessID
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,7 +96,7 @@ try {
|
||||||
|
|
||||||
if (!safeToCleanup) {
|
if (!safeToCleanup) {
|
||||||
arrayAppend(response.steps, "VERIFICATION FAILED - Cannot cleanup yet");
|
arrayAppend(response.steps, "VERIFICATION FAILED - Cannot cleanup yet");
|
||||||
arrayAppend(response.steps, "- " & qNoBusinessID.cnt & " items still missing BusinessID");
|
arrayAppend(response.steps, "- " & qNoBusinessID.cnt & " items still missing ItemBusinessID");
|
||||||
response["OK"] = false;
|
response["OK"] = false;
|
||||||
writeOutput(serializeJSON(response));
|
writeOutput(serializeJSON(response));
|
||||||
abort;
|
abort;
|
||||||
|
|
@ -119,31 +119,31 @@ try {
|
||||||
// Execute cleanup
|
// Execute cleanup
|
||||||
arrayAppend(response.steps, "Executing cleanup...");
|
arrayAppend(response.steps, "Executing cleanup...");
|
||||||
|
|
||||||
// Step 1: Drop CategoryID column
|
// Step 1: Drop ItemCategoryID column
|
||||||
try {
|
try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Items DROP COLUMN CategoryID
|
ALTER TABLE Items DROP COLUMN ItemCategoryID
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
arrayAppend(response.steps, "Dropped CategoryID column from Items");
|
arrayAppend(response.steps, "Dropped ItemCategoryID column from Items");
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
if (findNoCase("check that column", e.message) || findNoCase("Unknown column", e.message)) {
|
if (findNoCase("check that column", e.message) || findNoCase("Unknown column", e.message)) {
|
||||||
arrayAppend(response.steps, "CategoryID column already dropped");
|
arrayAppend(response.steps, "ItemCategoryID column already dropped");
|
||||||
} else {
|
} else {
|
||||||
arrayAppend(response.steps, "Warning dropping CategoryID: " & e.message);
|
arrayAppend(response.steps, "Warning dropping ItemCategoryID: " & e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Drop IsModifierTemplate column (now derived from lt_ItemID_TemplateItemID)
|
// Step 2: Drop ItemIsModifierTemplate column (now derived from ItemTemplateLinks)
|
||||||
try {
|
try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Items DROP COLUMN IsModifierTemplate
|
ALTER TABLE Items DROP COLUMN ItemIsModifierTemplate
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
arrayAppend(response.steps, "Dropped IsModifierTemplate column from Items");
|
arrayAppend(response.steps, "Dropped ItemIsModifierTemplate column from Items");
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
if (findNoCase("check that column", e.message) || findNoCase("Unknown column", e.message)) {
|
if (findNoCase("check that column", e.message) || findNoCase("Unknown column", e.message)) {
|
||||||
arrayAppend(response.steps, "IsModifierTemplate column already dropped");
|
arrayAppend(response.steps, "ItemIsModifierTemplate column already dropped");
|
||||||
} else {
|
} else {
|
||||||
arrayAppend(response.steps, "Warning dropping IsModifierTemplate: " & e.message);
|
arrayAppend(response.steps, "Warning dropping ItemIsModifierTemplate: " & e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ if (businessId <= 0) {
|
||||||
try {
|
try {
|
||||||
// Find duplicate UserIDs for this business (keep the one with highest status or oldest)
|
// Find duplicate UserIDs for this business (keep the one with highest status or oldest)
|
||||||
qDupes = queryExecute("
|
qDupes = queryExecute("
|
||||||
SELECT ID, COUNT(*) as cnt, MIN(ID) as keepId
|
SELECT UserID, COUNT(*) as cnt, MIN(EmployeeID) as keepId
|
||||||
FROM Employees
|
FROM lt_Users_Businesses_Employees
|
||||||
WHERE BusinessID = ?
|
WHERE BusinessID = ?
|
||||||
GROUP BY UserID
|
GROUP BY UserID
|
||||||
HAVING COUNT(*) > 1
|
HAVING COUNT(*) > 1
|
||||||
|
|
@ -45,8 +45,8 @@ try {
|
||||||
for (row in qDupes) {
|
for (row in qDupes) {
|
||||||
// Delete all but the one we want to keep (the one with lowest EmployeeID)
|
// Delete all but the one we want to keep (the one with lowest EmployeeID)
|
||||||
qDel = queryExecute("
|
qDel = queryExecute("
|
||||||
DELETE FROM Employees
|
DELETE FROM lt_Users_Businesses_Employees
|
||||||
WHERE BusinessID = ? AND UserID = ? AND ID != ?
|
WHERE BusinessID = ? AND UserID = ? AND EmployeeID != ?
|
||||||
", [
|
", [
|
||||||
{ value: businessId, cfsqltype: "cf_sql_integer" },
|
{ value: businessId, cfsqltype: "cf_sql_integer" },
|
||||||
{ value: row.UserID, cfsqltype: "cf_sql_integer" },
|
{ value: row.UserID, cfsqltype: "cf_sql_integer" },
|
||||||
|
|
@ -57,19 +57,19 @@ try {
|
||||||
|
|
||||||
// Get remaining employees
|
// Get remaining employees
|
||||||
qRemaining = queryExecute("
|
qRemaining = queryExecute("
|
||||||
SELECT e.ID, e.UserID, u.FirstName, u.LastName
|
SELECT e.EmployeeID, e.UserID, u.UserFirstName, u.UserLastName
|
||||||
FROM Employees e
|
FROM lt_Users_Businesses_Employees e
|
||||||
JOIN Users u ON e.UserID = u.ID
|
JOIN Users u ON e.UserID = u.UserID
|
||||||
WHERE e.BusinessID = ?
|
WHERE e.BusinessID = ?
|
||||||
ORDER BY e.ID
|
ORDER BY e.EmployeeID
|
||||||
", [{ value: businessId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
", [{ value: businessId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
||||||
|
|
||||||
remaining = [];
|
remaining = [];
|
||||||
for (r in qRemaining) {
|
for (r in qRemaining) {
|
||||||
arrayAppend(remaining, {
|
arrayAppend(remaining, {
|
||||||
"EmployeeID": r.ID,
|
"EmployeeID": r.EmployeeID,
|
||||||
"UserID": r.UserID,
|
"UserID": r.UserID,
|
||||||
"Name": trim(r.FirstName & " " & r.LastName)
|
"Name": trim(r.UserFirstName & " " & r.UserLastName)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,120 +9,106 @@ try {
|
||||||
// Keep only Lazy Daisy (BusinessID 37)
|
// Keep only Lazy Daisy (BusinessID 37)
|
||||||
keepBusinessID = 37;
|
keepBusinessID = 37;
|
||||||
|
|
||||||
// Unassign all beacons from service points of other businesses
|
// First, reassign all beacons to Lazy Daisy
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE ServicePoints
|
UPDATE lt_Beacon_Businesses_ServicePoints
|
||||||
SET BeaconID = NULL, AssignedByUserID = NULL
|
SET BusinessID = :keepID
|
||||||
WHERE BusinessID != :keepID AND BeaconID IS NOT NULL
|
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Unassigned beacons from other businesses' service points");
|
response.steps.append("Reassigned all beacons to Lazy Daisy");
|
||||||
|
|
||||||
// Get list of businesses to delete
|
// Get list of businesses to delete
|
||||||
qBiz = queryExecute("
|
qBiz = queryExecute("
|
||||||
SELECT ID, Name FROM Businesses WHERE ID != :keepID
|
SELECT BusinessID, BusinessName FROM Businesses WHERE BusinessID != :keepID
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
deletedBusinesses = [];
|
deletedBusinesses = [];
|
||||||
for (i = 1; i <= qBiz.recordCount; i++) {
|
for (i = 1; i <= qBiz.recordCount; i++) {
|
||||||
arrayAppend(deletedBusinesses, qBiz.Name[i]);
|
arrayAppend(deletedBusinesses, qBiz.BusinessName[i]);
|
||||||
}
|
}
|
||||||
response.steps.append("Found " & qBiz.recordCount & " businesses to delete");
|
response.steps.append("Found " & qBiz.recordCount & " businesses to delete");
|
||||||
|
|
||||||
// Delete related data first (foreign key constraints)
|
// Delete related data first (foreign key constraints)
|
||||||
// Delete lt_ItemID_TemplateItemID for items from other businesses
|
// Delete ItemTemplateLinks for items from other businesses
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE itl FROM lt_ItemID_TemplateItemID itl
|
DELETE itl FROM ItemTemplateLinks itl
|
||||||
JOIN Items i ON i.ID = itl.ItemID
|
JOIN Items i ON i.ItemID = itl.ItemID
|
||||||
WHERE i.BusinessID != :keepID
|
WHERE i.ItemBusinessID != :keepID
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Deleted lt_ItemID_TemplateItemID for other businesses");
|
response.steps.append("Deleted ItemTemplateLinks for other businesses");
|
||||||
|
|
||||||
// Delete Items for other businesses
|
// Delete Items for other businesses
|
||||||
qItems = queryExecute("
|
qItems = queryExecute("
|
||||||
SELECT COUNT(*) as cnt FROM Items WHERE BusinessID != :keepID
|
SELECT COUNT(*) as cnt FROM Items WHERE ItemBusinessID != :keepID
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM Items WHERE BusinessID != :keepID
|
DELETE FROM Items WHERE ItemBusinessID != :keepID
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Deleted " & qItems.cnt & " items from other businesses");
|
response.steps.append("Deleted " & qItems.cnt & " items from other businesses");
|
||||||
|
|
||||||
// Delete Categories for other businesses
|
// Delete Categories for other businesses
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM Categories WHERE BusinessID != :keepID
|
DELETE FROM Categories WHERE CategoryBusinessID != :keepID
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Deleted categories from other businesses");
|
response.steps.append("Deleted categories from other businesses");
|
||||||
|
|
||||||
// Delete Hours for other businesses
|
// Delete Hours for other businesses
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM Hours WHERE BusinessID != :keepID
|
DELETE FROM Hours WHERE HoursBusinessID != :keepID
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Deleted hours from other businesses");
|
response.steps.append("Deleted hours from other businesses");
|
||||||
|
|
||||||
// Delete Employees for other businesses
|
// Delete Employees for other businesses (skip if table doesn't exist)
|
||||||
try {
|
try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM Employees WHERE BusinessID != :keepID
|
DELETE FROM Employees WHERE EmployeeBusinessID != :keepID
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Deleted employees from other businesses");
|
response.steps.append("Deleted employees from other businesses");
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
response.steps.append("Skipped employees (table may not exist)");
|
response.steps.append("Skipped employees (table may not exist)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete ServicePoints for other businesses
|
// Delete ServicePoints for other businesses (skip if table doesn't exist)
|
||||||
try {
|
try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM ServicePoints WHERE BusinessID != :keepID
|
DELETE FROM ServicePoints WHERE ServicePointBusinessID != :keepID
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Deleted service points from other businesses");
|
response.steps.append("Deleted service points from other businesses");
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
response.steps.append("Skipped service points (table may not exist)");
|
response.steps.append("Skipped service points (table may not exist)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete Stations for other businesses
|
// Delete Stations for other businesses (skip if table doesn't exist)
|
||||||
try {
|
try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM Stations WHERE BusinessID != :keepID
|
DELETE FROM Stations WHERE StationBusinessID != :keepID
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Deleted stations from other businesses");
|
response.steps.append("Deleted stations from other businesses");
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
response.steps.append("Skipped stations (table may not exist)");
|
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
|
// Finally delete the businesses themselves
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM Businesses WHERE ID != :keepID
|
DELETE FROM Businesses WHERE BusinessID != :keepID
|
||||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Deleted " & arrayLen(deletedBusinesses) & " businesses");
|
response.steps.append("Deleted " & arrayLen(deletedBusinesses) & " businesses");
|
||||||
|
|
||||||
// Get beacon status
|
// Get beacon status
|
||||||
qBeacons = queryExecute("
|
qBeacons = queryExecute("
|
||||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
SELECT lt.BeaconID, b.BeaconUUID, lt.BusinessID, biz.BusinessName, lt.ServicePointID
|
||||||
b.UUID, biz.Name AS BusinessName, sp.Name AS ServicePointName
|
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||||
FROM ServicePoints sp
|
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
|
||||||
WHERE sp.BeaconID IS NOT NULL
|
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
beacons = [];
|
beacons = [];
|
||||||
for (i = 1; i <= qBeacons.recordCount; i++) {
|
for (i = 1; i <= qBeacons.recordCount; i++) {
|
||||||
arrayAppend(beacons, {
|
arrayAppend(beacons, {
|
||||||
"BeaconID": qBeacons.BeaconID[i],
|
"BeaconID": qBeacons.BeaconID[i],
|
||||||
"UUID": qBeacons.UUID[i],
|
"UUID": qBeacons.BeaconUUID[i],
|
||||||
"BusinessID": qBeacons.BusinessID[i],
|
"BusinessID": qBeacons.BusinessID[i],
|
||||||
"BusinessName": qBeacons.BusinessName[i],
|
"BusinessName": qBeacons.BusinessName[i],
|
||||||
"ServicePointID": qBeacons.ServicePointID[i],
|
"ServicePointID": qBeacons.ServicePointID[i]
|
||||||
"ServicePointName": qBeacons.ServicePointName[i]
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ param name="url.action" default="check"; // "check" or "deactivate"
|
||||||
|
|
||||||
// Check the item first
|
// Check the item first
|
||||||
qItem = queryExecute("
|
qItem = queryExecute("
|
||||||
SELECT ID, Name, ParentItemID, IsActive, IsCollapsible
|
SELECT ItemID, ItemName, ItemParentItemID, ItemIsActive, ItemIsCollapsible
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE ID = :itemId
|
WHERE ItemID = :itemId
|
||||||
", { itemId: url.itemId });
|
", { itemId: url.itemId });
|
||||||
|
|
||||||
if (qItem.recordCount == 0) {
|
if (qItem.recordCount == 0) {
|
||||||
|
|
@ -19,25 +19,25 @@ if (qItem.recordCount == 0) {
|
||||||
|
|
||||||
// Get all children (direct only for display)
|
// Get all children (direct only for display)
|
||||||
qChildren = queryExecute("
|
qChildren = queryExecute("
|
||||||
SELECT ID, Name
|
SELECT ItemID, ItemName
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE ParentItemID = :itemId
|
WHERE ItemParentItemID = :itemId
|
||||||
", { itemId: url.itemId });
|
", { itemId: url.itemId });
|
||||||
|
|
||||||
childList = [];
|
childList = [];
|
||||||
for (row in qChildren) {
|
for (row in qChildren) {
|
||||||
arrayAppend(childList, { "ItemID": row.ID, "Name": row.Name });
|
arrayAppend(childList, { "ItemID": row.ItemID, "ItemName": row.ItemName });
|
||||||
}
|
}
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"ACTION": url.action,
|
"ACTION": url.action,
|
||||||
"ITEM": {
|
"ITEM": {
|
||||||
"ItemID": qItem.ID,
|
"ItemID": qItem.ItemID,
|
||||||
"Name": qItem.Name,
|
"ItemName": qItem.ItemName,
|
||||||
"ParentItemID": qItem.ParentItemID,
|
"ItemParentItemID": qItem.ItemParentItemID,
|
||||||
"IsActive": qItem.IsActive,
|
"ItemIsActive": qItem.ItemIsActive,
|
||||||
"IsCollapsible": qItem.IsCollapsible
|
"ItemIsCollapsible": qItem.ItemIsCollapsible
|
||||||
},
|
},
|
||||||
"HAS_CHILDREN": qChildren.recordCount > 0,
|
"HAS_CHILDREN": qChildren.recordCount > 0,
|
||||||
"CHILD_COUNT": qChildren.recordCount,
|
"CHILD_COUNT": qChildren.recordCount,
|
||||||
|
|
@ -48,14 +48,14 @@ if (url.action == "deactivate") {
|
||||||
// Deactivate children first
|
// Deactivate children first
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET IsActive = 0
|
SET ItemIsActive = 0
|
||||||
WHERE ParentItemID = :itemId
|
WHERE ItemParentItemID = :itemId
|
||||||
", { itemId: url.itemId });
|
", { itemId: url.itemId });
|
||||||
|
|
||||||
// Then deactivate the parent
|
// Then deactivate the parent
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET IsActive = 0
|
SET ItemIsActive = 0
|
||||||
WHERE ItemID = :itemId
|
WHERE ItemID = :itemId
|
||||||
", { itemId: url.itemId });
|
", { itemId: url.itemId });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@
|
||||||
// Delete cart orders (status 0) to reset for testing
|
// Delete cart orders (status 0) to reset for testing
|
||||||
result = queryExecute("
|
result = queryExecute("
|
||||||
DELETE FROM OrderLineItems
|
DELETE FROM OrderLineItems
|
||||||
WHERE OrderID IN (
|
WHERE OrderLineItemOrderID IN (
|
||||||
SELECT ID FROM Orders WHERE StatusID = 0
|
SELECT OrderID FROM Orders WHERE OrderStatusID = 0
|
||||||
)
|
)
|
||||||
", {}, { datasource = "payfrit" });
|
", {}, { datasource = "payfrit" });
|
||||||
|
|
||||||
result2 = queryExecute("
|
result2 = queryExecute("
|
||||||
DELETE FROM Orders WHERE StatusID = 0
|
DELETE FROM Orders WHERE OrderStatusID = 0
|
||||||
", {}, { datasource = "payfrit" });
|
", {}, { datasource = "payfrit" });
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
|
|
|
||||||
|
|
@ -10,27 +10,27 @@ try {
|
||||||
businessIDs = [38, 39, 40, 41, 42];
|
businessIDs = [38, 39, 40, 41, 42];
|
||||||
|
|
||||||
for (bizID in businessIDs) {
|
for (bizID in businessIDs) {
|
||||||
// Delete lt_ItemID_TemplateItemID for items belonging to this business
|
// Delete ItemTemplateLinks for items belonging to this business
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE itl FROM lt_ItemID_TemplateItemID itl
|
DELETE itl FROM ItemTemplateLinks itl
|
||||||
INNER JOIN Items i ON i.ID = itl.ItemID
|
INNER JOIN Items i ON i.ItemID = itl.ItemID
|
||||||
WHERE i.BusinessID = :bizID
|
WHERE i.ItemBusinessID = :bizID
|
||||||
", { bizID: bizID }, { datasource: "payfrit" });
|
", { bizID: bizID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Delete Items
|
// Delete Items
|
||||||
queryExecute("DELETE FROM Items WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
queryExecute("DELETE FROM Items WHERE ItemBusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Delete Categories
|
// Delete Categories
|
||||||
queryExecute("DELETE FROM Categories WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
queryExecute("DELETE FROM Categories WHERE CategoryBusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Delete Hours
|
// Delete Hours
|
||||||
queryExecute("DELETE FROM Hours WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
queryExecute("DELETE FROM Hours WHERE HoursBusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Delete Addresses linked to this business
|
// Delete Addresses linked to this business
|
||||||
queryExecute("DELETE FROM Addresses WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
queryExecute("DELETE FROM Addresses WHERE AddressBusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Delete the Business itself
|
// Delete the Business itself
|
||||||
queryExecute("DELETE FROM Businesses WHERE ID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
queryExecute("DELETE FROM Businesses WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
response.steps.append("Deleted business " & bizID & " and all related data");
|
response.steps.append("Deleted business " & bizID & " and all related data");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
try {
|
try {
|
||||||
result = queryExecute("
|
result = queryExecute("
|
||||||
UPDATE Tasks
|
UPDATE Tasks
|
||||||
SET CompletedOn = NOW()
|
SET TaskCompletedOn = NOW()
|
||||||
WHERE TaskTypeID = 2
|
WHERE TaskTypeID = 2
|
||||||
AND CompletedOn IS NULL
|
AND TaskCompletedOn IS NULL
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
affected = result.recordCount ?: 0;
|
affected = result.recordCount ?: 0;
|
||||||
|
|
|
||||||
|
|
@ -15,24 +15,24 @@ try {
|
||||||
|
|
||||||
// First, check if Big Dean's has a Beverages/Drinks category
|
// First, check if Big Dean's has a Beverages/Drinks category
|
||||||
qExistingCat = queryExecute("
|
qExistingCat = queryExecute("
|
||||||
SELECT ID, Name FROM Categories
|
SELECT CategoryID, CategoryName FROM Categories
|
||||||
WHERE BusinessID = :bizId AND (Name LIKE '%Drink%' OR Name LIKE '%Beverage%')
|
WHERE CategoryBusinessID = :bizId AND (CategoryName LIKE '%Drink%' OR CategoryName LIKE '%Beverage%')
|
||||||
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qExistingCat.recordCount > 0) {
|
if (qExistingCat.recordCount > 0) {
|
||||||
drinksCategoryId = qExistingCat.CategoryID;
|
drinksCategoryId = qExistingCat.CategoryID;
|
||||||
response["CategoryNote"] = "Using existing category: " & qExistingCat.Name;
|
response["CategoryNote"] = "Using existing category: " & qExistingCat.CategoryName;
|
||||||
} else {
|
} else {
|
||||||
// Create a new Beverages category for Big Dean's
|
// Create a new Beverages category for Big Dean's
|
||||||
qMaxCat = queryExecute("SELECT COALESCE(MAX(CategoryID), 0) + 1 as nextId FROM Categories", {}, { datasource: "payfrit" });
|
qMaxCat = queryExecute("SELECT COALESCE(MAX(CategoryID), 0) + 1 as nextId FROM Categories", {}, { datasource: "payfrit" });
|
||||||
drinksCategoryId = qMaxCat.nextId;
|
drinksCategoryId = qMaxCat.nextId;
|
||||||
|
|
||||||
qMaxSort = queryExecute("
|
qMaxSort = queryExecute("
|
||||||
SELECT COALESCE(MAX(SortOrder), 0) + 1 as nextSort FROM Categories WHERE BusinessID = :bizId
|
SELECT COALESCE(MAX(CategorySortOrder), 0) + 1 as nextSort FROM Categories WHERE CategoryBusinessID = :bizId
|
||||||
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Categories (CategoryID, BusinessID, ParentCategoryID, Name, SortOrder, AddedOn)
|
INSERT INTO Categories (CategoryID, CategoryBusinessID, CategoryParentCategoryID, CategoryName, CategorySortOrder, CategoryAddedOn)
|
||||||
VALUES (:catId, :bizId, 0, 'Beverages', :sortOrder, NOW())
|
VALUES (:catId, :bizId, 0, 'Beverages', :sortOrder, NOW())
|
||||||
", {
|
", {
|
||||||
catId: drinksCategoryId,
|
catId: drinksCategoryId,
|
||||||
|
|
@ -61,8 +61,8 @@ try {
|
||||||
for (drink in drinks) {
|
for (drink in drinks) {
|
||||||
// Check if item already exists
|
// Check if item already exists
|
||||||
qExists = queryExecute("
|
qExists = queryExecute("
|
||||||
SELECT ID FROM Items
|
SELECT ItemID FROM Items
|
||||||
WHERE BusinessID = :bizId AND Name = :name AND CategoryID = :catId
|
WHERE ItemBusinessID = :bizId AND ItemName = :name AND ItemCategoryID = :catId
|
||||||
", { bizId: bigDeansBusinessId, name: drink.name, catId: drinksCategoryId }, { datasource: "payfrit" });
|
", { bizId: bigDeansBusinessId, name: drink.name, catId: drinksCategoryId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qExists.recordCount == 0) {
|
if (qExists.recordCount == 0) {
|
||||||
|
|
@ -72,10 +72,10 @@ try {
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Items (
|
INSERT INTO Items (
|
||||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||||
Name, Description, Price, IsActive,
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||||
SortOrder, IsCollapsible, RequiresChildSelection,
|
ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection,
|
||||||
AddedOn
|
ItemAddedOn
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:itemId, :bizId, :catId, 0,
|
:itemId, :bizId, :catId, 0,
|
||||||
:name, :desc, :price, 1,
|
:name, :desc, :price, 1,
|
||||||
|
|
@ -103,10 +103,10 @@ try {
|
||||||
qMaxOpt = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
qMaxOpt = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Items (
|
INSERT INTO Items (
|
||||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||||
Name, Description, Price, IsActive,
|
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||||
SortOrder, IsCollapsible, IsCheckedByDefault,
|
ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault,
|
||||||
AddedOn
|
ItemAddedOn
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:itemId, :bizId, 0, :parentId,
|
:itemId, :bizId, 0, :parentId,
|
||||||
:name, '', 0, 1,
|
:name, '', 0, 1,
|
||||||
|
|
|
||||||
|
|
@ -20,74 +20,69 @@ try {
|
||||||
uuid = beaconUUIDs[i];
|
uuid = beaconUUIDs[i];
|
||||||
|
|
||||||
// Check if beacon exists
|
// Check if beacon exists
|
||||||
qB = queryExecute("SELECT ID FROM Beacons WHERE UUID = :uuid", { uuid: uuid }, { datasource: "payfrit" });
|
qB = queryExecute("SELECT BeaconID FROM Beacons WHERE BeaconUUID = :uuid", { uuid: uuid }, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qB.recordCount == 0) {
|
if (qB.recordCount == 0) {
|
||||||
queryExecute("INSERT INTO Beacons (UUID, BusinessID) VALUES (:uuid, :bizID)", { uuid: uuid, bizID: lazyDaisyID }, { datasource: "payfrit" });
|
queryExecute("INSERT INTO Beacons (BeaconUUID, BeaconBusinessID) VALUES (:uuid, :bizID)", { uuid: uuid, bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
qNew = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
qNew = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
||||||
beaconID = qNew.id;
|
beaconID = qNew.id;
|
||||||
response.steps.append("Created beacon " & beaconID & " with UUID: " & uuid);
|
response.steps.append("Created beacon " & beaconID & " with UUID: " & uuid);
|
||||||
} else {
|
} else {
|
||||||
beaconID = qB.ID;
|
beaconID = qB.BeaconID;
|
||||||
response.steps.append("Beacon exists: " & beaconID & " with UUID: " & uuid);
|
response.steps.append("Beacon exists: " & beaconID & " with UUID: " & uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get service point Table 1
|
// Get service point Table 1
|
||||||
qSP = queryExecute("
|
qSP = queryExecute("
|
||||||
SELECT ID FROM ServicePoints
|
SELECT ServicePointID FROM ServicePoints
|
||||||
WHERE BusinessID = :bizID AND Name = 'Table 1'
|
WHERE ServicePointBusinessID = :bizID AND ServicePointName = 'Table 1'
|
||||||
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qSP.recordCount == 0) {
|
if (qSP.recordCount == 0) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO ServicePoints (BusinessID, Name)
|
INSERT INTO ServicePoints (ServicePointBusinessID, ServicePointName, ServicePointTypeID)
|
||||||
VALUES (:bizID, 'Table 1')
|
VALUES (:bizID, 'Table 1', 1)
|
||||||
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
qSP = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
qSP = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
||||||
servicePointID = qSP.id;
|
servicePointID = qSP.id;
|
||||||
response.steps.append("Created service point 'Table 1' (ID: " & servicePointID & ")");
|
response.steps.append("Created service point 'Table 1' (ID: " & servicePointID & ")");
|
||||||
} else {
|
} else {
|
||||||
servicePointID = qSP.ID;
|
servicePointID = qSP.ServicePointID;
|
||||||
response.steps.append("Found service point 'Table 1' (ID: " & servicePointID & ")");
|
response.steps.append("Found service point 'Table 1' (ID: " & servicePointID & ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign all beacons to the Table 1 service point
|
// Get all beacons and map them
|
||||||
qBeacons = queryExecute("SELECT ID, UUID FROM Beacons WHERE BusinessID = :bizID", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
qBeacons = queryExecute("SELECT BeaconID, BeaconUUID FROM Beacons", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
for (i = 1; i <= qBeacons.recordCount; i++) {
|
for (i = 1; i <= qBeacons.recordCount; i++) {
|
||||||
beaconID = qBeacons.ID[i];
|
beaconID = qBeacons.BeaconID[i];
|
||||||
|
|
||||||
// Unassign this beacon from any existing service point
|
// Delete old mapping if exists
|
||||||
queryExecute("
|
queryExecute("DELETE FROM lt_Beacon_Businesses_ServicePoints WHERE BeaconID = :beaconID", { beaconID: beaconID }, { datasource: "payfrit" });
|
||||||
UPDATE ServicePoints SET BeaconID = NULL, AssignedByUserID = NULL
|
|
||||||
WHERE BeaconID = :beaconID
|
|
||||||
", { beaconID: beaconID }, { datasource: "payfrit" });
|
|
||||||
|
|
||||||
// Assign beacon to Table 1 service point
|
// Create new mapping
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE ServicePoints SET BeaconID = :beaconID, AssignedByUserID = 1
|
INSERT INTO lt_Beacon_Businesses_ServicePoints (BeaconID, BusinessID, ServicePointID)
|
||||||
WHERE ID = :spID AND BusinessID = :bizID
|
VALUES (:beaconID, :bizID, :spID)
|
||||||
", { beaconID: beaconID, bizID: lazyDaisyID, spID: servicePointID }, { datasource: "payfrit" });
|
", { beaconID: beaconID, bizID: lazyDaisyID, spID: servicePointID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Assigned beacon " & beaconID & " to Table 1");
|
response.steps.append("Mapped beacon " & beaconID & " to Lazy Daisy, Table 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get final status
|
// Get final status
|
||||||
qFinal = queryExecute("
|
qFinal = queryExecute("
|
||||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
SELECT lt.BeaconID, b.BeaconUUID, lt.BusinessID, biz.BusinessName, lt.ServicePointID, sp.ServicePointName
|
||||||
b.Name AS BeaconName, b.UUID, sp.Name AS ServicePointName,
|
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||||
biz.Name AS BusinessName
|
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||||
FROM ServicePoints sp
|
JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
|
||||||
WHERE sp.BeaconID IS NOT NULL
|
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
beacons = [];
|
beacons = [];
|
||||||
for (i = 1; i <= qFinal.recordCount; i++) {
|
for (i = 1; i <= qFinal.recordCount; i++) {
|
||||||
arrayAppend(beacons, {
|
arrayAppend(beacons, {
|
||||||
"BeaconID": qFinal.BeaconID[i],
|
"BeaconID": qFinal.BeaconID[i],
|
||||||
"UUID": qFinal.UUID[i],
|
"UUID": qFinal.BeaconUUID[i],
|
||||||
"BusinessID": qFinal.BusinessID[i],
|
"BusinessID": qFinal.BusinessID[i],
|
||||||
"BusinessName": qFinal.BusinessName[i],
|
"BusinessName": qFinal.BusinessName[i],
|
||||||
"ServicePointID": qFinal.ServicePointID[i],
|
"ServicePointID": qFinal.ServicePointID[i],
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ try {
|
||||||
// Create ChatMessages table
|
// Create ChatMessages table
|
||||||
queryExecute("
|
queryExecute("
|
||||||
CREATE TABLE IF NOT EXISTS ChatMessages (
|
CREATE TABLE IF NOT EXISTS ChatMessages (
|
||||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
MessageID INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
TaskID INT NOT NULL,
|
TaskID INT NOT NULL,
|
||||||
SenderUserID INT NOT NULL,
|
SenderUserID INT NOT NULL,
|
||||||
SenderType ENUM('customer', 'worker') NOT NULL,
|
SenderType ENUM('customer', 'worker') NOT NULL,
|
||||||
MessageBody TEXT NOT NULL,
|
MessageText TEXT NOT NULL,
|
||||||
IsRead TINYINT(1) DEFAULT 0,
|
IsRead TINYINT(1) DEFAULT 0,
|
||||||
CreatedOn DATETIME DEFAULT NOW(),
|
CreatedOn DATETIME DEFAULT NOW(),
|
||||||
|
|
||||||
|
|
@ -21,13 +21,13 @@ try {
|
||||||
|
|
||||||
// Also add a "Chat" category if it doesn't exist for business 17
|
// Also add a "Chat" category if it doesn't exist for business 17
|
||||||
existing = queryExecute("
|
existing = queryExecute("
|
||||||
SELECT ID FROM TaskCategories
|
SELECT TaskCategoryID FROM TaskCategories
|
||||||
WHERE BusinessID = 17 AND Name = 'Chat'
|
WHERE TaskCategoryBusinessID = 17 AND TaskCategoryName = 'Chat'
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (existing.recordCount == 0) {
|
if (existing.recordCount == 0) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO TaskCategories (BusinessID, Name, Color)
|
INSERT INTO TaskCategories (TaskCategoryBusinessID, TaskCategoryName, TaskCategoryColor)
|
||||||
VALUES (17, 'Chat', '##2196F3')
|
VALUES (17, 'Chat', '##2196F3')
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,47 +32,47 @@ try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
CREATE TABLE Menus (
|
CREATE TABLE Menus (
|
||||||
MenuID INT AUTO_INCREMENT PRIMARY KEY,
|
MenuID INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
BusinessID INT NOT NULL,
|
MenuBusinessID INT NOT NULL,
|
||||||
Name VARCHAR(100) NOT NULL,
|
MenuName VARCHAR(100) NOT NULL,
|
||||||
Description VARCHAR(500) NULL,
|
MenuDescription VARCHAR(500) NULL,
|
||||||
DaysActive INT NOT NULL DEFAULT 127,
|
MenuDaysActive INT NOT NULL DEFAULT 127,
|
||||||
StartTime TIME NULL,
|
MenuStartTime TIME NULL,
|
||||||
EndTime TIME NULL,
|
MenuEndTime TIME NULL,
|
||||||
SortOrder INT NOT NULL DEFAULT 0,
|
MenuSortOrder INT NOT NULL DEFAULT 0,
|
||||||
IsActive TINYINT NOT NULL DEFAULT 1,
|
MenuIsActive TINYINT NOT NULL DEFAULT 1,
|
||||||
AddedOn DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
MenuAddedOn DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
INDEX idx_menus_business (BusinessID),
|
INDEX idx_menus_business (MenuBusinessID),
|
||||||
INDEX idx_menus_active (BusinessID, IsActive)
|
INDEX idx_menus_active (MenuBusinessID, MenuIsActive)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
response["OK"] = true;
|
response["OK"] = true;
|
||||||
response["MESSAGE"] = "Menus table created successfully";
|
response["MESSAGE"] = "Menus table created successfully";
|
||||||
response["SCHEMA"] = {
|
response["SCHEMA"] = {
|
||||||
"DaysActive": "Bitmask: 1=Sun, 2=Mon, 4=Tue, 8=Wed, 16=Thu, 32=Fri, 64=Sat (127 = all days)"
|
"MenuDaysActive": "Bitmask: 1=Sun, 2=Mon, 4=Tue, 8=Wed, 16=Thu, 32=Fri, 64=Sat (127 = all days)"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if MenuID column exists in Categories table
|
// Check if CategoryMenuID column exists in Categories table
|
||||||
qCatCol = queryExecute("
|
qCatCol = queryExecute("
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
||||||
WHERE TABLE_SCHEMA = 'payfrit'
|
WHERE TABLE_SCHEMA = 'payfrit'
|
||||||
AND TABLE_NAME = 'Categories'
|
AND TABLE_NAME = 'Categories'
|
||||||
AND COLUMN_NAME = 'MenuID'
|
AND COLUMN_NAME = 'CategoryMenuID'
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qCatCol.recordCount == 0) {
|
if (qCatCol.recordCount == 0) {
|
||||||
// Add MenuID column to Categories table
|
// Add CategoryMenuID column to Categories table
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Categories
|
ALTER TABLE Categories
|
||||||
ADD COLUMN MenuID INT NULL DEFAULT NULL AFTER BusinessID,
|
ADD COLUMN CategoryMenuID INT NULL DEFAULT NULL AFTER CategoryBusinessID,
|
||||||
ADD INDEX idx_categories_menu (MenuID)
|
ADD INDEX idx_categories_menu (CategoryMenuID)
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
response["CATEGORIES_UPDATED"] = true;
|
response["CATEGORIES_UPDATED"] = true;
|
||||||
response["CATEGORIES_MESSAGE"] = "Added MenuID column to Categories table";
|
response["CATEGORIES_MESSAGE"] = "Added CategoryMenuID column to Categories table";
|
||||||
} else {
|
} else {
|
||||||
response["CATEGORIES_UPDATED"] = false;
|
response["CATEGORIES_UPDATED"] = false;
|
||||||
response["CATEGORIES_MESSAGE"] = "MenuID column already exists";
|
response["CATEGORIES_MESSAGE"] = "CategoryMenuID column already exists";
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
*
|
*
|
||||||
* POST body:
|
* POST body:
|
||||||
* {
|
* {
|
||||||
* "Name": "Century Casino",
|
* "BusinessName": "Century Casino",
|
||||||
* "UserID": 1,
|
* "UserID": 1,
|
||||||
* "ChildBusinessIDs": [47, 48] // Optional: link existing businesses as children
|
* "ChildBusinessIDs": [47, 48] // Optional: link existing businesses as children
|
||||||
* }
|
* }
|
||||||
|
|
@ -36,13 +36,13 @@ response = { "OK": false };
|
||||||
try {
|
try {
|
||||||
data = readJsonBody();
|
data = readJsonBody();
|
||||||
|
|
||||||
Name = structKeyExists(data, "Name") ? trim(data.Name) : "";
|
BusinessName = structKeyExists(data, "BusinessName") ? trim(data.BusinessName) : "";
|
||||||
UserID = structKeyExists(data, "UserID") ? val(data.UserID) : 0;
|
UserID = structKeyExists(data, "UserID") ? val(data.UserID) : 0;
|
||||||
ChildBusinessIDs = structKeyExists(data, "ChildBusinessIDs") && isArray(data.ChildBusinessIDs) ? data.ChildBusinessIDs : [];
|
ChildBusinessIDs = structKeyExists(data, "ChildBusinessIDs") && isArray(data.ChildBusinessIDs) ? data.ChildBusinessIDs : [];
|
||||||
|
|
||||||
if (!len(Name)) {
|
if (!len(BusinessName)) {
|
||||||
response["ERROR"] = "missing_name";
|
response["ERROR"] = "missing_name";
|
||||||
response["MESSAGE"] = "Name is required";
|
response["MESSAGE"] = "BusinessName is required";
|
||||||
writeOutput(serializeJSON(response));
|
writeOutput(serializeJSON(response));
|
||||||
abort;
|
abort;
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ try {
|
||||||
|
|
||||||
// Create minimal address record (just a placeholder)
|
// Create minimal address record (just a placeholder)
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Addresses (Line1, UserID, AddressTypeID, AddedOn)
|
INSERT INTO Addresses (AddressLine1, AddressUserID, AddressTypeID, AddressAddedOn)
|
||||||
VALUES ('Parent Business - No Physical Location', :userID, 2, NOW())
|
VALUES ('Parent Business - No Physical Location', :userID, 2, NOW())
|
||||||
", {
|
", {
|
||||||
userID: UserID
|
userID: UserID
|
||||||
|
|
@ -67,10 +67,10 @@ try {
|
||||||
|
|
||||||
// Create parent business (no menu, no hours, just a shell)
|
// Create parent business (no menu, no hours, just a shell)
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Businesses (Name, UserID, AddressID, ParentBusinessID, BusinessDeliveryZipCodes, AddedOn)
|
INSERT INTO Businesses (BusinessName, BusinessUserID, BusinessAddressID, BusinessParentBusinessID, BusinessDeliveryZipCodes, BusinessAddedOn)
|
||||||
VALUES (:name, :userId, :addressId, NULL, '', NOW())
|
VALUES (:name, :userId, :addressId, NULL, '', NOW())
|
||||||
", {
|
", {
|
||||||
name: Name,
|
name: BusinessName,
|
||||||
userId: UserID,
|
userId: UserID,
|
||||||
addressId: addressId
|
addressId: addressId
|
||||||
}, { datasource = "payfrit" });
|
}, { datasource = "payfrit" });
|
||||||
|
|
@ -80,7 +80,7 @@ try {
|
||||||
|
|
||||||
// Link address back to business
|
// Link address back to business
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Addresses SET BusinessID = :bizId WHERE ID = :addrId
|
UPDATE Addresses SET AddressBusinessID = :bizId WHERE AddressID = :addrId
|
||||||
", {
|
", {
|
||||||
bizId: newBusinessID,
|
bizId: newBusinessID,
|
||||||
addrId: addressId
|
addrId: addressId
|
||||||
|
|
@ -92,7 +92,7 @@ try {
|
||||||
childID = val(childID);
|
childID = val(childID);
|
||||||
if (childID > 0) {
|
if (childID > 0) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Businesses SET ParentBusinessID = :parentId WHERE ID = :childId
|
UPDATE Businesses SET BusinessParentBusinessID = :parentId WHERE BusinessID = :childId
|
||||||
", {
|
", {
|
||||||
parentId: newBusinessID,
|
parentId: newBusinessID,
|
||||||
childId: childID
|
childId: childID
|
||||||
|
|
@ -103,7 +103,7 @@ try {
|
||||||
|
|
||||||
response["OK"] = true;
|
response["OK"] = true;
|
||||||
response["BusinessID"] = newBusinessID;
|
response["BusinessID"] = newBusinessID;
|
||||||
response["Name"] = Name;
|
response["BusinessName"] = BusinessName;
|
||||||
response["MESSAGE"] = "Parent business created";
|
response["MESSAGE"] = "Parent business created";
|
||||||
if (arrayLen(linkedChildren) > 0) {
|
if (arrayLen(linkedChildren) > 0) {
|
||||||
response["LinkedChildren"] = linkedChildren;
|
response["LinkedChildren"] = linkedChildren;
|
||||||
|
|
|
||||||
|
|
@ -9,22 +9,22 @@ bizId = 27;
|
||||||
deactivatedIds = [11177, 11180, 11183, 11186, 11190, 11193, 11196, 11199, 11204, 11212, 11220, 11259];
|
deactivatedIds = [11177, 11180, 11183, 11186, 11190, 11193, 11196, 11199, 11204, 11212, 11220, 11259];
|
||||||
|
|
||||||
qDeactivated = queryExecute("
|
qDeactivated = queryExecute("
|
||||||
SELECT i.ID, i.Name, i.ParentItemID, i.IsActive, i.IsCollapsible,
|
SELECT i.ItemID, i.ItemName, i.ItemParentItemID, i.ItemIsActive, i.ItemIsCollapsible,
|
||||||
(SELECT COUNT(*) FROM Items c WHERE c.ParentItemID = i.ID) as ChildCount,
|
(SELECT COUNT(*) FROM Items c WHERE c.ItemParentItemID = i.ItemID) as ChildCount,
|
||||||
(SELECT GROUP_CONCAT(c.Name) FROM Items c WHERE c.ParentItemID = i.ID) as Children
|
(SELECT GROUP_CONCAT(c.ItemName) FROM Items c WHERE c.ItemParentItemID = i.ItemID) as Children
|
||||||
FROM Items i
|
FROM Items i
|
||||||
WHERE i.ID IN (:ids)
|
WHERE i.ItemID IN (:ids)
|
||||||
ORDER BY i.ID
|
ORDER BY i.ItemID
|
||||||
", { ids: { value: arrayToList(deactivatedIds), list: true } }, { datasource: "payfrit" });
|
", { ids: { value: arrayToList(deactivatedIds), list: true } }, { datasource: "payfrit" });
|
||||||
|
|
||||||
items = [];
|
items = [];
|
||||||
for (row in qDeactivated) {
|
for (row in qDeactivated) {
|
||||||
arrayAppend(items, {
|
arrayAppend(items, {
|
||||||
"ItemID": row.ID,
|
"ItemID": row.ItemID,
|
||||||
"Name": row.Name,
|
"ItemName": row.ItemName,
|
||||||
"ParentID": row.ParentItemID,
|
"ParentID": row.ItemParentItemID,
|
||||||
"IsActive": row.IsActive,
|
"IsActive": row.ItemIsActive,
|
||||||
"IsCollapsible": row.IsCollapsible,
|
"IsCollapsible": row.ItemIsCollapsible,
|
||||||
"ChildCount": row.ChildCount,
|
"ChildCount": row.ChildCount,
|
||||||
"Children": row.Children
|
"Children": row.Children
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,24 +9,24 @@ bizId = 27;
|
||||||
qLinks = queryExecute("
|
qLinks = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
tl.ItemID as MenuItemID,
|
tl.ItemID as MenuItemID,
|
||||||
mi.Name as MenuName,
|
mi.ItemName as MenuItemName,
|
||||||
mi.ParentItemID,
|
mi.ItemParentItemID,
|
||||||
tl.TemplateItemID,
|
tl.TemplateItemID,
|
||||||
t.Name as TemplateName,
|
t.ItemName as TemplateName,
|
||||||
tl.SortOrder
|
tl.SortOrder
|
||||||
FROM lt_ItemID_TemplateItemID tl
|
FROM ItemTemplateLinks tl
|
||||||
JOIN Items mi ON mi.ID = tl.ItemID
|
JOIN Items mi ON mi.ItemID = tl.ItemID
|
||||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||||
WHERE mi.BusinessID = :bizId
|
WHERE mi.ItemBusinessID = :bizId
|
||||||
ORDER BY mi.ParentItemID, mi.Name, tl.SortOrder
|
ORDER BY mi.ItemParentItemID, mi.ItemName, tl.SortOrder
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
links = [];
|
links = [];
|
||||||
for (row in qLinks) {
|
for (row in qLinks) {
|
||||||
arrayAppend(links, {
|
arrayAppend(links, {
|
||||||
"MenuItemID": row.MenuItemID,
|
"MenuItemID": row.MenuItemID,
|
||||||
"MenuName": row.MenuName,
|
"MenuItemName": row.MenuItemName,
|
||||||
"ParentItemID": row.ParentItemID,
|
"ParentItemID": row.ItemParentItemID,
|
||||||
"TemplateItemID": row.TemplateItemID,
|
"TemplateItemID": row.TemplateItemID,
|
||||||
"TemplateName": row.TemplateName
|
"TemplateName": row.TemplateName
|
||||||
});
|
});
|
||||||
|
|
@ -34,20 +34,20 @@ for (row in qLinks) {
|
||||||
|
|
||||||
// Get burgers specifically (parent = 11271)
|
// Get burgers specifically (parent = 11271)
|
||||||
qBurgers = queryExecute("
|
qBurgers = queryExecute("
|
||||||
SELECT ID, Name FROM Items
|
SELECT ItemID, ItemName FROM Items
|
||||||
WHERE BusinessID = :bizId AND ParentItemID = 11271 AND IsActive = 1
|
WHERE ItemBusinessID = :bizId AND ItemParentItemID = 11271 AND ItemIsActive = 1
|
||||||
ORDER BY SortOrder
|
ORDER BY ItemSortOrder
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
burgers = [];
|
burgers = [];
|
||||||
for (row in qBurgers) {
|
for (row in qBurgers) {
|
||||||
// Get templates for this burger
|
// Get templates for this burger
|
||||||
qBurgerTemplates = queryExecute("
|
qBurgerTemplates = queryExecute("
|
||||||
SELECT tl.TemplateItemID, t.Name as TemplateName
|
SELECT tl.TemplateItemID, t.ItemName as TemplateName
|
||||||
FROM lt_ItemID_TemplateItemID tl
|
FROM ItemTemplateLinks tl
|
||||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||||
WHERE tl.ItemID = :itemId
|
WHERE tl.ItemID = :itemId
|
||||||
", { itemId: row.ID }, { datasource: "payfrit" });
|
", { itemId: row.ItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
templates = [];
|
templates = [];
|
||||||
for (t in qBurgerTemplates) {
|
for (t in qBurgerTemplates) {
|
||||||
|
|
@ -55,8 +55,8 @@ for (row in qBurgers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayAppend(burgers, {
|
arrayAppend(burgers, {
|
||||||
"ItemID": row.ID,
|
"ItemID": row.ItemID,
|
||||||
"Name": row.Name,
|
"ItemName": row.ItemName,
|
||||||
"Templates": templates
|
"Templates": templates
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,38 +9,38 @@ businessID = 27;
|
||||||
qCategories = queryExecute("
|
qCategories = queryExecute("
|
||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
p.ItemID as CategoryID,
|
p.ItemID as CategoryID,
|
||||||
p.Name as Name,
|
p.ItemName as CategoryName,
|
||||||
p.SortOrder
|
p.ItemSortOrder
|
||||||
FROM Items p
|
FROM Items p
|
||||||
INNER JOIN Items c ON c.ParentItemID = p.ItemID
|
INNER JOIN Items c ON c.ItemParentItemID = p.ItemID
|
||||||
WHERE p.BusinessID = :businessID
|
WHERE p.ItemBusinessID = :businessID
|
||||||
AND p.ParentItemID = 0
|
AND p.ItemParentItemID = 0
|
||||||
AND p.IsActive = 1
|
AND p.ItemIsActive = 1
|
||||||
AND NOT EXISTS (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = p.ItemID
|
SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = p.ItemID
|
||||||
)
|
)
|
||||||
ORDER BY p.SortOrder, p.Name
|
ORDER BY p.ItemSortOrder, p.ItemName
|
||||||
", { businessID: businessID });
|
", { businessID: businessID });
|
||||||
|
|
||||||
cats = [];
|
cats = [];
|
||||||
for (c in qCategories) {
|
for (c in qCategories) {
|
||||||
arrayAppend(cats, {
|
arrayAppend(cats, {
|
||||||
"CategoryID": c.ID,
|
"CategoryID": c.CategoryID,
|
||||||
"Name": c.Name
|
"CategoryName": c.CategoryName
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also check raw counts
|
// Also check raw counts
|
||||||
rawCount = queryExecute("
|
rawCount = queryExecute("
|
||||||
SELECT COUNT(*) as cnt FROM Items
|
SELECT COUNT(*) as cnt FROM Items
|
||||||
WHERE BusinessID = :bizId AND ParentItemID = 0 AND IsActive = 1
|
WHERE ItemBusinessID = :bizId AND ItemParentItemID = 0 AND ItemIsActive = 1
|
||||||
", { bizId: businessID });
|
", { bizId: businessID });
|
||||||
|
|
||||||
childrenCount = queryExecute("
|
childrenCount = queryExecute("
|
||||||
SELECT COUNT(DISTINCT c.ParentItemID) as cnt
|
SELECT COUNT(DISTINCT c.ItemParentItemID) as cnt
|
||||||
FROM Items c
|
FROM Items c
|
||||||
INNER JOIN Items p ON p.ItemID = c.ParentItemID
|
INNER JOIN Items p ON p.ItemID = c.ItemParentItemID
|
||||||
WHERE p.BusinessID = :bizId AND p.ParentItemID = 0
|
WHERE p.ItemBusinessID = :bizId AND p.ItemParentItemID = 0
|
||||||
", { bizId: businessID });
|
", { bizId: businessID });
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
|
|
|
||||||
|
|
@ -9,24 +9,24 @@ bizId = 27;
|
||||||
qLinks = queryExecute("
|
qLinks = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
tl.ItemID as MenuItemID,
|
tl.ItemID as MenuItemID,
|
||||||
mi.Name as MenuName,
|
mi.ItemName as MenuItemName,
|
||||||
mi.ParentItemID as MenuItemParentID,
|
mi.ItemParentItemID as MenuItemParentID,
|
||||||
tl.TemplateItemID,
|
tl.TemplateItemID,
|
||||||
t.Name as TemplateName,
|
t.ItemName as TemplateName,
|
||||||
t.IsActive as TemplateActive,
|
t.ItemIsActive as TemplateActive,
|
||||||
tl.SortOrder
|
tl.SortOrder
|
||||||
FROM lt_ItemID_TemplateItemID tl
|
FROM ItemTemplateLinks tl
|
||||||
JOIN Items mi ON mi.ID = tl.ItemID
|
JOIN Items mi ON mi.ItemID = tl.ItemID
|
||||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||||
WHERE mi.BusinessID = :bizId
|
WHERE mi.ItemBusinessID = :bizId
|
||||||
ORDER BY mi.Name, tl.SortOrder
|
ORDER BY mi.ItemName, tl.SortOrder
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
links = [];
|
links = [];
|
||||||
for (row in qLinks) {
|
for (row in qLinks) {
|
||||||
arrayAppend(links, {
|
arrayAppend(links, {
|
||||||
"MenuItemID": row.MenuItemID,
|
"MenuItemID": row.MenuItemID,
|
||||||
"MenuName": row.MenuName,
|
"MenuItemName": row.MenuItemName,
|
||||||
"MenuItemParentID": row.MenuItemParentID,
|
"MenuItemParentID": row.MenuItemParentID,
|
||||||
"TemplateItemID": row.TemplateItemID,
|
"TemplateItemID": row.TemplateItemID,
|
||||||
"TemplateName": row.TemplateName,
|
"TemplateName": row.TemplateName,
|
||||||
|
|
@ -37,20 +37,20 @@ for (row in qLinks) {
|
||||||
|
|
||||||
// Get all templates that exist for this business
|
// Get all templates that exist for this business
|
||||||
qTemplates = queryExecute("
|
qTemplates = queryExecute("
|
||||||
SELECT ID, Name, IsActive, ParentItemID
|
SELECT ItemID, ItemName, ItemIsActive, ItemParentItemID
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE BusinessID = :bizId
|
WHERE ItemBusinessID = :bizId
|
||||||
AND IsCollapsible = 1
|
AND ItemIsCollapsible = 1
|
||||||
ORDER BY Name
|
ORDER BY ItemName
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
templates = [];
|
templates = [];
|
||||||
for (row in qTemplates) {
|
for (row in qTemplates) {
|
||||||
arrayAppend(templates, {
|
arrayAppend(templates, {
|
||||||
"ItemID": row.ID,
|
"ItemID": row.ItemID,
|
||||||
"Name": row.Name,
|
"ItemName": row.ItemName,
|
||||||
"IsActive": row.IsActive,
|
"IsActive": row.ItemIsActive,
|
||||||
"ParentID": row.ParentItemID
|
"ParentID": row.ItemParentItemID
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,67 +5,67 @@
|
||||||
<cfscript>
|
<cfscript>
|
||||||
bizId = 27;
|
bizId = 27;
|
||||||
|
|
||||||
// Check the template items themselves (IDs from lt_ItemID_TemplateItemID)
|
// Check the template items themselves (IDs from ItemTemplateLinks)
|
||||||
templateIds = "11267, 11251, 11246, 11224, 11233, 11230, 11240, 11243, 11237, 11227";
|
templateIds = "11267, 11251, 11246, 11224, 11233, 11230, 11240, 11243, 11237, 11227";
|
||||||
|
|
||||||
qTemplates = queryExecute("
|
qTemplates = queryExecute("
|
||||||
SELECT ID, Name, IsCollapsible, IsActive, ParentItemID, BusinessID
|
SELECT ItemID, ItemName, ItemIsCollapsible, ItemIsActive, ItemParentItemID, ItemBusinessID
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE ID IN (#templateIds#)
|
WHERE ItemID IN (#templateIds#)
|
||||||
ORDER BY Name
|
ORDER BY ItemName
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
templates = [];
|
templates = [];
|
||||||
for (row in qTemplates) {
|
for (row in qTemplates) {
|
||||||
arrayAppend(templates, {
|
arrayAppend(templates, {
|
||||||
"ItemID": row.ID,
|
"ItemID": row.ItemID,
|
||||||
"Name": row.Name,
|
"ItemName": row.ItemName,
|
||||||
"IsCollapsible": row.IsCollapsible,
|
"IsCollapsible": row.ItemIsCollapsible,
|
||||||
"IsActive": row.IsActive,
|
"IsActive": row.ItemIsActive,
|
||||||
"ParentID": row.ParentItemID,
|
"ParentID": row.ItemParentItemID,
|
||||||
"BusinessID": row.BusinessID
|
"BusinessID": row.ItemBusinessID
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also check what other templates might exist for burgers
|
// Also check what other templates might exist for burgers
|
||||||
// Look for items that are in lt_ItemID_TemplateItemID but NOT linked to burgers
|
// Look for items that are in ItemTemplateLinks but NOT linked to burgers
|
||||||
qMissingTemplates = queryExecute("
|
qMissingTemplates = queryExecute("
|
||||||
SELECT DISTINCT t.ItemID, t.Name, t.IsCollapsible, t.IsActive
|
SELECT DISTINCT t.ItemID, t.ItemName, t.ItemIsCollapsible, t.ItemIsActive
|
||||||
FROM Items t
|
FROM Items t
|
||||||
WHERE t.BusinessID = :bizId
|
WHERE t.ItemBusinessID = :bizId
|
||||||
AND t.ParentItemID = 0
|
AND t.ItemParentItemID = 0
|
||||||
AND t.ItemID NOT IN (
|
AND t.ItemID NOT IN (
|
||||||
SELECT i.ID FROM Items i WHERE i.BusinessID = :bizId AND i.CategoryID > 0
|
SELECT i.ItemID FROM Items i WHERE i.ItemBusinessID = :bizId AND i.ItemCategoryID > 0
|
||||||
)
|
)
|
||||||
AND EXISTS (SELECT 1 FROM Items child WHERE child.ParentItemID = t.ItemID)
|
AND EXISTS (SELECT 1 FROM Items child WHERE child.ItemParentItemID = t.ItemID)
|
||||||
ORDER BY t.Name
|
ORDER BY t.ItemName
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
potentialTemplates = [];
|
potentialTemplates = [];
|
||||||
for (row in qMissingTemplates) {
|
for (row in qMissingTemplates) {
|
||||||
arrayAppend(potentialTemplates, {
|
arrayAppend(potentialTemplates, {
|
||||||
"ItemID": row.ID,
|
"ItemID": row.ItemID,
|
||||||
"Name": row.Name,
|
"ItemName": row.ItemName,
|
||||||
"IsCollapsible": row.IsCollapsible,
|
"IsCollapsible": row.ItemIsCollapsible,
|
||||||
"IsActive": row.IsActive
|
"IsActive": row.ItemIsActive
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// What templates SHOULD burgers have? Let's see all templates used by ANY item
|
// What templates SHOULD burgers have? Let's see all templates used by ANY item
|
||||||
qAllTemplateUsage = queryExecute("
|
qAllTemplateUsage = queryExecute("
|
||||||
SELECT t.ItemID, t.Name, COUNT(tl.ItemID) as UsageCount
|
SELECT t.ItemID, t.ItemName, COUNT(tl.ItemID) as UsageCount
|
||||||
FROM lt_ItemID_TemplateItemID tl
|
FROM ItemTemplateLinks tl
|
||||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||||
JOIN Items mi ON mi.ID = tl.ItemID AND mi.BusinessID = :bizId
|
JOIN Items mi ON mi.ItemID = tl.ItemID AND mi.ItemBusinessID = :bizId
|
||||||
GROUP BY t.ItemID, t.Name
|
GROUP BY t.ItemID, t.ItemName
|
||||||
ORDER BY t.Name
|
ORDER BY t.ItemName
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
allTemplates = [];
|
allTemplates = [];
|
||||||
for (row in qAllTemplateUsage) {
|
for (row in qAllTemplateUsage) {
|
||||||
arrayAppend(allTemplates, {
|
arrayAppend(allTemplates, {
|
||||||
"TemplateID": row.ID,
|
"TemplateID": row.ItemID,
|
||||||
"TemplateName": row.Name,
|
"TemplateName": row.ItemName,
|
||||||
"UsageCount": row.UsageCount
|
"UsageCount": row.UsageCount
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,41 +7,41 @@ bizId = 27;
|
||||||
|
|
||||||
// Get the template items themselves
|
// Get the template items themselves
|
||||||
qTemplates = queryExecute("
|
qTemplates = queryExecute("
|
||||||
SELECT ID, Name, IsCollapsible, IsActive, ParentItemID, BusinessID
|
SELECT ItemID, ItemName, ItemIsCollapsible, ItemIsActive, ItemParentItemID, ItemBusinessID
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE ID IN (11267, 11251, 11246, 11224, 11233, 11230, 11240, 11243, 11237, 11227)
|
WHERE ItemID IN (11267, 11251, 11246, 11224, 11233, 11230, 11240, 11243, 11237, 11227)
|
||||||
ORDER BY Name
|
ORDER BY ItemName
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
templates = [];
|
templates = [];
|
||||||
for (row in qTemplates) {
|
for (row in qTemplates) {
|
||||||
arrayAppend(templates, {
|
arrayAppend(templates, {
|
||||||
"ItemID": row.ID,
|
"ItemID": row.ItemID,
|
||||||
"Name": row.Name,
|
"ItemName": row.ItemName,
|
||||||
"IsCollapsible": row.IsCollapsible,
|
"IsCollapsible": row.ItemIsCollapsible,
|
||||||
"IsActive": row.IsActive,
|
"IsActive": row.ItemIsActive,
|
||||||
"ParentID": row.ParentItemID,
|
"ParentID": row.ItemParentItemID,
|
||||||
"BusinessID": row.BusinessID
|
"BusinessID": row.ItemBusinessID
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// What templates are used by burgers vs all items?
|
// What templates are used by burgers vs all items?
|
||||||
qBurgerLinks = queryExecute("
|
qBurgerLinks = queryExecute("
|
||||||
SELECT mi.ID, mi.Name, GROUP_CONCAT(t.Name ORDER BY tl.SortOrder) as Templates
|
SELECT mi.ItemID, mi.ItemName, GROUP_CONCAT(t.ItemName ORDER BY tl.SortOrder) as Templates
|
||||||
FROM Items mi
|
FROM Items mi
|
||||||
JOIN lt_ItemID_TemplateItemID tl ON tl.ItemID = mi.ID
|
JOIN ItemTemplateLinks tl ON tl.ItemID = mi.ItemID
|
||||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||||
WHERE mi.BusinessID = :bizId
|
WHERE mi.ItemBusinessID = :bizId
|
||||||
AND mi.ParentItemID = 11271
|
AND mi.ItemParentItemID = 11271
|
||||||
GROUP BY mi.ID, mi.Name
|
GROUP BY mi.ItemID, mi.ItemName
|
||||||
ORDER BY mi.Name
|
ORDER BY mi.ItemName
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
burgerLinks = [];
|
burgerLinks = [];
|
||||||
for (row in qBurgerLinks) {
|
for (row in qBurgerLinks) {
|
||||||
arrayAppend(burgerLinks, {
|
arrayAppend(burgerLinks, {
|
||||||
"ItemID": row.ID,
|
"ItemID": row.ItemID,
|
||||||
"Name": row.Name,
|
"ItemName": row.ItemName,
|
||||||
"Templates": row.Templates
|
"Templates": row.Templates
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -49,20 +49,20 @@ for (row in qBurgerLinks) {
|
||||||
// Also check: are there templates that SHOULD be linked to burgers?
|
// Also check: are there templates that SHOULD be linked to burgers?
|
||||||
// (e.g., Add Cheese, etc.)
|
// (e.g., Add Cheese, etc.)
|
||||||
qCheeseTemplate = queryExecute("
|
qCheeseTemplate = queryExecute("
|
||||||
SELECT ID, Name, ParentItemID, IsActive
|
SELECT ItemID, ItemName, ItemParentItemID, ItemIsActive
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE BusinessID = :bizId
|
WHERE ItemBusinessID = :bizId
|
||||||
AND Name LIKE '%Cheese%'
|
AND ItemName LIKE '%Cheese%'
|
||||||
ORDER BY Name
|
ORDER BY ItemName
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
cheeseItems = [];
|
cheeseItems = [];
|
||||||
for (row in qCheeseTemplate) {
|
for (row in qCheeseTemplate) {
|
||||||
arrayAppend(cheeseItems, {
|
arrayAppend(cheeseItems, {
|
||||||
"ItemID": row.ID,
|
"ItemID": row.ItemID,
|
||||||
"Name": row.Name,
|
"ItemName": row.ItemName,
|
||||||
"ParentID": row.ParentItemID,
|
"ParentID": row.ItemParentItemID,
|
||||||
"IsActive": row.IsActive
|
"IsActive": row.ItemIsActive
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,36 +26,36 @@
|
||||||
<cftry>
|
<cftry>
|
||||||
<!--- Get raw employee records --- >
|
<!--- Get raw employee records --- >
|
||||||
<cfset qEmployees = queryExecute("
|
<cfset qEmployees = queryExecute("
|
||||||
SELECT e.*, b.Name
|
SELECT e.*, b.BusinessName
|
||||||
FROM Employees e
|
FROM lt_Users_Businesses_Employees e
|
||||||
INNER JOIN Businesses b ON b.ID = e.BusinessID
|
INNER JOIN Businesses b ON b.BusinessID = e.BusinessID
|
||||||
WHERE e.UserID = ?
|
WHERE e.UserID = ?
|
||||||
ORDER BY b.Name ASC
|
ORDER BY b.BusinessName ASC
|
||||||
", [ { value = UserID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })>
|
", [ { value = UserID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })>
|
||||||
|
|
||||||
<cfset employees = []>
|
<cfset employees = []>
|
||||||
<cfloop query="qEmployees">
|
<cfloop query="qEmployees">
|
||||||
<cfset arrayAppend(employees, {
|
<cfset arrayAppend(employees, {
|
||||||
"EmployeeID": qEmployees.ID,
|
"EmployeeID": qEmployees.EmployeeID,
|
||||||
"UserID": qEmployees.UserID,
|
"UserID": qEmployees.UserID,
|
||||||
"BusinessID": qEmployees.BusinessID,
|
"BusinessID": qEmployees.BusinessID,
|
||||||
"Name": qEmployees.Name,
|
"BusinessName": qEmployees.BusinessName,
|
||||||
"IsActive": qEmployees.IsActive
|
"EmployeeIsActive": qEmployees.EmployeeIsActive
|
||||||
})>
|
})>
|
||||||
</cfloop>
|
</cfloop>
|
||||||
|
|
||||||
<!--- Check for duplicate businesses --- >
|
<!--- Check for duplicate businesses --- >
|
||||||
<cfset qDuplicates = queryExecute("
|
<cfset qDuplicates = queryExecute("
|
||||||
SELECT Name, COUNT(*) AS cnt
|
SELECT BusinessName, COUNT(*) AS cnt
|
||||||
FROM Businesses
|
FROM Businesses
|
||||||
GROUP BY Name
|
GROUP BY BusinessName
|
||||||
HAVING COUNT(*) > 1
|
HAVING COUNT(*) > 1
|
||||||
", [], { datasource = "payfrit" })>
|
", [], { datasource = "payfrit" })>
|
||||||
|
|
||||||
<cfset duplicates = []>
|
<cfset duplicates = []>
|
||||||
<cfloop query="qDuplicates">
|
<cfloop query="qDuplicates">
|
||||||
<cfset arrayAppend(duplicates, {
|
<cfset arrayAppend(duplicates, {
|
||||||
"Name": qDuplicates.Name,
|
"BusinessName": qDuplicates.BusinessName,
|
||||||
"Count": qDuplicates.cnt
|
"Count": qDuplicates.cnt
|
||||||
})>
|
})>
|
||||||
</cfloop>
|
</cfloop>
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,11 @@ try {
|
||||||
messages = [];
|
messages = [];
|
||||||
for (row in qAll) {
|
for (row in qAll) {
|
||||||
arrayAppend(messages, {
|
arrayAppend(messages, {
|
||||||
"MessageID": row.ID,
|
"MessageID": row.MessageID,
|
||||||
"TaskID": row.TaskID,
|
"TaskID": row.TaskID,
|
||||||
"SenderUserID": row.SenderUserID,
|
"SenderUserID": row.SenderUserID,
|
||||||
"SenderType": row.SenderType,
|
"SenderType": row.SenderType,
|
||||||
"MessageBody": left(row.MessageBody, 100),
|
"MessageText": left(row.MessageText, 100),
|
||||||
"CreatedOn": row.CreatedOn
|
"CreatedOn": row.CreatedOn
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,54 +10,54 @@ response = { "OK": true };
|
||||||
try {
|
try {
|
||||||
// Get Fountain Drinks item
|
// Get Fountain Drinks item
|
||||||
qFountain = queryExecute("
|
qFountain = queryExecute("
|
||||||
SELECT ID, Name, ParentItemID, Price, IsCollapsible, RequiresChildSelection
|
SELECT ItemID, ItemName, ItemParentItemID, ItemPrice, ItemIsCollapsible, ItemRequiresChildSelection
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE BusinessID = 17 AND Name LIKE '%Fountain%'
|
WHERE ItemBusinessID = 17 AND ItemName LIKE '%Fountain%'
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
response["FountainDrinks"] = [];
|
response["FountainDrinks"] = [];
|
||||||
for (row in qFountain) {
|
for (row in qFountain) {
|
||||||
fountainItem = {
|
fountainItem = {
|
||||||
"ItemID": row.ID,
|
"ItemID": row.ItemID,
|
||||||
"Name": row.Name,
|
"ItemName": row.ItemName,
|
||||||
"Price": row.Price,
|
"ItemPrice": row.ItemPrice,
|
||||||
"IsCollapsible": row.IsCollapsible,
|
"ItemIsCollapsible": row.ItemIsCollapsible,
|
||||||
"RequiresChildSelection": row.RequiresChildSelection,
|
"ItemRequiresChildSelection": row.ItemRequiresChildSelection,
|
||||||
"Children": []
|
"Children": []
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get children of this item
|
// Get children of this item
|
||||||
qChildren = queryExecute("
|
qChildren = queryExecute("
|
||||||
SELECT ID, Name, ParentItemID, Price, IsCollapsible, RequiresChildSelection, IsCheckedByDefault
|
SELECT ItemID, ItemName, ItemParentItemID, ItemPrice, ItemIsCollapsible, ItemRequiresChildSelection, ItemIsCheckedByDefault
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE ParentItemID = :parentId
|
WHERE ItemParentItemID = :parentId
|
||||||
ORDER BY SortOrder
|
ORDER BY ItemSortOrder
|
||||||
", { parentId: row.ID }, { datasource: "payfrit" });
|
", { parentId: row.ItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
for (child in qChildren) {
|
for (child in qChildren) {
|
||||||
childItem = {
|
childItem = {
|
||||||
"ItemID": child.ItemID,
|
"ItemID": child.ItemID,
|
||||||
"Name": child.Name,
|
"ItemName": child.ItemName,
|
||||||
"Price": child.Price,
|
"ItemPrice": child.ItemPrice,
|
||||||
"IsCollapsible": child.IsCollapsible,
|
"ItemIsCollapsible": child.ItemIsCollapsible,
|
||||||
"IsCheckedByDefault": child.IsCheckedByDefault,
|
"ItemIsCheckedByDefault": child.ItemIsCheckedByDefault,
|
||||||
"Grandchildren": []
|
"Grandchildren": []
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get grandchildren
|
// Get grandchildren
|
||||||
qGrandchildren = queryExecute("
|
qGrandchildren = queryExecute("
|
||||||
SELECT ID, Name, Price, IsCheckedByDefault
|
SELECT ItemID, ItemName, ItemPrice, ItemIsCheckedByDefault
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE ParentItemID = :parentId
|
WHERE ItemParentItemID = :parentId
|
||||||
ORDER BY SortOrder
|
ORDER BY ItemSortOrder
|
||||||
", { parentId: child.ItemID }, { datasource: "payfrit" });
|
", { parentId: child.ItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
for (gc in qGrandchildren) {
|
for (gc in qGrandchildren) {
|
||||||
arrayAppend(childItem.Grandchildren, {
|
arrayAppend(childItem.Grandchildren, {
|
||||||
"ItemID": gc.ItemID,
|
"ItemID": gc.ItemID,
|
||||||
"Name": gc.Name,
|
"ItemName": gc.ItemName,
|
||||||
"Price": gc.Price,
|
"ItemPrice": gc.ItemPrice,
|
||||||
"IsCheckedByDefault": gc.IsCheckedByDefault
|
"ItemIsCheckedByDefault": gc.ItemIsCheckedByDefault
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,10 @@ if (structKeyExists(data, "Phone") && len(data.Phone)) {
|
||||||
phone = reReplace(data.Phone, "[^0-9]", "", "all");
|
phone = reReplace(data.Phone, "[^0-9]", "", "all");
|
||||||
|
|
||||||
qUser = queryExecute("
|
qUser = queryExecute("
|
||||||
SELECT ID, FirstName, LastName, EmailAddress, ContactNumber
|
SELECT UserID, UserFirstName, UserLastName, UserEmailAddress, UserContactNumber
|
||||||
FROM Users
|
FROM Users
|
||||||
WHERE REPLACE(REPLACE(REPLACE(ContactNumber, '-', ''), '(', ''), ')', '') LIKE ?
|
WHERE REPLACE(REPLACE(REPLACE(UserContactNumber, '-', ''), '(', ''), ')', '') LIKE ?
|
||||||
OR ContactNumber LIKE ?
|
OR UserContactNumber LIKE ?
|
||||||
", [
|
", [
|
||||||
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" },
|
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" },
|
||||||
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" }
|
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" }
|
||||||
|
|
@ -28,35 +28,35 @@ if (structKeyExists(data, "Phone") && len(data.Phone)) {
|
||||||
abort;
|
abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
userId = qUser.ID;
|
userId = qUser.UserID;
|
||||||
|
|
||||||
qEmployees = queryExecute("
|
qEmployees = queryExecute("
|
||||||
SELECT e.ID, e.BusinessID, e.StatusID,
|
SELECT e.EmployeeID, e.BusinessID, e.EmployeeStatusID,
|
||||||
CAST(e.IsActive AS UNSIGNED) AS IsActive,
|
CAST(e.EmployeeIsActive AS UNSIGNED) AS EmployeeIsActive,
|
||||||
b.Name
|
b.BusinessName
|
||||||
FROM Employees e
|
FROM lt_Users_Businesses_Employees e
|
||||||
JOIN Businesses b ON e.BusinessID = b.ID
|
JOIN Businesses b ON e.BusinessID = b.BusinessID
|
||||||
WHERE e.UserID = ?
|
WHERE e.UserID = ?
|
||||||
", [{ value: userId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
", [{ value: userId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
||||||
|
|
||||||
employees = [];
|
employees = [];
|
||||||
for (row in qEmployees) {
|
for (row in qEmployees) {
|
||||||
arrayAppend(employees, {
|
arrayAppend(employees, {
|
||||||
"EmployeeID": row.ID,
|
"EmployeeID": row.EmployeeID,
|
||||||
"BusinessID": row.BusinessID,
|
"BusinessID": row.BusinessID,
|
||||||
"Name": row.Name,
|
"BusinessName": row.BusinessName,
|
||||||
"StatusID": row.StatusID,
|
"StatusID": row.EmployeeStatusID,
|
||||||
"IsActive": row.IsActive
|
"IsActive": row.EmployeeIsActive
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"USER": {
|
"USER": {
|
||||||
"UserID": qUser.ID,
|
"UserID": qUser.UserID,
|
||||||
"Name": trim(qUser.FirstName & " " & qUser.LastName),
|
"Name": trim(qUser.UserFirstName & " " & qUser.UserLastName),
|
||||||
"Email": qUser.EmailAddress,
|
"Email": qUser.UserEmailAddress,
|
||||||
"Phone": qUser.ContactNumber
|
"Phone": qUser.UserContactNumber
|
||||||
},
|
},
|
||||||
"EMPLOYEES": employees
|
"EMPLOYEES": employees
|
||||||
}));
|
}));
|
||||||
|
|
@ -67,23 +67,23 @@ if (structKeyExists(data, "Phone") && len(data.Phone)) {
|
||||||
businessId = structKeyExists(data, "BusinessID") ? val(data.BusinessID) : 17;
|
businessId = structKeyExists(data, "BusinessID") ? val(data.BusinessID) : 17;
|
||||||
|
|
||||||
q = queryExecute("
|
q = queryExecute("
|
||||||
SELECT ID, UserID, StatusID, IsActive,
|
SELECT EmployeeID, UserID, EmployeeStatusID, EmployeeIsActive,
|
||||||
CAST(IsActive AS UNSIGNED) AS IsActiveInt
|
CAST(EmployeeIsActive AS UNSIGNED) AS IsActiveInt
|
||||||
FROM Employees
|
FROM lt_Users_Businesses_Employees
|
||||||
WHERE BusinessID = ?
|
WHERE BusinessID = ?
|
||||||
", [{ value: businessId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
", [{ value: businessId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
||||||
|
|
||||||
rows = [];
|
rows = [];
|
||||||
for (r in q) {
|
for (r in q) {
|
||||||
arrayAppend(rows, {
|
arrayAppend(rows, {
|
||||||
"EmployeeID": r.ID,
|
"EmployeeID": r.EmployeeID,
|
||||||
"UserID": r.UserID,
|
"UserID": r.UserID,
|
||||||
"StatusID": r.StatusID,
|
"StatusID": r.EmployeeStatusID,
|
||||||
"RawIsActive": r.IsActive,
|
"RawIsActive": r.EmployeeIsActive,
|
||||||
"CastIsActive": r.IsActiveInt,
|
"CastIsActive": r.IsActiveInt,
|
||||||
"ValRaw": val(r.IsActive),
|
"ValRaw": val(r.EmployeeIsActive),
|
||||||
"ValCast": val(r.IsActiveInt),
|
"ValCast": val(r.IsActiveInt),
|
||||||
"EqRaw1": r.IsActive == 1,
|
"EqRaw1": r.EmployeeIsActive == 1,
|
||||||
"EqCast1": r.IsActiveInt == 1
|
"EqCast1": r.IsActiveInt == 1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ try {
|
||||||
// Close all open chats action
|
// Close all open chats action
|
||||||
if (structKeyExists(data, "action") && data.action == "closeAllChats") {
|
if (structKeyExists(data, "action") && data.action == "closeAllChats") {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Tasks SET CompletedOn = NOW()
|
UPDATE Tasks SET TaskCompletedOn = NOW()
|
||||||
WHERE TaskTypeID = 2 AND CompletedOn IS NULL
|
WHERE TaskTypeID = 2 AND TaskCompletedOn IS NULL
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
writeOutput(serializeJSON({ "OK": true, "MESSAGE": "All open chats closed" }));
|
writeOutput(serializeJSON({ "OK": true, "MESSAGE": "All open chats closed" }));
|
||||||
abort;
|
abort;
|
||||||
|
|
@ -24,38 +24,38 @@ if (structKeyExists(data, "action") && data.action == "closeAllChats") {
|
||||||
<cftry>
|
<cftry>
|
||||||
<cfset qTasks = queryExecute("
|
<cfset qTasks = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
t.ID,
|
t.TaskID,
|
||||||
t.BusinessID,
|
t.TaskBusinessID,
|
||||||
t.OrderID,
|
t.TaskOrderID,
|
||||||
t.ClaimedByUserID,
|
t.TaskClaimedByUserID,
|
||||||
t.ClaimedOn,
|
t.TaskClaimedOn,
|
||||||
t.CompletedOn,
|
t.TaskCompletedOn,
|
||||||
o.StatusID
|
o.OrderStatusID
|
||||||
FROM Tasks t
|
FROM Tasks t
|
||||||
LEFT JOIN Orders o ON o.ID = t.OrderID
|
LEFT JOIN Orders o ON o.OrderID = t.TaskOrderID
|
||||||
ORDER BY t.ID DESC
|
ORDER BY t.TaskID DESC
|
||||||
LIMIT 20
|
LIMIT 20
|
||||||
", [], { datasource = "payfrit" })>
|
", [], { datasource = "payfrit" })>
|
||||||
|
|
||||||
<cfset tasks = []>
|
<cfset tasks = []>
|
||||||
<cfloop query="qTasks">
|
<cfloop query="qTasks">
|
||||||
<cfset arrayAppend(tasks, {
|
<cfset arrayAppend(tasks, {
|
||||||
"TaskID": qTasks.ID,
|
"TaskID": qTasks.TaskID,
|
||||||
"BusinessID": qTasks.BusinessID,
|
"TaskBusinessID": qTasks.TaskBusinessID,
|
||||||
"OrderID": qTasks.OrderID,
|
"TaskOrderID": qTasks.TaskOrderID,
|
||||||
"ClaimedByUserID": qTasks.ClaimedByUserID,
|
"TaskClaimedByUserID": qTasks.TaskClaimedByUserID,
|
||||||
"ClaimedOn": isNull(qTasks.ClaimedOn) ? "NULL" : dateTimeFormat(qTasks.ClaimedOn, "yyyy-mm-dd HH:nn:ss"),
|
"TaskClaimedOn": isNull(qTasks.TaskClaimedOn) ? "NULL" : dateTimeFormat(qTasks.TaskClaimedOn, "yyyy-mm-dd HH:nn:ss"),
|
||||||
"CompletedOn": isNull(qTasks.CompletedOn) ? "NULL" : dateTimeFormat(qTasks.CompletedOn, "yyyy-mm-dd HH:nn:ss"),
|
"TaskCompletedOn": isNull(qTasks.TaskCompletedOn) ? "NULL" : dateTimeFormat(qTasks.TaskCompletedOn, "yyyy-mm-dd HH:nn:ss"),
|
||||||
"StatusID": isNull(qTasks.StatusID) ? "NULL" : qTasks.StatusID
|
"OrderStatusID": isNull(qTasks.OrderStatusID) ? "NULL" : qTasks.OrderStatusID
|
||||||
})>
|
})>
|
||||||
</cfloop>
|
</cfloop>
|
||||||
|
|
||||||
<cfset qStats = queryExecute("
|
<cfset qStats = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) as Total,
|
COUNT(*) as Total,
|
||||||
SUM(CASE WHEN ClaimedByUserID > 0 AND CompletedOn IS NULL THEN 1 ELSE 0 END) as ClaimedNotCompleted,
|
SUM(CASE WHEN TaskClaimedByUserID > 0 AND TaskCompletedOn IS NULL THEN 1 ELSE 0 END) as ClaimedNotCompleted,
|
||||||
SUM(CASE WHEN ClaimedByUserID = 0 OR ClaimedByUserID IS NULL THEN 1 ELSE 0 END) as Unclaimed,
|
SUM(CASE WHEN TaskClaimedByUserID = 0 OR TaskClaimedByUserID IS NULL THEN 1 ELSE 0 END) as Unclaimed,
|
||||||
SUM(CASE WHEN CompletedOn IS NOT NULL THEN 1 ELSE 0 END) as Completed
|
SUM(CASE WHEN TaskCompletedOn IS NOT NULL THEN 1 ELSE 0 END) as Completed
|
||||||
FROM Tasks
|
FROM Tasks
|
||||||
", [], { datasource = "payfrit" })>
|
", [], { datasource = "payfrit" })>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,19 +4,19 @@
|
||||||
|
|
||||||
<cftry>
|
<cftry>
|
||||||
<cfset qAll = queryExecute("
|
<cfset qAll = queryExecute("
|
||||||
SELECT ID, ClaimedByUserID, CompletedOn, OrderID,
|
SELECT TaskID, TaskClaimedByUserID, TaskCompletedOn, TaskOrderID,
|
||||||
CASE WHEN CompletedOn IS NULL THEN 'YES_NULL' ELSE 'NOT_NULL' END AS IsNull
|
CASE WHEN TaskCompletedOn IS NULL THEN 'YES_NULL' ELSE 'NOT_NULL' END AS IsNull
|
||||||
FROM Tasks
|
FROM Tasks
|
||||||
ORDER BY ID DESC
|
ORDER BY TaskID DESC
|
||||||
", [], { datasource = "payfrit" })>
|
", [], { datasource = "payfrit" })>
|
||||||
|
|
||||||
<cfset tasks = []>
|
<cfset tasks = []>
|
||||||
<cfloop query="qAll">
|
<cfloop query="qAll">
|
||||||
<cfset arrayAppend(tasks, {
|
<cfset arrayAppend(tasks, {
|
||||||
"TaskID": qAll.ID,
|
"TaskID": qAll.TaskID,
|
||||||
"ClaimedByUserID": qAll.ClaimedByUserID,
|
"TaskClaimedByUserID": qAll.TaskClaimedByUserID,
|
||||||
"OrderID": qAll.OrderID,
|
"TaskOrderID": qAll.TaskOrderID,
|
||||||
"CompletedOn": len(trim(qAll.CompletedOn)) ? toString(qAll.CompletedOn) : "",
|
"TaskCompletedOn": len(trim(qAll.TaskCompletedOn)) ? toString(qAll.TaskCompletedOn) : "",
|
||||||
"IsNull": qAll.IsNull
|
"IsNull": qAll.IsNull
|
||||||
})>
|
})>
|
||||||
</cfloop>
|
</cfloop>
|
||||||
|
|
|
||||||
|
|
@ -3,39 +3,39 @@
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||||
|
|
||||||
<cfscript>
|
<cfscript>
|
||||||
// Check lt_ItemID_TemplateItemID for Big Dean's (BusinessID 27)
|
// Check ItemTemplateLinks for Big Dean's (BusinessID 27)
|
||||||
bizId = 27;
|
bizId = 27;
|
||||||
|
|
||||||
// Count total links
|
// Count total links
|
||||||
qCount = queryExecute("SELECT COUNT(*) as cnt FROM lt_ItemID_TemplateItemID", {}, { datasource: "payfrit" });
|
qCount = queryExecute("SELECT COUNT(*) as cnt FROM ItemTemplateLinks", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Get template item IDs for this business
|
// Get template item IDs for this business
|
||||||
qTemplates = queryExecute("
|
qTemplates = queryExecute("
|
||||||
SELECT DISTINCT tl.TemplateItemID, i.Name
|
SELECT DISTINCT tl.TemplateItemID, i.ItemName
|
||||||
FROM lt_ItemID_TemplateItemID tl
|
FROM ItemTemplateLinks tl
|
||||||
JOIN Items i ON i.ID = tl.TemplateItemID
|
JOIN Items i ON i.ItemID = tl.TemplateItemID
|
||||||
WHERE i.BusinessID = :bizId
|
WHERE i.ItemBusinessID = :bizId
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
templates = [];
|
templates = [];
|
||||||
for (row in qTemplates) {
|
for (row in qTemplates) {
|
||||||
arrayAppend(templates, { "TemplateItemID": row.TemplateItemID, "Name": row.Name });
|
arrayAppend(templates, { "TemplateItemID": row.TemplateItemID, "ItemName": row.ItemName });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get items that should be categories (ParentItemID=0, not templates)
|
// Get items that should be categories (ParentItemID=0, not templates)
|
||||||
qCategories = queryExecute("
|
qCategories = queryExecute("
|
||||||
SELECT i.ID, i.Name, i.ParentItemID, i.IsCollapsible
|
SELECT i.ItemID, i.ItemName, i.ItemParentItemID, i.ItemIsCollapsible
|
||||||
FROM Items i
|
FROM Items i
|
||||||
WHERE i.BusinessID = :bizId
|
WHERE i.ItemBusinessID = :bizId
|
||||||
AND i.ParentItemID = 0
|
AND i.ItemParentItemID = 0
|
||||||
AND i.IsCollapsible = 0
|
AND i.ItemIsCollapsible = 0
|
||||||
AND NOT EXISTS (SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = i.ID)
|
AND NOT EXISTS (SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = i.ItemID)
|
||||||
ORDER BY i.SortOrder
|
ORDER BY i.ItemSortOrder
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
categories = [];
|
categories = [];
|
||||||
for (row in qCategories) {
|
for (row in qCategories) {
|
||||||
arrayAppend(categories, { "ItemID": row.ID, "Name": row.Name });
|
arrayAppend(categories, { "ItemID": row.ItemID, "ItemName": row.ItemName });
|
||||||
}
|
}
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@ if (len(phone) == 0) {
|
||||||
|
|
||||||
// Find user by phone
|
// Find user by phone
|
||||||
qUser = queryExecute("
|
qUser = queryExecute("
|
||||||
SELECT ID, FirstName, LastName, EmailAddress, ContactNumber
|
SELECT UserID, UserFirstName, UserLastName, UserEmailAddress, UserContactNumber
|
||||||
FROM Users
|
FROM Users
|
||||||
WHERE REPLACE(REPLACE(REPLACE(ContactNumber, '-', ''), '(', ''), ')', '') LIKE ?
|
WHERE REPLACE(REPLACE(REPLACE(UserContactNumber, '-', ''), '(', ''), ')', '') LIKE ?
|
||||||
OR ContactNumber LIKE ?
|
OR UserContactNumber LIKE ?
|
||||||
", [
|
", [
|
||||||
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" },
|
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" },
|
||||||
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" }
|
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" }
|
||||||
|
|
@ -34,36 +34,36 @@ if (qUser.recordCount == 0) {
|
||||||
abort;
|
abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
userId = qUser.ID;
|
userId = qUser.UserID;
|
||||||
|
|
||||||
// Get all employee records for this user
|
// Get all employee records for this user
|
||||||
qEmployees = queryExecute("
|
qEmployees = queryExecute("
|
||||||
SELECT e.ID, e.BusinessID, e.StatusID,
|
SELECT e.EmployeeID, e.BusinessID, e.EmployeeStatusID,
|
||||||
CAST(e.IsActive AS UNSIGNED) AS IsActive,
|
CAST(e.EmployeeIsActive AS UNSIGNED) AS EmployeeIsActive,
|
||||||
b.Name
|
b.BusinessName
|
||||||
FROM Employees e
|
FROM lt_Users_Businesses_Employees e
|
||||||
JOIN Businesses b ON e.BusinessID = b.ID
|
JOIN Businesses b ON e.BusinessID = b.BusinessID
|
||||||
WHERE e.UserID = ?
|
WHERE e.UserID = ?
|
||||||
", [{ value: userId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
", [{ value: userId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
||||||
|
|
||||||
employees = [];
|
employees = [];
|
||||||
for (row in qEmployees) {
|
for (row in qEmployees) {
|
||||||
arrayAppend(employees, {
|
arrayAppend(employees, {
|
||||||
"EmployeeID": row.ID,
|
"EmployeeID": row.EmployeeID,
|
||||||
"BusinessID": row.BusinessID,
|
"BusinessID": row.BusinessID,
|
||||||
"Name": row.Name,
|
"BusinessName": row.BusinessName,
|
||||||
"StatusID": row.StatusID,
|
"StatusID": row.EmployeeStatusID,
|
||||||
"IsActive": row.IsActive
|
"IsActive": row.EmployeeIsActive
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"USER": {
|
"USER": {
|
||||||
"UserID": qUser.ID,
|
"UserID": qUser.UserID,
|
||||||
"Name": trim(qUser.FirstName & " " & qUser.LastName),
|
"Name": trim(qUser.UserFirstName & " " & qUser.UserLastName),
|
||||||
"Email": qUser.EmailAddress,
|
"Email": qUser.UserEmailAddress,
|
||||||
"Phone": qUser.ContactNumber
|
"Phone": qUser.UserContactNumber
|
||||||
},
|
},
|
||||||
"EMPLOYEES": employees
|
"EMPLOYEES": employees
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -28,19 +28,19 @@ try {
|
||||||
response["ERROR"] = "BusinessID required";
|
response["ERROR"] = "BusinessID required";
|
||||||
} else {
|
} else {
|
||||||
// Get address ID first
|
// Get address ID first
|
||||||
qBiz = queryExecute("SELECT AddressID FROM Businesses WHERE ID = :id", { id: bizID }, { datasource = "payfrit" });
|
qBiz = queryExecute("SELECT BusinessAddressID FROM Businesses WHERE BusinessID = :id", { id: bizID }, { datasource = "payfrit" });
|
||||||
|
|
||||||
if (qBiz.recordCount == 0) {
|
if (qBiz.recordCount == 0) {
|
||||||
response["ERROR"] = "Business not found";
|
response["ERROR"] = "Business not found";
|
||||||
} else {
|
} else {
|
||||||
addrID = qBiz.AddressID;
|
addrID = qBiz.BusinessAddressID;
|
||||||
|
|
||||||
// Delete business
|
// Delete business
|
||||||
queryExecute("DELETE FROM Businesses WHERE ID = :id", { id: bizID }, { datasource = "payfrit" });
|
queryExecute("DELETE FROM Businesses WHERE BusinessID = :id", { id: bizID }, { datasource = "payfrit" });
|
||||||
|
|
||||||
// Delete address if exists
|
// Delete address if exists
|
||||||
if (val(addrID) > 0) {
|
if (val(addrID) > 0) {
|
||||||
queryExecute("DELETE FROM Addresses WHERE ID = :id", { id: addrID }, { datasource = "payfrit" });
|
queryExecute("DELETE FROM Addresses WHERE AddressID = :id", { id: addrID }, { datasource = "payfrit" });
|
||||||
}
|
}
|
||||||
|
|
||||||
response["OK"] = true;
|
response["OK"] = true;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
* Delete Orphan Modifiers for In and Out Burger (BusinessID=17)
|
* Delete Orphan Modifiers for In and Out Burger (BusinessID=17)
|
||||||
*
|
*
|
||||||
* This script deletes duplicate modifier items that are no longer needed
|
* This script deletes duplicate modifier items that are no longer needed
|
||||||
* because we now use lt_ItemID_TemplateItemID.
|
* because we now use ItemTemplateLinks.
|
||||||
*
|
*
|
||||||
* The orphan items are level-1 modifiers (direct children of parent items)
|
* The orphan items are level-1 modifiers (direct children of parent items)
|
||||||
* that have been replaced by template links.
|
* that have been replaced by template links.
|
||||||
|
|
@ -29,18 +29,18 @@ try {
|
||||||
qOrphans = queryExecute("
|
qOrphans = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
m.ItemID,
|
m.ItemID,
|
||||||
m.Name,
|
m.ItemName,
|
||||||
m.ParentItemID,
|
m.ItemParentItemID,
|
||||||
p.Name as ParentName
|
p.ItemName as ParentName
|
||||||
FROM Items m
|
FROM Items m
|
||||||
INNER JOIN Items p ON p.ItemID = m.ParentItemID
|
INNER JOIN Items p ON p.ItemID = m.ItemParentItemID
|
||||||
INNER JOIN Categories c ON c.ID = p.CategoryID
|
INNER JOIN Categories c ON c.CategoryID = p.ItemCategoryID
|
||||||
WHERE c.BusinessID = :businessID
|
WHERE c.CategoryBusinessID = :businessID
|
||||||
AND m.ParentItemID > 0
|
AND m.ItemParentItemID > 0
|
||||||
AND p.ParentItemID = 0
|
AND p.ItemParentItemID = 0
|
||||||
AND (m.IsModifierTemplate IS NULL OR m.IsModifierTemplate = 0)
|
AND (m.ItemIsModifierTemplate IS NULL OR m.ItemIsModifierTemplate = 0)
|
||||||
AND m.IsActive = 1
|
AND m.ItemIsActive = 1
|
||||||
ORDER BY m.Name
|
ORDER BY m.ItemName
|
||||||
", { businessID: businessID }, { datasource: "payfrit" });
|
", { businessID: businessID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(response.deleted, "Found " & qOrphans.recordCount & " orphan modifiers to delete");
|
arrayAppend(response.deleted, "Found " & qOrphans.recordCount & " orphan modifiers to delete");
|
||||||
|
|
@ -50,23 +50,23 @@ try {
|
||||||
try {
|
try {
|
||||||
// Delete children of this orphan (options within the modifier group)
|
// Delete children of this orphan (options within the modifier group)
|
||||||
qDeleteChildren = queryExecute("
|
qDeleteChildren = queryExecute("
|
||||||
DELETE FROM Items WHERE ParentItemID = :orphanID
|
DELETE FROM Items WHERE ItemParentItemID = :orphanID
|
||||||
", { orphanID: orphan.ItemID }, { datasource: "payfrit" });
|
", { orphanID: orphan.ItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Delete the orphan itself
|
// Delete the orphan itself
|
||||||
qDeleteOrphan = queryExecute("
|
qDeleteOrphan = queryExecute("
|
||||||
DELETE FROM Items WHERE ID = :orphanID
|
DELETE FROM Items WHERE ItemID = :orphanID
|
||||||
", { orphanID: orphan.ItemID }, { datasource: "payfrit" });
|
", { orphanID: orphan.ItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(response.deleted, {
|
arrayAppend(response.deleted, {
|
||||||
"ItemID": orphan.ItemID,
|
"ItemID": orphan.ItemID,
|
||||||
"Name": orphan.Name,
|
"ItemName": orphan.ItemName,
|
||||||
"WasUnder": orphan.ParentName
|
"WasUnder": orphan.ParentName
|
||||||
});
|
});
|
||||||
} catch (any deleteErr) {
|
} catch (any deleteErr) {
|
||||||
arrayAppend(response.errors, {
|
arrayAppend(response.errors, {
|
||||||
"ItemID": orphan.ItemID,
|
"ItemID": orphan.ItemID,
|
||||||
"Name": orphan.Name,
|
"ItemName": orphan.ItemName,
|
||||||
"Error": deleteErr.message
|
"Error": deleteErr.message
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
<cfscript>
|
<cfscript>
|
||||||
/**
|
/**
|
||||||
* Delete orphan Items at ParentID=0
|
* Delete orphan Items at ParentID=0
|
||||||
* Orphan = ParentID=0, no children, not in lt_ItemID_TemplateItemID
|
* Orphan = ParentID=0, no children, not in ItemTemplateLinks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
response = { "OK": false, "deleted": 0, "orphans": [] };
|
response = { "OK": false, "deleted": 0, "orphans": [] };
|
||||||
|
|
@ -19,24 +19,24 @@ response = { "OK": false, "deleted": 0, "orphans": [] };
|
||||||
try {
|
try {
|
||||||
// Find orphans
|
// Find orphans
|
||||||
qOrphans = queryExecute("
|
qOrphans = queryExecute("
|
||||||
SELECT i.ID, i.Name, i.BusinessID
|
SELECT i.ItemID, i.ItemName, i.ItemBusinessID
|
||||||
FROM Items i
|
FROM Items i
|
||||||
WHERE i.ParentItemID = 0
|
WHERE i.ItemParentItemID = 0
|
||||||
AND NOT EXISTS (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM Items child WHERE child.ParentItemID = i.ID
|
SELECT 1 FROM Items child WHERE child.ItemParentItemID = i.ItemID
|
||||||
)
|
)
|
||||||
AND NOT EXISTS (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = i.ID
|
SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = i.ItemID
|
||||||
)
|
)
|
||||||
ORDER BY i.BusinessID, i.Name
|
ORDER BY i.ItemBusinessID, i.ItemName
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
orphanIDs = [];
|
orphanIDs = [];
|
||||||
for (orphan in qOrphans) {
|
for (orphan in qOrphans) {
|
||||||
arrayAppend(response.orphans, {
|
arrayAppend(response.orphans, {
|
||||||
"ItemID": orphan.ItemID,
|
"ItemID": orphan.ItemID,
|
||||||
"Name": orphan.Name,
|
"ItemName": orphan.ItemName,
|
||||||
"BusinessID": orphan.BusinessID
|
"BusinessID": orphan.ItemBusinessID
|
||||||
});
|
});
|
||||||
arrayAppend(orphanIDs, orphan.ItemID);
|
arrayAppend(orphanIDs, orphan.ItemID);
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ try {
|
||||||
// Delete them by ID list
|
// Delete them by ID list
|
||||||
if (arrayLen(orphanIDs) > 0) {
|
if (arrayLen(orphanIDs) > 0) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM Items WHERE ID IN (#arrayToList(orphanIDs)#)
|
DELETE FROM Items WHERE ItemID IN (#arrayToList(orphanIDs)#)
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,16 @@
|
||||||
* Eliminate Categories Table - Schema Migration
|
* Eliminate Categories Table - Schema Migration
|
||||||
*
|
*
|
||||||
* Final unified schema:
|
* Final unified schema:
|
||||||
* - Everything is an Item with BusinessID
|
* - Everything is an Item with ItemBusinessID
|
||||||
* - ParentID=0 items are either categories or templates (derived from usage)
|
* - ParentID=0 items are either categories or templates (derived from usage)
|
||||||
* - Categories = items at ParentID=0 that have menu items as children
|
* - Categories = items at ParentID=0 that have menu items as children
|
||||||
* - Templates = items at ParentID=0 that appear in lt_ItemID_TemplateItemID
|
* - Templates = items at ParentID=0 that appear in ItemTemplateLinks
|
||||||
* - Orphans = ParentID=0 items that are neither (cleanup candidates)
|
* - Orphans = ParentID=0 items that are neither (cleanup candidates)
|
||||||
*
|
*
|
||||||
* Steps:
|
* Steps:
|
||||||
* 1. Add BusinessID column to Items
|
* 1. Add ItemBusinessID column to Items
|
||||||
* 2. For each Category: create Item, re-parent menu items, set BusinessID
|
* 2. For each Category: create Item, re-parent menu items, set BusinessID
|
||||||
* 3. Set BusinessID on templates based on linked items
|
* 3. Set ItemBusinessID on templates based on linked items
|
||||||
*
|
*
|
||||||
* Query param: ?dryRun=1 to preview without making changes
|
* Query param: ?dryRun=1 to preview without making changes
|
||||||
*/
|
*/
|
||||||
|
|
@ -34,30 +34,30 @@ try {
|
||||||
dryRun = structKeyExists(url, "dryRun") && url.dryRun == 1;
|
dryRun = structKeyExists(url, "dryRun") && url.dryRun == 1;
|
||||||
response["dryRun"] = dryRun;
|
response["dryRun"] = dryRun;
|
||||||
|
|
||||||
// Step 1: Add BusinessID column if it doesn't exist
|
// Step 1: Add ItemBusinessID column if it doesn't exist
|
||||||
try {
|
try {
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Items ADD COLUMN BusinessID INT DEFAULT 0 AFTER ItemID
|
ALTER TABLE Items ADD COLUMN ItemBusinessID INT DEFAULT 0 AFTER ItemID
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
arrayAppend(response.steps, "Added BusinessID column to Items table");
|
arrayAppend(response.steps, "Added ItemBusinessID column to Items table");
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
if (findNoCase("Duplicate column", e.message)) {
|
if (findNoCase("Duplicate column", e.message)) {
|
||||||
arrayAppend(response.steps, "BusinessID column already exists");
|
arrayAppend(response.steps, "ItemBusinessID column already exists");
|
||||||
} else {
|
} else {
|
||||||
throw(e);
|
throw(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Add index on BusinessID
|
// Step 2: Add index on ItemBusinessID
|
||||||
try {
|
try {
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
CREATE INDEX idx_item_business ON Items (BusinessID)
|
CREATE INDEX idx_item_business ON Items (ItemBusinessID)
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
arrayAppend(response.steps, "Added index on BusinessID");
|
arrayAppend(response.steps, "Added index on ItemBusinessID");
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
if (findNoCase("Duplicate key name", e.message)) {
|
if (findNoCase("Duplicate key name", e.message)) {
|
||||||
arrayAppend(response.steps, "Index idx_item_business already exists");
|
arrayAppend(response.steps, "Index idx_item_business already exists");
|
||||||
|
|
@ -66,7 +66,7 @@ try {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Drop foreign key constraint on CategoryID if it exists
|
// Step 3: Drop foreign key constraint on ItemCategoryID if it exists
|
||||||
try {
|
try {
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
|
|
@ -84,9 +84,9 @@ try {
|
||||||
|
|
||||||
// Step 4: Get all Categories
|
// Step 4: Get all Categories
|
||||||
qCategories = queryExecute("
|
qCategories = queryExecute("
|
||||||
SELECT ID, BusinessID, Name
|
SELECT CategoryID, CategoryBusinessID, CategoryName
|
||||||
FROM Categories
|
FROM Categories
|
||||||
ORDER BY BusinessID, Name
|
ORDER BY CategoryBusinessID, CategoryName
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(response.steps, "Found " & qCategories.recordCount & " categories to migrate");
|
arrayAppend(response.steps, "Found " & qCategories.recordCount & " categories to migrate");
|
||||||
|
|
@ -94,29 +94,29 @@ try {
|
||||||
// Step 4: Migrate each category
|
// Step 4: Migrate each category
|
||||||
for (cat in qCategories) {
|
for (cat in qCategories) {
|
||||||
migration = {
|
migration = {
|
||||||
"oldCategoryID": cat.ID,
|
"oldCategoryID": cat.CategoryID,
|
||||||
"categoryName": cat.Name,
|
"categoryName": cat.CategoryName,
|
||||||
"businessID": cat.BusinessID,
|
"businessID": cat.CategoryBusinessID,
|
||||||
"newItemID": 0,
|
"newItemID": 0,
|
||||||
"itemsUpdated": 0
|
"itemsUpdated": 0
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
// Create new Item for this category (ParentID=0, no template flag needed)
|
// Create new Item for this category (ParentID=0, no template flag needed)
|
||||||
// Note: CategoryID set to 0 temporarily until we drop that column
|
// Note: ItemCategoryID set to 0 temporarily until we drop that column
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Items (
|
INSERT INTO Items (
|
||||||
BusinessID,
|
ItemBusinessID,
|
||||||
CategoryID,
|
ItemCategoryID,
|
||||||
Name,
|
ItemName,
|
||||||
Description,
|
ItemDescription,
|
||||||
ParentItemID,
|
ItemParentItemID,
|
||||||
Price,
|
ItemPrice,
|
||||||
IsActive,
|
ItemIsActive,
|
||||||
IsCheckedByDefault,
|
ItemIsCheckedByDefault,
|
||||||
RequiresChildSelection,
|
ItemRequiresChildSelection,
|
||||||
SortOrder,
|
ItemSortOrder,
|
||||||
AddedOn
|
ItemAddedOn
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:businessID,
|
:businessID,
|
||||||
0,
|
0,
|
||||||
|
|
@ -131,56 +131,56 @@ try {
|
||||||
NOW()
|
NOW()
|
||||||
)
|
)
|
||||||
", {
|
", {
|
||||||
businessID: cat.BusinessID,
|
businessID: cat.CategoryBusinessID,
|
||||||
categoryName: cat.Name
|
categoryName: cat.CategoryName
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Get the new Item ID
|
// Get the new Item ID
|
||||||
qNewItem = queryExecute("
|
qNewItem = queryExecute("
|
||||||
SELECT ID FROM Items
|
SELECT ItemID FROM Items
|
||||||
WHERE BusinessID = :businessID
|
WHERE ItemBusinessID = :businessID
|
||||||
AND Name = :categoryName
|
AND ItemName = :categoryName
|
||||||
AND ParentItemID = 0
|
AND ItemParentItemID = 0
|
||||||
ORDER BY ID DESC
|
ORDER BY ItemID DESC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
", {
|
", {
|
||||||
businessID: cat.BusinessID,
|
businessID: cat.CategoryBusinessID,
|
||||||
categoryName: cat.Name
|
categoryName: cat.CategoryName
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
newItemID = qNewItem.ID;
|
newItemID = qNewItem.ItemID;
|
||||||
migration["newItemID"] = newItemID;
|
migration["newItemID"] = newItemID;
|
||||||
|
|
||||||
// Update menu items in this category:
|
// Update menu items in this category:
|
||||||
// - Set ParentItemID = newItemID (for top-level items only)
|
// - Set ItemParentItemID = newItemID (for top-level items only)
|
||||||
// - Set BusinessID = businessID (for all items)
|
// - Set ItemBusinessID = businessID (for all items)
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET BusinessID = :businessID,
|
SET ItemBusinessID = :businessID,
|
||||||
ParentItemID = :newItemID
|
ItemParentItemID = :newItemID
|
||||||
WHERE CategoryID = :categoryID
|
WHERE ItemCategoryID = :categoryID
|
||||||
AND ParentItemID = 0
|
AND ItemParentItemID = 0
|
||||||
", {
|
", {
|
||||||
businessID: cat.BusinessID,
|
businessID: cat.CategoryBusinessID,
|
||||||
newItemID: newItemID,
|
newItemID: newItemID,
|
||||||
categoryID: cat.ID
|
categoryID: cat.CategoryID
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Set BusinessID on ALL items in this category (including nested)
|
// Set ItemBusinessID on ALL items in this category (including nested)
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET BusinessID = :businessID
|
SET ItemBusinessID = :businessID
|
||||||
WHERE CategoryID = :categoryID
|
WHERE ItemCategoryID = :categoryID
|
||||||
AND (BusinessID IS NULL OR BusinessID = 0)
|
AND (ItemBusinessID IS NULL OR ItemBusinessID = 0)
|
||||||
", {
|
", {
|
||||||
businessID: cat.BusinessID,
|
businessID: cat.CategoryBusinessID,
|
||||||
categoryID: cat.ID
|
categoryID: cat.CategoryID
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Count how many were updated
|
// Count how many were updated
|
||||||
qCount = queryExecute("
|
qCount = queryExecute("
|
||||||
SELECT COUNT(*) as cnt FROM Items
|
SELECT COUNT(*) as cnt FROM Items
|
||||||
WHERE ParentItemID = :newItemID
|
WHERE ItemParentItemID = :newItemID
|
||||||
", { newItemID: newItemID }, { datasource: "payfrit" });
|
", { newItemID: newItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
migration["itemsUpdated"] = qCount.cnt;
|
migration["itemsUpdated"] = qCount.cnt;
|
||||||
|
|
@ -188,9 +188,9 @@ try {
|
||||||
// Dry run - count what would be updated
|
// Dry run - count what would be updated
|
||||||
qCount = queryExecute("
|
qCount = queryExecute("
|
||||||
SELECT COUNT(*) as cnt FROM Items
|
SELECT COUNT(*) as cnt FROM Items
|
||||||
WHERE CategoryID = :categoryID
|
WHERE ItemCategoryID = :categoryID
|
||||||
AND ParentItemID = 0
|
AND ItemParentItemID = 0
|
||||||
", { categoryID: cat.ID }, { datasource: "payfrit" });
|
", { categoryID: cat.CategoryID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
migration["itemsToUpdate"] = qCount.cnt;
|
migration["itemsToUpdate"] = qCount.cnt;
|
||||||
}
|
}
|
||||||
|
|
@ -198,37 +198,37 @@ try {
|
||||||
arrayAppend(response.migrations, migration);
|
arrayAppend(response.migrations, migration);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5: Set BusinessID for templates (items in lt_ItemID_TemplateItemID)
|
// Step 5: Set ItemBusinessID for templates (items in ItemTemplateLinks)
|
||||||
// Templates get their BusinessID from the items they're linked to
|
// Templates get their BusinessID from the items they're linked to
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items t
|
UPDATE Items t
|
||||||
INNER JOIN lt_ItemID_TemplateItemID tl ON tl.TemplateItemID = t.ItemID
|
INNER JOIN ItemTemplateLinks tl ON tl.TemplateItemID = t.ItemID
|
||||||
INNER JOIN Items i ON i.ID = tl.ItemID
|
INNER JOIN Items i ON i.ItemID = tl.ItemID
|
||||||
SET t.BusinessID = i.BusinessID
|
SET t.ItemBusinessID = i.ItemBusinessID
|
||||||
WHERE (t.BusinessID IS NULL OR t.BusinessID = 0)
|
WHERE (t.ItemBusinessID IS NULL OR t.ItemBusinessID = 0)
|
||||||
AND i.BusinessID > 0
|
AND i.ItemBusinessID > 0
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(response.steps, "Set BusinessID on templates from linked items");
|
arrayAppend(response.steps, "Set ItemBusinessID on templates from linked items");
|
||||||
|
|
||||||
// Set BusinessID on template children (options)
|
// Set ItemBusinessID on template children (options)
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items c
|
UPDATE Items c
|
||||||
INNER JOIN Items t ON t.ItemID = c.ParentItemID
|
INNER JOIN Items t ON t.ItemID = c.ItemParentItemID
|
||||||
SET c.BusinessID = t.BusinessID
|
SET c.ItemBusinessID = t.ItemBusinessID
|
||||||
WHERE t.BusinessID > 0
|
WHERE t.ItemBusinessID > 0
|
||||||
AND (c.BusinessID IS NULL OR c.BusinessID = 0)
|
AND (c.ItemBusinessID IS NULL OR c.ItemBusinessID = 0)
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(response.steps, "Set BusinessID on template children");
|
arrayAppend(response.steps, "Set ItemBusinessID on template children");
|
||||||
|
|
||||||
// Make sure templates have ParentID=0 (they live at top level)
|
// Make sure templates have ParentID=0 (they live at top level)
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items t
|
UPDATE Items t
|
||||||
INNER JOIN lt_ItemID_TemplateItemID tl ON tl.TemplateItemID = t.ItemID
|
INNER JOIN ItemTemplateLinks tl ON tl.TemplateItemID = t.ItemID
|
||||||
SET t.ParentItemID = 0
|
SET t.ItemParentItemID = 0
|
||||||
WHERE t.ParentItemID != 0
|
WHERE t.ItemParentItemID != 0
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(response.steps, "Ensured templates have ParentItemID=0");
|
arrayAppend(response.steps, "Ensured templates have ParentItemID=0");
|
||||||
|
|
|
||||||
|
|
@ -14,32 +14,32 @@ fakeCategories = [11177, 11180, 11183, 11186, 11190, 11193, 11196, 11199, 11204,
|
||||||
// Deactivate these items (or we could delete them, but deactivate is safer)
|
// Deactivate these items (or we could delete them, but deactivate is safer)
|
||||||
for (itemId in fakeCategories) {
|
for (itemId in fakeCategories) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items SET IsActive = 0 WHERE ItemID = :itemId AND BusinessID = :bizId
|
UPDATE Items SET ItemIsActive = 0 WHERE ItemID = :itemId AND ItemBusinessID = :bizId
|
||||||
", { itemId: itemId, bizId: bizId }, { datasource: "payfrit" });
|
", { itemId: itemId, bizId: bizId }, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also deactivate their children (modifier options that belong to these fake parents)
|
// Also deactivate their children (modifier options that belong to these fake parents)
|
||||||
for (itemId in fakeCategories) {
|
for (itemId in fakeCategories) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items SET IsActive = 0 WHERE ParentItemID = :itemId AND BusinessID = :bizId
|
UPDATE Items SET ItemIsActive = 0 WHERE ItemParentItemID = :itemId AND ItemBusinessID = :bizId
|
||||||
", { itemId: itemId, bizId: bizId }, { datasource: "payfrit" });
|
", { itemId: itemId, bizId: bizId }, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now verify what categories remain
|
// Now verify what categories remain
|
||||||
qCategories = queryExecute("
|
qCategories = queryExecute("
|
||||||
SELECT i.ID, i.Name
|
SELECT i.ItemID, i.ItemName
|
||||||
FROM Items i
|
FROM Items i
|
||||||
WHERE i.BusinessID = :bizId
|
WHERE i.ItemBusinessID = :bizId
|
||||||
AND i.ParentItemID = 0
|
AND i.ItemParentItemID = 0
|
||||||
AND i.IsActive = 1
|
AND i.ItemIsActive = 1
|
||||||
AND i.IsCollapsible = 0
|
AND i.ItemIsCollapsible = 0
|
||||||
AND NOT EXISTS (SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = i.ID)
|
AND NOT EXISTS (SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = i.ItemID)
|
||||||
ORDER BY i.SortOrder
|
ORDER BY i.ItemSortOrder
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
categories = [];
|
categories = [];
|
||||||
for (row in qCategories) {
|
for (row in qCategories) {
|
||||||
arrayAppend(categories, { "ItemID": row.ID, "Name": row.Name });
|
arrayAppend(categories, { "ItemID": row.ItemID, "ItemName": row.ItemName });
|
||||||
}
|
}
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ actions = [];
|
||||||
|
|
||||||
// First, let's see what templates already exist and are active for burgers
|
// First, let's see what templates already exist and are active for burgers
|
||||||
qExistingLinks = queryExecute("
|
qExistingLinks = queryExecute("
|
||||||
SELECT tl.ItemID as MenuItemID, tl.TemplateItemID, t.Name as TemplateName
|
SELECT tl.ItemID as MenuItemID, tl.TemplateItemID, t.ItemName as TemplateName
|
||||||
FROM lt_ItemID_TemplateItemID tl
|
FROM ItemTemplateLinks tl
|
||||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||||
WHERE tl.ItemID IN (:burgerIds)
|
WHERE tl.ItemID IN (:burgerIds)
|
||||||
", { burgerIds: { value: arrayToList(burgerIds), list: true } }, { datasource: "payfrit" });
|
", { burgerIds: { value: arrayToList(burgerIds), list: true } }, { datasource: "payfrit" });
|
||||||
|
|
@ -33,8 +33,8 @@ for (row in qExistingLinks) {
|
||||||
|
|
||||||
// Reactivate template 11196 (Extras with Add Cheese)
|
// Reactivate template 11196 (Extras with Add Cheese)
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
queryExecute("UPDATE Items SET IsActive = 1 WHERE ItemID = 11196", {}, { datasource: "payfrit" });
|
queryExecute("UPDATE Items SET ItemIsActive = 1 WHERE ItemID = 11196", {}, { datasource: "payfrit" });
|
||||||
queryExecute("UPDATE Items SET IsActive = 1 WHERE ParentItemID = 11196", {}, { datasource: "payfrit" });
|
queryExecute("UPDATE Items SET ItemIsActive = 1 WHERE ItemParentItemID = 11196", {}, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
arrayAppend(actions, { action: dryRun ? "WOULD_REACTIVATE" : "REACTIVATED", itemID: 11196, name: "Extras (Add Cheese, Add Onions)" });
|
arrayAppend(actions, { action: dryRun ? "WOULD_REACTIVATE" : "REACTIVATED", itemID: 11196, name: "Extras (Add Cheese, Add Onions)" });
|
||||||
|
|
||||||
|
|
@ -42,13 +42,13 @@ arrayAppend(actions, { action: dryRun ? "WOULD_REACTIVATE" : "REACTIVATED", item
|
||||||
for (burgerId in burgerIds) {
|
for (burgerId in burgerIds) {
|
||||||
// Check if link already exists
|
// Check if link already exists
|
||||||
qCheck = queryExecute("
|
qCheck = queryExecute("
|
||||||
SELECT COUNT(*) as cnt FROM lt_ItemID_TemplateItemID WHERE ItemID = :burgerId AND TemplateItemID = 11196
|
SELECT COUNT(*) as cnt FROM ItemTemplateLinks WHERE ItemID = :burgerId AND TemplateItemID = 11196
|
||||||
", { burgerId: burgerId }, { datasource: "payfrit" });
|
", { burgerId: burgerId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qCheck.cnt EQ 0) {
|
if (qCheck.cnt EQ 0) {
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder)
|
INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder)
|
||||||
VALUES (:burgerId, 11196, 2)
|
VALUES (:burgerId, 11196, 2)
|
||||||
", { burgerId: burgerId }, { datasource: "payfrit" });
|
", { burgerId: burgerId }, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
|
|
@ -59,17 +59,17 @@ for (burgerId in burgerIds) {
|
||||||
// Verify the result
|
// Verify the result
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
qVerify = queryExecute("
|
qVerify = queryExecute("
|
||||||
SELECT mi.ID, mi.Name, GROUP_CONCAT(t.Name ORDER BY tl.SortOrder) as Templates
|
SELECT mi.ItemID, mi.ItemName, GROUP_CONCAT(t.ItemName ORDER BY tl.SortOrder) as Templates
|
||||||
FROM Items mi
|
FROM Items mi
|
||||||
LEFT JOIN lt_ItemID_TemplateItemID tl ON tl.ItemID = mi.ID
|
LEFT JOIN ItemTemplateLinks tl ON tl.ItemID = mi.ItemID
|
||||||
LEFT JOIN Items t ON t.ItemID = tl.TemplateItemID
|
LEFT JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||||
WHERE mi.ID IN (:burgerIds)
|
WHERE mi.ItemID IN (:burgerIds)
|
||||||
GROUP BY mi.ID, mi.Name
|
GROUP BY mi.ItemID, mi.ItemName
|
||||||
", { burgerIds: { value: arrayToList(burgerIds), list: true } }, { datasource: "payfrit" });
|
", { burgerIds: { value: arrayToList(burgerIds), list: true } }, { datasource: "payfrit" });
|
||||||
|
|
||||||
result = [];
|
result = [];
|
||||||
for (row in qVerify) {
|
for (row in qVerify) {
|
||||||
arrayAppend(result, { itemID: row.ID, name: row.Name, templates: row.Templates });
|
arrayAppend(result, { itemID: row.ItemID, name: row.ItemName, templates: row.Templates });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = "Dry run - no changes made";
|
result = "Dry run - no changes made";
|
||||||
|
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfcontent type="application/json" reset="true">
|
|
||||||
<cfscript>
|
|
||||||
// One-time fix: remove # prefix from BrandColor
|
|
||||||
qBefore = queryExecute("
|
|
||||||
SELECT ID, BrandColor
|
|
||||||
FROM Businesses
|
|
||||||
WHERE BrandColor LIKE :pattern
|
|
||||||
", { pattern: { value: "##%", cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" });
|
|
||||||
|
|
||||||
if (qBefore.recordCount > 0) {
|
|
||||||
queryExecute("
|
|
||||||
UPDATE Businesses
|
|
||||||
SET BrandColor = SUBSTRING(BrandColor, 2)
|
|
||||||
WHERE BrandColor LIKE :pattern
|
|
||||||
", { pattern: { value: "##%", cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" });
|
|
||||||
}
|
|
||||||
|
|
||||||
qAfter = queryExecute("
|
|
||||||
SELECT ID, BrandColor
|
|
||||||
FROM Businesses
|
|
||||||
WHERE BrandColor IS NOT NULL AND LENGTH(BrandColor) > 0
|
|
||||||
", {}, { datasource: "payfrit" });
|
|
||||||
|
|
||||||
rows = [];
|
|
||||||
for (i = 1; i <= qAfter.recordCount; i++) {
|
|
||||||
arrayAppend(rows, {
|
|
||||||
"BusinessID": qAfter.BusinessID[i],
|
|
||||||
"BrandColor": qAfter.BrandColor[i]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"FIXED": qBefore.recordCount,
|
|
||||||
"CURRENT": rows
|
|
||||||
}));
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
||||||
|
|
||||||
<cfscript>
|
|
||||||
// Fix orphaned tasks that had old category ID 4 (deleted Service Point)
|
|
||||||
// Update them to use new category ID 25 (new Service Point)
|
|
||||||
try {
|
|
||||||
// First check how many tasks are affected
|
|
||||||
qCount = queryExecute("
|
|
||||||
SELECT COUNT(*) as cnt FROM Tasks WHERE TaskCategoryID = 4
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
affectedCount = qCount.cnt;
|
|
||||||
|
|
||||||
if (affectedCount > 0) {
|
|
||||||
// Update them to the new category
|
|
||||||
queryExecute("
|
|
||||||
UPDATE Tasks SET TaskCategoryID = 25 WHERE TaskCategoryID = 4
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"MESSAGE": "Updated " & affectedCount & " tasks from category 4 to category 25"
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"MESSAGE": "No tasks found with category ID 4"
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} catch (any e) {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": false,
|
|
||||||
"ERROR": e.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -30,8 +30,8 @@
|
||||||
* 2. Re-parent the three flavors under the new group
|
* 2. Re-parent the three flavors under the new group
|
||||||
* 3. Remove template flag from flavors
|
* 3. Remove template flag from flavors
|
||||||
* 4. Mark "Choose Flavor" as the template
|
* 4. Mark "Choose Flavor" as the template
|
||||||
* 5. Create lt_ItemID_TemplateItemID entry for Shake -> Choose Flavor
|
* 5. Create ItemTemplateLinks entry for Shake -> Choose Flavor
|
||||||
* 6. Set RequiresChildSelection=1 on the shake item
|
* 6. Set ItemRequiresChildSelection=1 on the shake item
|
||||||
*/
|
*/
|
||||||
|
|
||||||
response = { "OK": false, "steps": [] };
|
response = { "OK": false, "steps": [] };
|
||||||
|
|
@ -46,19 +46,19 @@ try {
|
||||||
// Step 1: Create "Choose Flavor" modifier group under Shake
|
// Step 1: Create "Choose Flavor" modifier group under Shake
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Items (
|
INSERT INTO Items (
|
||||||
CategoryID,
|
ItemCategoryID,
|
||||||
Name,
|
ItemName,
|
||||||
Description,
|
ItemDescription,
|
||||||
ParentItemID,
|
ItemParentItemID,
|
||||||
Price,
|
ItemPrice,
|
||||||
IsActive,
|
ItemIsActive,
|
||||||
IsCheckedByDefault,
|
ItemIsCheckedByDefault,
|
||||||
RequiresChildSelection,
|
ItemRequiresChildSelection,
|
||||||
MaxNumSelectionReq,
|
ItemMaxNumSelectionReq,
|
||||||
IsCollapsible,
|
ItemIsCollapsible,
|
||||||
SortOrder,
|
ItemSortOrder,
|
||||||
IsModifierTemplate,
|
ItemIsModifierTemplate,
|
||||||
AddedOn
|
ItemAddedOn
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:categoryID,
|
:categoryID,
|
||||||
'Choose Flavor',
|
'Choose Flavor',
|
||||||
|
|
@ -81,22 +81,22 @@ try {
|
||||||
|
|
||||||
// Get the new Choose Flavor ID
|
// Get the new Choose Flavor ID
|
||||||
qNewGroup = queryExecute("
|
qNewGroup = queryExecute("
|
||||||
SELECT ID FROM Items
|
SELECT ItemID FROM Items
|
||||||
WHERE Name = 'Choose Flavor'
|
WHERE ItemName = 'Choose Flavor'
|
||||||
AND ParentItemID = :shakeItemID
|
AND ItemParentItemID = :shakeItemID
|
||||||
ORDER BY ID DESC
|
ORDER BY ItemID DESC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
", { shakeItemID: shakeItemID }, { datasource: "payfrit" });
|
", { shakeItemID: shakeItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
chooseFlavorID = qNewGroup.ID;
|
chooseFlavorID = qNewGroup.ItemID;
|
||||||
arrayAppend(response.steps, "Created 'Choose Flavor' group with ID: " & chooseFlavorID);
|
arrayAppend(response.steps, "Created 'Choose Flavor' group with ID: " & chooseFlavorID);
|
||||||
|
|
||||||
// Step 2: Re-parent the three flavors under Choose Flavor
|
// Step 2: Re-parent the three flavors under Choose Flavor
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET ParentItemID = :chooseFlavorID,
|
SET ItemParentItemID = :chooseFlavorID,
|
||||||
IsModifierTemplate = 0,
|
ItemIsModifierTemplate = 0,
|
||||||
IsCheckedByDefault = 0
|
ItemIsCheckedByDefault = 0
|
||||||
WHERE ItemID IN (:chocolateID, :strawberryID, :vanillaID)
|
WHERE ItemID IN (:chocolateID, :strawberryID, :vanillaID)
|
||||||
", {
|
", {
|
||||||
chooseFlavorID: chooseFlavorID,
|
chooseFlavorID: chooseFlavorID,
|
||||||
|
|
@ -109,14 +109,14 @@ try {
|
||||||
|
|
||||||
// Step 3: Set Vanilla as default (common choice)
|
// Step 3: Set Vanilla as default (common choice)
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items SET IsCheckedByDefault = 1 WHERE ItemID = :vanillaID
|
UPDATE Items SET ItemIsCheckedByDefault = 1 WHERE ItemID = :vanillaID
|
||||||
", { vanillaID: vanillaID }, { datasource: "payfrit" });
|
", { vanillaID: vanillaID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(response.steps, "Set Vanilla as default flavor");
|
arrayAppend(response.steps, "Set Vanilla as default flavor");
|
||||||
|
|
||||||
// Step 4: Remove old template links for the flavors
|
// Step 4: Remove old template links for the flavors
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM lt_ItemID_TemplateItemID
|
DELETE FROM ItemTemplateLinks
|
||||||
WHERE TemplateItemID IN (:chocolateID, :strawberryID, :vanillaID)
|
WHERE TemplateItemID IN (:chocolateID, :strawberryID, :vanillaID)
|
||||||
", {
|
", {
|
||||||
chocolateID: chocolateID,
|
chocolateID: chocolateID,
|
||||||
|
|
@ -126,9 +126,9 @@ try {
|
||||||
|
|
||||||
arrayAppend(response.steps, "Removed old template links for flavor items");
|
arrayAppend(response.steps, "Removed old template links for flavor items");
|
||||||
|
|
||||||
// Step 5: Create lt_ItemID_TemplateItemID for Shake -> Choose Flavor
|
// Step 5: Create ItemTemplateLinks for Shake -> Choose Flavor
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder)
|
INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder)
|
||||||
VALUES (:shakeItemID, :chooseFlavorID, 0)
|
VALUES (:shakeItemID, :chooseFlavorID, 0)
|
||||||
ON DUPLICATE KEY UPDATE SortOrder = 0
|
ON DUPLICATE KEY UPDATE SortOrder = 0
|
||||||
", {
|
", {
|
||||||
|
|
@ -138,14 +138,14 @@ try {
|
||||||
|
|
||||||
arrayAppend(response.steps, "Created template link: Shake -> Choose Flavor");
|
arrayAppend(response.steps, "Created template link: Shake -> Choose Flavor");
|
||||||
|
|
||||||
// Step 6: Set RequiresChildSelection on shake
|
// Step 6: Set ItemRequiresChildSelection on shake
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET RequiresChildSelection = 1
|
SET ItemRequiresChildSelection = 1
|
||||||
WHERE ItemID = :shakeItemID
|
WHERE ItemID = :shakeItemID
|
||||||
", { shakeItemID: shakeItemID }, { datasource: "payfrit" });
|
", { shakeItemID: shakeItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(response.steps, "Set RequiresChildSelection=1 on Shake item");
|
arrayAppend(response.steps, "Set ItemRequiresChildSelection=1 on Shake item");
|
||||||
|
|
||||||
response["OK"] = true;
|
response["OK"] = true;
|
||||||
response["chooseFlavorID"] = chooseFlavorID;
|
response["chooseFlavorID"] = chooseFlavorID;
|
||||||
|
|
|
||||||
|
|
@ -75,17 +75,17 @@ function buildAddressString(line1, line2, city, zipCode) {
|
||||||
<cfif structKeyExists(url, "geocode") AND structKeyExists(url, "addressId")>
|
<cfif structKeyExists(url, "geocode") AND structKeyExists(url, "addressId")>
|
||||||
<cfset addressId = val(url.addressId)>
|
<cfset addressId = val(url.addressId)>
|
||||||
<cfquery name="addr" datasource="payfrit">
|
<cfquery name="addr" datasource="payfrit">
|
||||||
SELECT Line1, Line2, City, ZIPCode
|
SELECT AddressLine1, AddressLine2, AddressCity, AddressZIPCode
|
||||||
FROM Addresses WHERE ID = <cfqueryparam value="#addressId#" cfsqltype="cf_sql_integer">
|
FROM Addresses WHERE AddressID = <cfqueryparam value="#addressId#" cfsqltype="cf_sql_integer">
|
||||||
</cfquery>
|
</cfquery>
|
||||||
<cfif addr.recordCount GT 0>
|
<cfif addr.recordCount GT 0>
|
||||||
<cfset fullAddress = buildAddressString(addr.Line1, addr.Line2, addr.City, addr.ZIPCode)>
|
<cfset fullAddress = buildAddressString(addr.AddressLine1, addr.AddressLine2, addr.AddressCity, addr.AddressZIPCode)>
|
||||||
<cfset geo = geocodeAddress(fullAddress)>
|
<cfset geo = geocodeAddress(fullAddress)>
|
||||||
<cfif geo.success>
|
<cfif geo.success>
|
||||||
<cfquery datasource="payfrit">
|
<cfquery datasource="payfrit">
|
||||||
UPDATE Addresses SET Latitude = <cfqueryparam value="#geo.lat#" cfsqltype="cf_sql_decimal">,
|
UPDATE Addresses SET AddressLat = <cfqueryparam value="#geo.lat#" cfsqltype="cf_sql_decimal">,
|
||||||
Longitude = <cfqueryparam value="#geo.lng#" cfsqltype="cf_sql_decimal">
|
AddressLng = <cfqueryparam value="#geo.lng#" cfsqltype="cf_sql_decimal">
|
||||||
WHERE ID = <cfqueryparam value="#addressId#" cfsqltype="cf_sql_integer">
|
WHERE AddressID = <cfqueryparam value="#addressId#" cfsqltype="cf_sql_integer">
|
||||||
</cfquery>
|
</cfquery>
|
||||||
<cfoutput><div class="success">Geocoded Address ID #addressId#: #geo.lat#, #geo.lng#</div></cfoutput>
|
<cfoutput><div class="success">Geocoded Address ID #addressId#: #geo.lat#, #geo.lng#</div></cfoutput>
|
||||||
<cfelse>
|
<cfelse>
|
||||||
|
|
@ -96,21 +96,21 @@ function buildAddressString(line1, line2, city, zipCode) {
|
||||||
|
|
||||||
<cfif structKeyExists(url, "geocodeAll")>
|
<cfif structKeyExists(url, "geocodeAll")>
|
||||||
<cfquery name="missing" datasource="payfrit">
|
<cfquery name="missing" datasource="payfrit">
|
||||||
SELECT ID, Line1, Line2, City, ZIPCode
|
SELECT AddressID, AddressLine1, AddressLine2, AddressCity, AddressZIPCode
|
||||||
FROM Addresses
|
FROM Addresses
|
||||||
WHERE (Latitude IS NULL OR Latitude = 0)
|
WHERE (AddressLat IS NULL OR AddressLat = 0)
|
||||||
AND Line1 IS NOT NULL AND Line1 != ''
|
AND AddressLine1 IS NOT NULL AND AddressLine1 != ''
|
||||||
</cfquery>
|
</cfquery>
|
||||||
<cfset successCount = 0>
|
<cfset successCount = 0>
|
||||||
<cfset failCount = 0>
|
<cfset failCount = 0>
|
||||||
<cfloop query="missing">
|
<cfloop query="missing">
|
||||||
<cfset fullAddress = buildAddressString(missing.Line1, missing.Line2, missing.City, missing.ZIPCode)>
|
<cfset fullAddress = buildAddressString(missing.AddressLine1, missing.AddressLine2, missing.AddressCity, missing.AddressZIPCode)>
|
||||||
<cfset geo = geocodeAddress(fullAddress)>
|
<cfset geo = geocodeAddress(fullAddress)>
|
||||||
<cfif geo.success>
|
<cfif geo.success>
|
||||||
<cfquery datasource="payfrit">
|
<cfquery datasource="payfrit">
|
||||||
UPDATE Addresses SET Latitude = <cfqueryparam value="#geo.lat#" cfsqltype="cf_sql_decimal">,
|
UPDATE Addresses SET AddressLat = <cfqueryparam value="#geo.lat#" cfsqltype="cf_sql_decimal">,
|
||||||
Longitude = <cfqueryparam value="#geo.lng#" cfsqltype="cf_sql_decimal">
|
AddressLng = <cfqueryparam value="#geo.lng#" cfsqltype="cf_sql_decimal">
|
||||||
WHERE ID = <cfqueryparam value="#missing.ID#" cfsqltype="cf_sql_integer">
|
WHERE AddressID = <cfqueryparam value="#missing.AddressID#" cfsqltype="cf_sql_integer">
|
||||||
</cfquery>
|
</cfquery>
|
||||||
<cfset successCount = successCount + 1>
|
<cfset successCount = successCount + 1>
|
||||||
<cfelse>
|
<cfelse>
|
||||||
|
|
@ -123,23 +123,23 @@ function buildAddressString(line1, line2, city, zipCode) {
|
||||||
|
|
||||||
<cfquery name="addresses" datasource="payfrit">
|
<cfquery name="addresses" datasource="payfrit">
|
||||||
SELECT
|
SELECT
|
||||||
b.ID,
|
b.BusinessID,
|
||||||
b.Name,
|
b.BusinessName,
|
||||||
a.ID,
|
a.AddressID,
|
||||||
a.Line1,
|
a.AddressLine1,
|
||||||
a.Line2,
|
a.AddressLine2,
|
||||||
a.City,
|
a.AddressCity,
|
||||||
a.ZIPCode,
|
a.AddressZIPCode,
|
||||||
a.Latitude,
|
a.AddressLat,
|
||||||
a.Longitude
|
a.AddressLng
|
||||||
FROM Businesses b
|
FROM Businesses b
|
||||||
LEFT JOIN Addresses a ON b.AddressID = a.ID
|
LEFT JOIN Addresses a ON b.BusinessAddressID = a.AddressID
|
||||||
ORDER BY b.Name
|
ORDER BY b.BusinessName
|
||||||
</cfquery>
|
</cfquery>
|
||||||
|
|
||||||
<cfset missingCount = 0>
|
<cfset missingCount = 0>
|
||||||
<cfloop query="addresses">
|
<cfloop query="addresses">
|
||||||
<cfif (NOT len(addresses.Latitude) OR val(addresses.Latitude) EQ 0) AND len(addresses.Line1)>
|
<cfif (NOT len(addresses.AddressLat) OR val(addresses.AddressLat) EQ 0) AND len(addresses.AddressLine1)>
|
||||||
<cfset missingCount = missingCount + 1>
|
<cfset missingCount = missingCount + 1>
|
||||||
</cfif>
|
</cfif>
|
||||||
</cfloop>
|
</cfloop>
|
||||||
|
|
@ -166,31 +166,31 @@ function buildAddressString(line1, line2, city, zipCode) {
|
||||||
<cfloop query="addresses">
|
<cfloop query="addresses">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
#addresses.Name#
|
#addresses.BusinessName#
|
||||||
<cfif len(addresses.Latitude) AND val(addresses.Latitude) NEQ 0>
|
<cfif len(addresses.AddressLat) AND val(addresses.AddressLat) NEQ 0>
|
||||||
<span class="has-coords">#chr(10003)#</span>
|
<span class="has-coords">#chr(10003)#</span>
|
||||||
<cfelseif len(addresses.Line1)>
|
<cfelseif len(addresses.AddressLine1)>
|
||||||
<span class="no-coords">#chr(9679)#</span>
|
<span class="no-coords">#chr(9679)#</span>
|
||||||
</cfif>
|
</cfif>
|
||||||
</td>
|
</td>
|
||||||
<td class="address">
|
<td class="address">
|
||||||
<cfif len(addresses.Line1)>
|
<cfif len(addresses.AddressLine1)>
|
||||||
#addresses.Line1#<cfif len(addresses.Line2)>, #addresses.Line2#</cfif><br>
|
#addresses.AddressLine1#<cfif len(addresses.AddressLine2)>, #addresses.AddressLine2#</cfif><br>
|
||||||
#addresses.City# #addresses.ZIPCode#
|
#addresses.AddressCity# #addresses.AddressZIPCode#
|
||||||
<cfelse>
|
<cfelse>
|
||||||
<em style="color:##666;">No address</em>
|
<em style="color:##666;">No address</em>
|
||||||
</cfif>
|
</cfif>
|
||||||
</td>
|
</td>
|
||||||
<td class="coords">
|
<td class="coords">
|
||||||
<cfif len(addresses.Latitude) AND val(addresses.Latitude) NEQ 0>
|
<cfif len(addresses.AddressLat) AND val(addresses.AddressLat) NEQ 0>
|
||||||
#numberFormat(addresses.Latitude, "_.______")#<br>
|
#numberFormat(addresses.AddressLat, "_.______")#<br>
|
||||||
#numberFormat(addresses.Longitude, "_.______")#
|
#numberFormat(addresses.AddressLng, "_.______")#
|
||||||
<cfelse>
|
<cfelse>
|
||||||
-
|
-
|
||||||
</cfif>
|
</cfif>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<cfif len(addresses.Line1) AND len(addresses.AddressID)>
|
<cfif len(addresses.AddressLine1) AND len(addresses.AddressID)>
|
||||||
<a href="?geocode=1&addressId=#addresses.AddressID#"><button class="btn-lookup">Lookup</button></a>
|
<a href="?geocode=1&addressId=#addresses.AddressID#"><button class="btn-lookup">Lookup</button></a>
|
||||||
</cfif>
|
</cfif>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ try {
|
||||||
response["ERROR"] = "ChildBusinessID required";
|
response["ERROR"] = "ChildBusinessID required";
|
||||||
} else {
|
} else {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Businesses SET ParentBusinessID = :parentId WHERE ID = :childId
|
UPDATE Businesses SET BusinessParentBusinessID = :parentId WHERE BusinessID = :childId
|
||||||
", {
|
", {
|
||||||
parentId: { value = parentID > 0 ? parentID : javaCast("null", ""), cfsqltype = "cf_sql_integer", null = parentID == 0 },
|
parentId: { value = parentID > 0 ? parentID : javaCast("null", ""), cfsqltype = "cf_sql_integer", null = parentID == 0 },
|
||||||
childId: childID
|
childId: childID
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,13 @@ try {
|
||||||
|
|
||||||
// Step 1: Get all parent items (burgers, combos, etc.)
|
// Step 1: Get all parent items (burgers, combos, etc.)
|
||||||
qParentItems = queryExecute("
|
qParentItems = queryExecute("
|
||||||
SELECT i.ID, i.Name
|
SELECT i.ItemID, i.ItemName
|
||||||
FROM Items i
|
FROM Items i
|
||||||
INNER JOIN Categories c ON c.ID = i.CategoryID
|
INNER JOIN Categories c ON c.CategoryID = i.ItemCategoryID
|
||||||
WHERE c.BusinessID = :businessID
|
WHERE c.CategoryBusinessID = :businessID
|
||||||
AND i.ParentItemID = 0
|
AND i.ItemParentItemID = 0
|
||||||
AND i.IsActive = 1
|
AND i.ItemIsActive = 1
|
||||||
ORDER BY i.Name
|
ORDER BY i.ItemName
|
||||||
", { businessID: businessID }, { datasource: "payfrit" });
|
", { businessID: businessID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(response.steps, "Found " & qParentItems.recordCount & " parent items");
|
arrayAppend(response.steps, "Found " & qParentItems.recordCount & " parent items");
|
||||||
|
|
@ -41,20 +41,20 @@ try {
|
||||||
qModifiers = queryExecute("
|
qModifiers = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
m.ItemID,
|
m.ItemID,
|
||||||
m.Name,
|
m.ItemName,
|
||||||
m.ParentItemID,
|
m.ItemParentItemID,
|
||||||
m.Price,
|
m.ItemPrice,
|
||||||
m.IsCheckedByDefault,
|
m.ItemIsCheckedByDefault,
|
||||||
m.SortOrder,
|
m.ItemSortOrder,
|
||||||
p.Name as ParentName
|
p.ItemName as ParentName
|
||||||
FROM Items m
|
FROM Items m
|
||||||
INNER JOIN Items p ON p.ItemID = m.ParentItemID
|
INNER JOIN Items p ON p.ItemID = m.ItemParentItemID
|
||||||
INNER JOIN Categories c ON c.ID = p.CategoryID
|
INNER JOIN Categories c ON c.CategoryID = p.ItemCategoryID
|
||||||
WHERE c.BusinessID = :businessID
|
WHERE c.CategoryBusinessID = :businessID
|
||||||
AND m.ParentItemID > 0
|
AND m.ItemParentItemID > 0
|
||||||
AND m.IsActive = 1
|
AND m.ItemIsActive = 1
|
||||||
AND p.ParentItemID = 0
|
AND p.ItemParentItemID = 0
|
||||||
ORDER BY m.Name, m.ItemID
|
ORDER BY m.ItemName, m.ItemID
|
||||||
", { businessID: businessID }, { datasource: "payfrit" });
|
", { businessID: businessID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(response.steps, "Found " & qModifiers.recordCount & " level-1 modifiers");
|
arrayAppend(response.steps, "Found " & qModifiers.recordCount & " level-1 modifiers");
|
||||||
|
|
@ -62,17 +62,17 @@ try {
|
||||||
// Step 3: Group modifiers by name to find duplicates
|
// Step 3: Group modifiers by name to find duplicates
|
||||||
modifiersByName = {};
|
modifiersByName = {};
|
||||||
for (mod in qModifiers) {
|
for (mod in qModifiers) {
|
||||||
modName = mod.Name;
|
modName = mod.ItemName;
|
||||||
if (!structKeyExists(modifiersByName, modName)) {
|
if (!structKeyExists(modifiersByName, modName)) {
|
||||||
modifiersByName[modName] = [];
|
modifiersByName[modName] = [];
|
||||||
}
|
}
|
||||||
arrayAppend(modifiersByName[modName], {
|
arrayAppend(modifiersByName[modName], {
|
||||||
"ItemID": mod.ItemID,
|
"ItemID": mod.ItemID,
|
||||||
"ParentItemID": mod.ParentItemID,
|
"ParentItemID": mod.ItemParentItemID,
|
||||||
"ParentName": mod.ParentName,
|
"ParentName": mod.ParentName,
|
||||||
"Price": mod.Price,
|
"Price": mod.ItemPrice,
|
||||||
"IsDefault": mod.IsCheckedByDefault,
|
"IsDefault": mod.ItemIsCheckedByDefault,
|
||||||
"SortOrder": mod.SortOrder
|
"SortOrder": mod.ItemSortOrder
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,7 +91,7 @@ try {
|
||||||
|
|
||||||
// Mark as template
|
// Mark as template
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items SET IsModifierTemplate = 1 WHERE ItemID = :itemID
|
UPDATE Items SET ItemIsModifierTemplate = 1 WHERE ItemID = :itemID
|
||||||
", { itemID: templateItemID }, { datasource: "payfrit" });
|
", { itemID: templateItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
templateMap[modName] = templateItemID;
|
templateMap[modName] = templateItemID;
|
||||||
|
|
@ -111,7 +111,7 @@ try {
|
||||||
// Insert link (ignore duplicates)
|
// Insert link (ignore duplicates)
|
||||||
try {
|
try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder)
|
INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder)
|
||||||
VALUES (:itemID, :templateID, :sortOrder)
|
VALUES (:itemID, :templateID, :sortOrder)
|
||||||
ON DUPLICATE KEY UPDATE SortOrder = :sortOrder
|
ON DUPLICATE KEY UPDATE SortOrder = :sortOrder
|
||||||
", {
|
", {
|
||||||
|
|
@ -134,7 +134,7 @@ try {
|
||||||
if (i > 1) {
|
if (i > 1) {
|
||||||
arrayAppend(orphanItems, {
|
arrayAppend(orphanItems, {
|
||||||
"ItemID": inst.ItemID,
|
"ItemID": inst.ItemID,
|
||||||
"Name": modName,
|
"ItemName": modName,
|
||||||
"WasUnder": inst.ParentName
|
"WasUnder": inst.ParentName
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -143,12 +143,12 @@ try {
|
||||||
// Single instance - still mark as template for consistency
|
// Single instance - still mark as template for consistency
|
||||||
singleItem = instances[1];
|
singleItem = instances[1];
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items SET IsModifierTemplate = 1 WHERE ItemID = :itemID
|
UPDATE Items SET ItemIsModifierTemplate = 1 WHERE ItemID = :itemID
|
||||||
", { itemID: singleItem.ItemID }, { datasource: "payfrit" });
|
", { itemID: singleItem.ItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Create link
|
// Create link
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder)
|
INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder)
|
||||||
VALUES (:itemID, :templateID, :sortOrder)
|
VALUES (:itemID, :templateID, :sortOrder)
|
||||||
ON DUPLICATE KEY UPDATE SortOrder = :sortOrder
|
ON DUPLICATE KEY UPDATE SortOrder = :sortOrder
|
||||||
", {
|
", {
|
||||||
|
|
|
||||||
|
|
@ -27,20 +27,20 @@ try {
|
||||||
// Find all businesses with items in unified schema
|
// Find all businesses with items in unified schema
|
||||||
if (len(businessFilter)) {
|
if (len(businessFilter)) {
|
||||||
qBusinesses = queryExecute("
|
qBusinesses = queryExecute("
|
||||||
SELECT DISTINCT BusinessID as BusinessID
|
SELECT DISTINCT ItemBusinessID as BusinessID
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE BusinessID = :bid AND BusinessID > 0
|
WHERE ItemBusinessID = :bid AND ItemBusinessID > 0
|
||||||
", { bid: businessFilter }, { datasource: "payfrit" });
|
", { bid: businessFilter }, { datasource: "payfrit" });
|
||||||
} else {
|
} else {
|
||||||
qBusinesses = queryExecute("
|
qBusinesses = queryExecute("
|
||||||
SELECT DISTINCT BusinessID as BusinessID
|
SELECT DISTINCT ItemBusinessID as BusinessID
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE BusinessID > 0
|
WHERE ItemBusinessID > 0
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
|
|
||||||
for (biz in qBusinesses) {
|
for (biz in qBusinesses) {
|
||||||
bizId = biz.ID;
|
bizId = biz.BusinessID;
|
||||||
bizResult = { "BusinessID": bizId, "CategoriesCreated": 0, "ItemsUpdated": 0 };
|
bizResult = { "BusinessID": bizId, "CategoriesCreated": 0, "ItemsUpdated": 0 };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -48,26 +48,26 @@ try {
|
||||||
qCategoryItems = queryExecute("
|
qCategoryItems = queryExecute("
|
||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
p.ItemID,
|
p.ItemID,
|
||||||
p.Name,
|
p.ItemName,
|
||||||
p.SortOrder
|
p.ItemSortOrder
|
||||||
FROM Items p
|
FROM Items p
|
||||||
INNER JOIN Items c ON c.ParentItemID = p.ItemID
|
INNER JOIN Items c ON c.ItemParentItemID = p.ItemID
|
||||||
WHERE p.BusinessID = :bizId
|
WHERE p.ItemBusinessID = :bizId
|
||||||
AND p.ParentItemID = 0
|
AND p.ItemParentItemID = 0
|
||||||
AND (p.IsCollapsible = 0 OR p.IsCollapsible IS NULL)
|
AND (p.ItemIsCollapsible = 0 OR p.ItemIsCollapsible IS NULL)
|
||||||
AND NOT EXISTS (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = p.ItemID
|
SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = p.ItemID
|
||||||
)
|
)
|
||||||
ORDER BY p.SortOrder, p.Name
|
ORDER BY p.ItemSortOrder, p.ItemName
|
||||||
", { bizId: bizId }, { datasource: "payfrit" });
|
", { bizId: bizId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
sortOrder = 0;
|
sortOrder = 0;
|
||||||
for (catItem in qCategoryItems) {
|
for (catItem in qCategoryItems) {
|
||||||
// Check if category already exists for this business with same name
|
// Check if category already exists for this business with same name
|
||||||
qExisting = queryExecute("
|
qExisting = queryExecute("
|
||||||
SELECT ID FROM Categories
|
SELECT CategoryID FROM Categories
|
||||||
WHERE BusinessID = :bizId AND Name = :name
|
WHERE CategoryBusinessID = :bizId AND CategoryName = :name
|
||||||
", { bizId: bizId, name: left(catItem.Name, 30) }, { datasource: "payfrit" });
|
", { bizId: bizId, name: left(catItem.ItemName, 30) }, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qExisting.recordCount == 0) {
|
if (qExisting.recordCount == 0) {
|
||||||
// Get next CategoryID
|
// Get next CategoryID
|
||||||
|
|
@ -79,12 +79,12 @@ try {
|
||||||
// Create new category with explicit ID
|
// Create new category with explicit ID
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Categories
|
INSERT INTO Categories
|
||||||
(CategoryID, BusinessID, ParentCategoryID, Name, SortOrder, AddedOn)
|
(CategoryID, CategoryBusinessID, CategoryParentCategoryID, CategoryName, CategorySortOrder, CategoryAddedOn)
|
||||||
VALUES (:catId, :bizId, 0, :name, :sortOrder, NOW())
|
VALUES (:catId, :bizId, 0, :name, :sortOrder, NOW())
|
||||||
", {
|
", {
|
||||||
catId: newCatId,
|
catId: newCatId,
|
||||||
bizId: bizId,
|
bizId: bizId,
|
||||||
name: left(catItem.Name, 30),
|
name: left(catItem.ItemName, 30),
|
||||||
sortOrder: sortOrder
|
sortOrder: sortOrder
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
|
|
@ -96,9 +96,9 @@ try {
|
||||||
// Update all children of this category Item to have the new CategoryID
|
// Update all children of this category Item to have the new CategoryID
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET CategoryID = :catId
|
SET ItemCategoryID = :catId
|
||||||
WHERE ParentItemID = :parentId
|
WHERE ItemParentItemID = :parentId
|
||||||
AND BusinessID = :bizId
|
AND ItemBusinessID = :bizId
|
||||||
", {
|
", {
|
||||||
catId: newCatId,
|
catId: newCatId,
|
||||||
parentId: catItem.ItemID,
|
parentId: catItem.ItemID,
|
||||||
|
|
|
||||||
|
|
@ -1,299 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfsetting enablecfoutputonly="false">
|
|
||||||
<cfscript>
|
|
||||||
// Localhost-only protection
|
|
||||||
remoteAddr = cgi.REMOTE_ADDR;
|
|
||||||
if (remoteAddr != "127.0.0.1" && remoteAddr != "::1" && remoteAddr != "0:0:0:0:0:0:0:1" && remoteAddr != "10.10.0.2") {
|
|
||||||
writeOutput("Forbidden"); abort;
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>API Performance Dashboard</title>
|
|
||||||
<style>
|
|
||||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
||||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; background: #0f1117; color: #e1e4e8; padding: 20px; }
|
|
||||||
h1 { font-size: 22px; font-weight: 600; margin-bottom: 16px; color: #fff; }
|
|
||||||
.controls { display: flex; gap: 10px; margin-bottom: 20px; align-items: center; flex-wrap: wrap; }
|
|
||||||
.controls label { font-size: 13px; color: #8b949e; }
|
|
||||||
.controls select, .controls input { background: #1c1f26; border: 1px solid #30363d; color: #e1e4e8; padding: 6px 10px; border-radius: 6px; font-size: 13px; }
|
|
||||||
.controls button { background: #238636; color: #fff; border: none; padding: 6px 16px; border-radius: 6px; font-size: 13px; cursor: pointer; font-weight: 500; }
|
|
||||||
.controls button:hover { background: #2ea043; }
|
|
||||||
.controls button.secondary { background: #30363d; }
|
|
||||||
.controls button.secondary:hover { background: #3d444d; }
|
|
||||||
|
|
||||||
.summary-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 24px; }
|
|
||||||
.card { background: #1c1f26; border: 1px solid #30363d; border-radius: 8px; padding: 16px; }
|
|
||||||
.card .label { font-size: 11px; color: #8b949e; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 4px; }
|
|
||||||
.card .value { font-size: 28px; font-weight: 700; color: #fff; }
|
|
||||||
.card .unit { font-size: 13px; color: #8b949e; font-weight: 400; }
|
|
||||||
|
|
||||||
.section { margin-bottom: 28px; }
|
|
||||||
.section h2 { font-size: 15px; font-weight: 600; margin-bottom: 10px; color: #c9d1d9; display: flex; align-items: center; gap: 8px; }
|
|
||||||
.section h2 .badge { background: #30363d; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 500; color: #8b949e; }
|
|
||||||
|
|
||||||
table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
|
||||||
thead th { text-align: left; padding: 8px 12px; border-bottom: 1px solid #30363d; color: #8b949e; font-weight: 500; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; white-space: nowrap; }
|
|
||||||
thead th.num { text-align: right; }
|
|
||||||
tbody td { padding: 8px 12px; border-bottom: 1px solid #1c1f26; }
|
|
||||||
tbody td.num { text-align: right; font-variant-numeric: tabular-nums; }
|
|
||||||
tbody tr:hover { background: #1c1f26; }
|
|
||||||
tbody td.endpoint { font-family: 'SF Mono', 'Fira Code', monospace; font-size: 12px; color: #58a6ff; }
|
|
||||||
|
|
||||||
.bar-cell { position: relative; }
|
|
||||||
.bar-bg { position: absolute; left: 0; top: 2px; bottom: 2px; border-radius: 3px; opacity: 0.15; }
|
|
||||||
.bar-db { background: #f0883e; }
|
|
||||||
.bar-app { background: #58a6ff; }
|
|
||||||
.bar-wrap { display: flex; height: 18px; border-radius: 3px; overflow: hidden; min-width: 80px; }
|
|
||||||
.bar-seg-db { background: #f0883e; height: 100%; }
|
|
||||||
.bar-seg-app { background: #58a6ff; height: 100%; }
|
|
||||||
|
|
||||||
.legend { display: flex; gap: 16px; font-size: 11px; color: #8b949e; margin-bottom: 12px; }
|
|
||||||
.legend span { display: flex; align-items: center; gap: 4px; }
|
|
||||||
.legend .dot { width: 10px; height: 10px; border-radius: 2px; }
|
|
||||||
.legend .dot.db { background: #f0883e; }
|
|
||||||
.legend .dot.app { background: #58a6ff; }
|
|
||||||
|
|
||||||
.status { padding: 8px 12px; background: #1c1f26; border-radius: 6px; font-size: 12px; color: #8b949e; margin-bottom: 16px; }
|
|
||||||
.status.error { border: 1px solid #da3633; color: #f85149; }
|
|
||||||
.status.loading { border: 1px solid #30363d; }
|
|
||||||
|
|
||||||
.tag { display: inline-block; padding: 1px 6px; border-radius: 4px; font-size: 11px; font-weight: 500; }
|
|
||||||
.tag.fast { background: #23863620; color: #3fb950; }
|
|
||||||
.tag.ok { background: #d29b0020; color: #d29922; }
|
|
||||||
.tag.slow { background: #da363320; color: #f85149; }
|
|
||||||
|
|
||||||
.auto-refresh { display: flex; align-items: center; gap: 6px; margin-left: auto; }
|
|
||||||
.auto-refresh input[type=checkbox] { accent-color: #238636; }
|
|
||||||
.timestamp { font-size: 11px; color: #484f58; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<h1>API Performance Dashboard</h1>
|
|
||||||
|
|
||||||
<div class="controls">
|
|
||||||
<label>Time range:
|
|
||||||
<select id="hours">
|
|
||||||
<option value="1">Last 1 hour</option>
|
|
||||||
<option value="6">Last 6 hours</option>
|
|
||||||
<option value="24" selected>Last 24 hours</option>
|
|
||||||
<option value="72">Last 3 days</option>
|
|
||||||
<option value="168">Last 7 days</option>
|
|
||||||
<option value="720">Last 30 days</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<label>Rows:
|
|
||||||
<input type="number" id="limit" value="20" min="5" max="100" style="width:60px">
|
|
||||||
</label>
|
|
||||||
<button onclick="loadAll()">Refresh</button>
|
|
||||||
<div class="auto-refresh">
|
|
||||||
<input type="checkbox" id="autoRefresh">
|
|
||||||
<label for="autoRefresh" style="font-size:12px;color:#8b949e;cursor:pointer">Auto-refresh 30s</label>
|
|
||||||
</div>
|
|
||||||
<span class="timestamp" id="lastUpdated"></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="status" class="status loading">Loading...</div>
|
|
||||||
|
|
||||||
<div id="summarySection" class="section" style="display:none">
|
|
||||||
<div class="summary-cards" id="summaryCards"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="legend">
|
|
||||||
<span><span class="dot db"></span> DB time</span>
|
|
||||||
<span><span class="dot app"></span> App time</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="countSection" class="section" style="display:none">
|
|
||||||
<h2>Top Endpoints by Volume <span class="badge" id="countBadge"></span></h2>
|
|
||||||
<div style="overflow-x:auto"><table id="countTable"><thead></thead><tbody></tbody></table></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="latencySection" class="section" style="display:none">
|
|
||||||
<h2>Top Endpoints by Latency <span class="badge" id="latencyBadge"></span></h2>
|
|
||||||
<div style="overflow-x:auto"><table id="latencyTable"><thead></thead><tbody></tbody></table></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="slowSection" class="section" style="display:none">
|
|
||||||
<h2>Slowest Individual Requests <span class="badge" id="slowBadge"></span></h2>
|
|
||||||
<div style="overflow-x:auto"><table id="slowTable"><thead></thead><tbody></tbody></table></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const API = 'perf.cfm';
|
|
||||||
let refreshTimer = null;
|
|
||||||
|
|
||||||
function qs(s) { return document.querySelector(s); }
|
|
||||||
function fmt(n) { return n == null ? '-' : Number(n).toLocaleString(); }
|
|
||||||
function fmtMs(n) {
|
|
||||||
if (n == null) return '-';
|
|
||||||
n = Number(n);
|
|
||||||
if (n < 100) return '<span class="tag fast">' + n + 'ms</span>';
|
|
||||||
if (n < 500) return '<span class="tag ok">' + n + 'ms</span>';
|
|
||||||
return '<span class="tag slow">' + n + 'ms</span>';
|
|
||||||
}
|
|
||||||
function fmtBytes(n) {
|
|
||||||
if (!n) return '-';
|
|
||||||
n = Number(n);
|
|
||||||
if (n < 1024) return n + ' B';
|
|
||||||
if (n < 1048576) return (n / 1024).toFixed(1) + ' KB';
|
|
||||||
return (n / 1048576).toFixed(1) + ' MB';
|
|
||||||
}
|
|
||||||
function pct(part, total) { return total > 0 ? Math.round(part / total * 100) : 0; }
|
|
||||||
|
|
||||||
function timeBar(dbMs, appMs) {
|
|
||||||
var total = (dbMs || 0) + (appMs || 0);
|
|
||||||
if (total === 0) return '';
|
|
||||||
var dbPct = pct(dbMs, total);
|
|
||||||
var appPct = 100 - dbPct;
|
|
||||||
return '<div class="bar-wrap" title="DB: ' + dbMs + 'ms / App: ' + appMs + 'ms">'
|
|
||||||
+ '<div class="bar-seg-db" style="width:' + dbPct + '%"></div>'
|
|
||||||
+ '<div class="bar-seg-app" style="width:' + appPct + '%"></div>'
|
|
||||||
+ '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function endpointName(ep) {
|
|
||||||
return ep.replace(/^\/api\//, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchView(view) {
|
|
||||||
var h = qs('#hours').value;
|
|
||||||
var l = qs('#limit').value;
|
|
||||||
var r = await fetch(API + '?view=' + view + '&hours=' + h + '&limit=' + l);
|
|
||||||
return r.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadAll() {
|
|
||||||
qs('#status').className = 'status loading';
|
|
||||||
qs('#status').textContent = 'Loading...';
|
|
||||||
qs('#status').style.display = '';
|
|
||||||
|
|
||||||
try {
|
|
||||||
var [summary, count, latency, slow] = await Promise.all([
|
|
||||||
fetchView('summary'), fetchView('count'), fetchView('latency'), fetchView('slow')
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!summary.OK) throw new Error(summary.MESSAGE || summary.ERROR);
|
|
||||||
|
|
||||||
qs('#status').style.display = 'none';
|
|
||||||
|
|
||||||
// Summary cards
|
|
||||||
var s = summary.DATA;
|
|
||||||
qs('#summaryCards').innerHTML =
|
|
||||||
card('Total Requests', fmt(s.TotalRequests), '') +
|
|
||||||
card('Unique Endpoints', fmt(s.UniqueEndpoints), '') +
|
|
||||||
card('Avg Latency', s.OverallAvgMs || 0, 'ms') +
|
|
||||||
card('Max Latency', s.OverallMaxMs || 0, 'ms') +
|
|
||||||
card('Avg DB Time', s.OverallAvgDbMs || 0, 'ms') +
|
|
||||||
card('Avg App Time', s.OverallAvgAppMs || 0, 'ms') +
|
|
||||||
card('Avg Queries', s.OverallAvgQueries || 0, '/req') +
|
|
||||||
card('Data Since', s.FirstLog || 'none', '');
|
|
||||||
qs('#summarySection').style.display = '';
|
|
||||||
|
|
||||||
// Count table
|
|
||||||
renderCountTable(count.DATA || []);
|
|
||||||
|
|
||||||
// Latency table
|
|
||||||
renderLatencyTable(latency.DATA || []);
|
|
||||||
|
|
||||||
// Slow table
|
|
||||||
renderSlowTable(slow.DATA || []);
|
|
||||||
|
|
||||||
qs('#lastUpdated').textContent = 'Updated ' + new Date().toLocaleTimeString();
|
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
qs('#status').className = 'status error';
|
|
||||||
qs('#status').textContent = 'Error: ' + e.message;
|
|
||||||
qs('#status').style.display = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function card(label, value, unit) {
|
|
||||||
return '<div class="card"><div class="label">' + label + '</div><div class="value">' + value + ' <span class="unit">' + unit + '</span></div></div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderCountTable(data) {
|
|
||||||
if (!data.length) { qs('#countSection').style.display = 'none'; return; }
|
|
||||||
qs('#countBadge').textContent = data.length + ' endpoints';
|
|
||||||
var maxCalls = Math.max(...data.map(r => r.Calls));
|
|
||||||
var html = '<thead><tr><th>Endpoint</th><th class="num">Calls</th><th class="num">Avg</th><th class="num">DB</th><th class="num">App</th><th>DB / App Split</th><th class="num">Max</th><th class="num">Queries</th><th class="num">Avg Size</th></tr></thead><tbody>';
|
|
||||||
data.forEach(function(r) {
|
|
||||||
html += '<tr>'
|
|
||||||
+ '<td class="endpoint">' + endpointName(r.Endpoint) + '</td>'
|
|
||||||
+ '<td class="num">' + fmt(r.Calls) + '</td>'
|
|
||||||
+ '<td class="num">' + fmtMs(r.AvgMs) + '</td>'
|
|
||||||
+ '<td class="num">' + fmt(r.AvgDbMs) + 'ms</td>'
|
|
||||||
+ '<td class="num">' + fmt(r.AvgAppMs) + 'ms</td>'
|
|
||||||
+ '<td>' + timeBar(r.AvgDbMs, r.AvgAppMs) + '</td>'
|
|
||||||
+ '<td class="num">' + fmtMs(r.MaxMs) + '</td>'
|
|
||||||
+ '<td class="num">' + r.AvgQueries + '</td>'
|
|
||||||
+ '<td class="num">' + fmtBytes(r.AvgBytes) + '</td>'
|
|
||||||
+ '</tr>';
|
|
||||||
});
|
|
||||||
html += '</tbody>';
|
|
||||||
qs('#countTable').innerHTML = html;
|
|
||||||
qs('#countSection').style.display = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderLatencyTable(data) {
|
|
||||||
if (!data.length) { qs('#latencySection').style.display = 'none'; return; }
|
|
||||||
qs('#latencyBadge').textContent = data.length + ' endpoints';
|
|
||||||
var html = '<thead><tr><th>Endpoint</th><th class="num">Calls</th><th class="num">Avg</th><th class="num">DB</th><th class="num">App</th><th>DB / App Split</th><th class="num">Max</th><th class="num">Queries</th></tr></thead><tbody>';
|
|
||||||
data.forEach(function(r) {
|
|
||||||
html += '<tr>'
|
|
||||||
+ '<td class="endpoint">' + endpointName(r.Endpoint) + '</td>'
|
|
||||||
+ '<td class="num">' + fmt(r.Calls) + '</td>'
|
|
||||||
+ '<td class="num">' + fmtMs(r.AvgMs) + '</td>'
|
|
||||||
+ '<td class="num">' + fmt(r.AvgDbMs) + 'ms</td>'
|
|
||||||
+ '<td class="num">' + fmt(r.AvgAppMs) + 'ms</td>'
|
|
||||||
+ '<td>' + timeBar(r.AvgDbMs, r.AvgAppMs) + '</td>'
|
|
||||||
+ '<td class="num">' + fmtMs(r.MaxMs) + '</td>'
|
|
||||||
+ '<td class="num">' + r.AvgQueries + '</td>'
|
|
||||||
+ '</tr>';
|
|
||||||
});
|
|
||||||
html += '</tbody>';
|
|
||||||
qs('#latencyTable').innerHTML = html;
|
|
||||||
qs('#latencySection').style.display = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderSlowTable(data) {
|
|
||||||
if (!data.length) { qs('#slowSection').style.display = 'none'; return; }
|
|
||||||
qs('#slowBadge').textContent = data.length + ' requests';
|
|
||||||
var html = '<thead><tr><th>Endpoint</th><th class="num">Total</th><th class="num">DB</th><th class="num">App</th><th>DB / App Split</th><th class="num">Queries</th><th class="num">Size</th><th class="num">Biz</th><th>When</th></tr></thead><tbody>';
|
|
||||||
data.forEach(function(r) {
|
|
||||||
html += '<tr>'
|
|
||||||
+ '<td class="endpoint">' + endpointName(r.Endpoint) + '</td>'
|
|
||||||
+ '<td class="num">' + fmtMs(r.TotalMs) + '</td>'
|
|
||||||
+ '<td class="num">' + fmt(r.DbMs) + 'ms</td>'
|
|
||||||
+ '<td class="num">' + fmt(r.AppMs) + 'ms</td>'
|
|
||||||
+ '<td>' + timeBar(r.DbMs, r.AppMs) + '</td>'
|
|
||||||
+ '<td class="num">' + r.QueryCount + '</td>'
|
|
||||||
+ '<td class="num">' + fmtBytes(r.ResponseBytes) + '</td>'
|
|
||||||
+ '<td class="num">' + (r.BusinessID || '-') + '</td>'
|
|
||||||
+ '<td style="font-size:11px;color:#8b949e;white-space:nowrap">' + (r.LoggedAt || '') + '</td>'
|
|
||||||
+ '</tr>';
|
|
||||||
});
|
|
||||||
html += '</tbody>';
|
|
||||||
qs('#slowTable').innerHTML = html;
|
|
||||||
qs('#slowSection').style.display = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-refresh
|
|
||||||
qs('#autoRefresh').addEventListener('change', function() {
|
|
||||||
if (this.checked) {
|
|
||||||
refreshTimer = setInterval(loadAll, 30000);
|
|
||||||
} else {
|
|
||||||
clearInterval(refreshTimer);
|
|
||||||
refreshTimer = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Load on page open
|
|
||||||
loadAll();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfsetting enablecfoutputonly="true">
|
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
||||||
<cfheader name="Cache-Control" value="no-store">
|
|
||||||
|
|
||||||
<cfscript>
|
|
||||||
function apiAbort(payload) {
|
|
||||||
writeOutput(serializeJSON(payload));
|
|
||||||
abort;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Localhost-only protection
|
|
||||||
remoteAddr = cgi.REMOTE_ADDR;
|
|
||||||
if (remoteAddr != "127.0.0.1" && remoteAddr != "::1" && remoteAddr != "0:0:0:0:0:0:0:1" && remoteAddr != "10.10.0.2") {
|
|
||||||
apiAbort({ "OK": false, "ERROR": "forbidden" });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Parse parameters
|
|
||||||
view = structKeyExists(url, "view") ? lcase(url.view) : "count";
|
|
||||||
hours = structKeyExists(url, "hours") ? val(url.hours) : 24;
|
|
||||||
if (hours <= 0 || hours > 720) hours = 24;
|
|
||||||
limitRows = structKeyExists(url, "limit") ? val(url.limit) : 20;
|
|
||||||
if (limitRows <= 0 || limitRows > 100) limitRows = 20;
|
|
||||||
|
|
||||||
// Flush any buffered metrics first
|
|
||||||
flushPerfBuffer();
|
|
||||||
|
|
||||||
response = { "OK": true, "VIEW": view, "HOURS": hours };
|
|
||||||
|
|
||||||
if (view == "count") {
|
|
||||||
// Top endpoints by call count
|
|
||||||
q = queryExecute("
|
|
||||||
SELECT
|
|
||||||
Endpoint,
|
|
||||||
COUNT(*) as Calls,
|
|
||||||
ROUND(AVG(TotalMs)) as AvgMs,
|
|
||||||
ROUND(AVG(DbMs)) as AvgDbMs,
|
|
||||||
ROUND(AVG(AppMs)) as AvgAppMs,
|
|
||||||
MAX(TotalMs) as MaxMs,
|
|
||||||
ROUND(AVG(QueryCount), 1) as AvgQueries,
|
|
||||||
ROUND(AVG(ResponseBytes)) as AvgBytes
|
|
||||||
FROM ApiPerfLogs
|
|
||||||
WHERE LoggedAt > DATE_SUB(NOW(), INTERVAL :hours HOUR)
|
|
||||||
GROUP BY Endpoint
|
|
||||||
ORDER BY Calls DESC
|
|
||||||
LIMIT :lim
|
|
||||||
", {
|
|
||||||
hours: { value: hours, cfsqltype: "cf_sql_integer" },
|
|
||||||
lim: { value: limitRows, cfsqltype: "cf_sql_integer" }
|
|
||||||
}, { datasource: "payfrit" });
|
|
||||||
|
|
||||||
rows = [];
|
|
||||||
for (row in q) {
|
|
||||||
arrayAppend(rows, {
|
|
||||||
"Endpoint": row.Endpoint,
|
|
||||||
"Calls": row.Calls,
|
|
||||||
"AvgMs": row.AvgMs,
|
|
||||||
"AvgDbMs": row.AvgDbMs,
|
|
||||||
"AvgAppMs": row.AvgAppMs,
|
|
||||||
"MaxMs": row.MaxMs,
|
|
||||||
"AvgQueries": row.AvgQueries,
|
|
||||||
"AvgBytes": row.AvgBytes
|
|
||||||
});
|
|
||||||
}
|
|
||||||
response["DATA"] = rows;
|
|
||||||
|
|
||||||
} else if (view == "latency") {
|
|
||||||
// Top endpoints by average latency
|
|
||||||
q = queryExecute("
|
|
||||||
SELECT
|
|
||||||
Endpoint,
|
|
||||||
COUNT(*) as Calls,
|
|
||||||
ROUND(AVG(TotalMs)) as AvgMs,
|
|
||||||
ROUND(AVG(DbMs)) as AvgDbMs,
|
|
||||||
ROUND(AVG(AppMs)) as AvgAppMs,
|
|
||||||
MAX(TotalMs) as MaxMs,
|
|
||||||
ROUND(AVG(QueryCount), 1) as AvgQueries
|
|
||||||
FROM ApiPerfLogs
|
|
||||||
WHERE LoggedAt > DATE_SUB(NOW(), INTERVAL :hours HOUR)
|
|
||||||
GROUP BY Endpoint
|
|
||||||
HAVING Calls >= 3
|
|
||||||
ORDER BY AvgMs DESC
|
|
||||||
LIMIT :lim
|
|
||||||
", {
|
|
||||||
hours: { value: hours, cfsqltype: "cf_sql_integer" },
|
|
||||||
lim: { value: limitRows, cfsqltype: "cf_sql_integer" }
|
|
||||||
}, { datasource: "payfrit" });
|
|
||||||
|
|
||||||
rows = [];
|
|
||||||
for (row in q) {
|
|
||||||
arrayAppend(rows, {
|
|
||||||
"Endpoint": row.Endpoint,
|
|
||||||
"Calls": row.Calls,
|
|
||||||
"AvgMs": row.AvgMs,
|
|
||||||
"AvgDbMs": row.AvgDbMs,
|
|
||||||
"AvgAppMs": row.AvgAppMs,
|
|
||||||
"MaxMs": row.MaxMs,
|
|
||||||
"AvgQueries": row.AvgQueries
|
|
||||||
});
|
|
||||||
}
|
|
||||||
response["DATA"] = rows;
|
|
||||||
|
|
||||||
} else if (view == "slow") {
|
|
||||||
// Slowest individual requests
|
|
||||||
q = queryExecute("
|
|
||||||
SELECT Endpoint, TotalMs, DbMs, AppMs, QueryCount, ResponseBytes,
|
|
||||||
BusinessID, UserID, LoggedAt
|
|
||||||
FROM ApiPerfLogs
|
|
||||||
WHERE LoggedAt > DATE_SUB(NOW(), INTERVAL :hours HOUR)
|
|
||||||
ORDER BY TotalMs DESC
|
|
||||||
LIMIT :lim
|
|
||||||
", {
|
|
||||||
hours: { value: hours, cfsqltype: "cf_sql_integer" },
|
|
||||||
lim: { value: limitRows, cfsqltype: "cf_sql_integer" }
|
|
||||||
}, { datasource: "payfrit" });
|
|
||||||
|
|
||||||
rows = [];
|
|
||||||
for (row in q) {
|
|
||||||
arrayAppend(rows, {
|
|
||||||
"Endpoint": row.Endpoint,
|
|
||||||
"TotalMs": row.TotalMs,
|
|
||||||
"DbMs": row.DbMs,
|
|
||||||
"AppMs": row.AppMs,
|
|
||||||
"QueryCount": row.QueryCount,
|
|
||||||
"ResponseBytes": row.ResponseBytes,
|
|
||||||
"BusinessID": row.BusinessID,
|
|
||||||
"UserID": row.UserID,
|
|
||||||
"LoggedAt": dateTimeFormat(row.LoggedAt, "yyyy-mm-dd HH:nn:ss")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
response["DATA"] = rows;
|
|
||||||
|
|
||||||
} else if (view == "summary") {
|
|
||||||
// Overall summary stats
|
|
||||||
q = queryExecute("
|
|
||||||
SELECT
|
|
||||||
COUNT(*) as TotalRequests,
|
|
||||||
COUNT(DISTINCT Endpoint) as UniqueEndpoints,
|
|
||||||
ROUND(AVG(TotalMs)) as OverallAvgMs,
|
|
||||||
MAX(TotalMs) as OverallMaxMs,
|
|
||||||
ROUND(AVG(DbMs)) as OverallAvgDbMs,
|
|
||||||
ROUND(AVG(AppMs)) as OverallAvgAppMs,
|
|
||||||
ROUND(AVG(QueryCount), 1) as OverallAvgQueries,
|
|
||||||
MIN(LoggedAt) as FirstLog,
|
|
||||||
MAX(LoggedAt) as LastLog
|
|
||||||
FROM ApiPerfLogs
|
|
||||||
WHERE LoggedAt > DATE_SUB(NOW(), INTERVAL :hours HOUR)
|
|
||||||
", {
|
|
||||||
hours: { value: hours, cfsqltype: "cf_sql_integer" }
|
|
||||||
}, { datasource: "payfrit" });
|
|
||||||
|
|
||||||
response["DATA"] = {
|
|
||||||
"TotalRequests": q.TotalRequests,
|
|
||||||
"UniqueEndpoints": q.UniqueEndpoints,
|
|
||||||
"OverallAvgMs": q.OverallAvgMs,
|
|
||||||
"OverallMaxMs": q.OverallMaxMs,
|
|
||||||
"OverallAvgDbMs": q.OverallAvgDbMs,
|
|
||||||
"OverallAvgAppMs": q.OverallAvgAppMs,
|
|
||||||
"OverallAvgQueries": q.OverallAvgQueries,
|
|
||||||
"FirstLog": isDate(q.FirstLog) ? dateTimeFormat(q.FirstLog, "yyyy-mm-dd HH:nn:ss") : "",
|
|
||||||
"LastLog": isDate(q.LastLog) ? dateTimeFormat(q.LastLog, "yyyy-mm-dd HH:nn:ss") : ""
|
|
||||||
};
|
|
||||||
|
|
||||||
} else {
|
|
||||||
apiAbort({ "OK": false, "ERROR": "invalid_view", "MESSAGE": "Use ?view=count|latency|slow|summary" });
|
|
||||||
}
|
|
||||||
|
|
||||||
apiAbort(response);
|
|
||||||
|
|
||||||
} catch (any e) {
|
|
||||||
apiAbort({
|
|
||||||
"OK": false,
|
|
||||||
"ERROR": "server_error",
|
|
||||||
"MESSAGE": e.message,
|
|
||||||
"DETAIL": e.detail
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
||||||
|
|
||||||
<cfscript>
|
|
||||||
// Add TaskTypeID column to QuickTaskTemplates table if it doesn't exist
|
|
||||||
try {
|
|
||||||
// Check if column exists
|
|
||||||
qCheck = queryExecute("
|
|
||||||
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = 'payfrit'
|
|
||||||
AND TABLE_NAME = 'QuickTaskTemplates'
|
|
||||||
AND COLUMN_NAME = 'TaskTypeID'
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
if (qCheck.recordCount == 0) {
|
|
||||||
queryExecute("
|
|
||||||
ALTER TABLE QuickTaskTemplates
|
|
||||||
ADD COLUMN TaskTypeID INT NULL AFTER TaskCategoryID
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"MESSAGE": "Column TaskTypeID added to QuickTaskTemplates"
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"MESSAGE": "Column already exists"
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} catch (any e) {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": false,
|
|
||||||
"ERROR": e.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfsetting enablecfoutputonly="true">
|
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
||||||
|
|
||||||
<cfscript>
|
|
||||||
// One-time cleanup: delete test tasks and reset
|
|
||||||
try {
|
|
||||||
// Delete tasks 30, 31, 32 (test tasks with bad data)
|
|
||||||
queryExecute("DELETE FROM Tasks WHERE ID IN (30, 31, 32)", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"MESSAGE": "Cleanup complete - deleted test tasks"
|
|
||||||
}));
|
|
||||||
} catch (any e) {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": false,
|
|
||||||
"ERROR": e.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -50,13 +50,14 @@ try {
|
||||||
// Get template details
|
// Get template details
|
||||||
qTemplate = queryExecute("
|
qTemplate = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
Title as Title,
|
QuickTaskTemplateTitle as Title,
|
||||||
Details as Details,
|
QuickTaskTemplateDetails as Details,
|
||||||
TaskCategoryID as CategoryID
|
QuickTaskTemplateCategoryID as CategoryID,
|
||||||
|
QuickTaskTemplateTypeID as TypeID
|
||||||
FROM QuickTaskTemplates
|
FROM QuickTaskTemplates
|
||||||
WHERE ID = :id
|
WHERE QuickTaskTemplateID = :id
|
||||||
AND BusinessID = :businessID
|
AND QuickTaskTemplateBusinessID = :businessID
|
||||||
AND IsActive = 1
|
AND QuickTaskTemplateIsActive = 1
|
||||||
", {
|
", {
|
||||||
id: { value: templateID, cfsqltype: "cf_sql_integer" },
|
id: { value: templateID, cfsqltype: "cf_sql_integer" },
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -66,21 +67,24 @@ try {
|
||||||
apiAbort({ "OK": false, "ERROR": "not_found", "MESSAGE": "Template not found" });
|
apiAbort({ "OK": false, "ERROR": "not_found", "MESSAGE": "Template not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the task (ClaimedByUserID=0 means unclaimed/pending)
|
// Create the task
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Tasks (
|
INSERT INTO Tasks (
|
||||||
BusinessID, CategoryID, TaskTypeID,
|
TaskBusinessID, TaskCategoryID, TaskTypeID,
|
||||||
Title, Details, CreatedOn, ClaimedByUserID
|
TaskTitle, TaskDetails, TaskStatusID, TaskAddedOn,
|
||||||
|
TaskSourceType, TaskSourceID
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:businessID, :categoryID, :typeID,
|
:businessID, :categoryID, :typeID,
|
||||||
:title, :details, NOW(), 0
|
:title, :details, 0, NOW(),
|
||||||
|
'quicktask', :templateID
|
||||||
)
|
)
|
||||||
", {
|
", {
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
||||||
categoryID: { value: qTemplate.CategoryID, cfsqltype: "cf_sql_integer", null: isNull(qTemplate.CategoryID) },
|
categoryID: { value: qTemplate.CategoryID, cfsqltype: "cf_sql_integer", null: isNull(qTemplate.CategoryID) },
|
||||||
typeID: { value: 0, cfsqltype: "cf_sql_integer" },
|
typeID: { value: qTemplate.TypeID, cfsqltype: "cf_sql_integer", null: isNull(qTemplate.TypeID) },
|
||||||
title: { value: qTemplate.Title, cfsqltype: "cf_sql_varchar" },
|
title: { value: qTemplate.Title, cfsqltype: "cf_sql_varchar" },
|
||||||
details: { value: qTemplate.Details, cfsqltype: "cf_sql_longvarchar", null: isNull(qTemplate.Details) }
|
details: { value: qTemplate.Details, cfsqltype: "cf_sql_longvarchar", null: isNull(qTemplate.Details) },
|
||||||
|
templateID: { value: templateID, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
qNew = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" });
|
qNew = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" });
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfsetting enablecfoutputonly="true">
|
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
||||||
|
|
||||||
<cfscript>
|
|
||||||
try {
|
|
||||||
q = queryExecute("
|
|
||||||
SELECT ID, Title, Details, TaskCategoryID, ClaimedByUserID, CompletedOn, CreatedOn
|
|
||||||
FROM Tasks
|
|
||||||
WHERE BusinessID = 47
|
|
||||||
ORDER BY ID DESC
|
|
||||||
LIMIT 20
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
tasks = [];
|
|
||||||
for (row in q) {
|
|
||||||
arrayAppend(tasks, {
|
|
||||||
"TaskID": row.ID,
|
|
||||||
"Title": row.Title,
|
|
||||||
"Details": isNull(row.Details) ? "" : row.Details,
|
|
||||||
"CategoryID": row.ID,
|
|
||||||
"ClaimedByUserID": row.ClaimedByUserID,
|
|
||||||
"CompletedOn": isNull(row.CompletedOn) ? "" : dateTimeFormat(row.CompletedOn, "yyyy-mm-dd HH:nn:ss"),
|
|
||||||
"AddedOn": isNull(row.CreatedOn) ? "" : dateTimeFormat(row.CreatedOn, "yyyy-mm-dd HH:nn:ss")
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"COUNT": arrayLen(tasks),
|
|
||||||
"TASKS": tasks
|
|
||||||
}));
|
|
||||||
} catch (any e) {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": false,
|
|
||||||
"ERROR": e.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -50,7 +50,7 @@ try {
|
||||||
// Verify template exists and belongs to this business
|
// Verify template exists and belongs to this business
|
||||||
qCheck = queryExecute("
|
qCheck = queryExecute("
|
||||||
SELECT QuickTaskTemplateID FROM QuickTaskTemplates
|
SELECT QuickTaskTemplateID FROM QuickTaskTemplates
|
||||||
WHERE ID = :id AND BusinessID = :businessID
|
WHERE QuickTaskTemplateID = :id AND QuickTaskTemplateBusinessID = :businessID
|
||||||
", {
|
", {
|
||||||
id: { value: templateID, cfsqltype: "cf_sql_integer" },
|
id: { value: templateID, cfsqltype: "cf_sql_integer" },
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -62,8 +62,8 @@ try {
|
||||||
|
|
||||||
// Soft delete by setting IsActive to 0
|
// Soft delete by setting IsActive to 0
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE QuickTaskTemplates SET IsActive = 0
|
UPDATE QuickTaskTemplates SET QuickTaskTemplateIsActive = 0
|
||||||
WHERE ID = :id
|
WHERE QuickTaskTemplateID = :id
|
||||||
", {
|
", {
|
||||||
id: { value: templateID, cfsqltype: "cf_sql_integer" }
|
id: { value: templateID, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
|
||||||
|
|
@ -45,22 +45,23 @@ try {
|
||||||
// Get quick task templates for this business
|
// Get quick task templates for this business
|
||||||
q = queryExecute("
|
q = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
qt.ID,
|
qt.QuickTaskTemplateID,
|
||||||
qt.Name as Name,
|
qt.QuickTaskTemplateName as Name,
|
||||||
qt.TaskCategoryID as CategoryID,
|
qt.QuickTaskTemplateCategoryID as CategoryID,
|
||||||
qt.Title as Title,
|
qt.QuickTaskTemplateTypeID as TypeID,
|
||||||
qt.Details as Details,
|
qt.QuickTaskTemplateTitle as Title,
|
||||||
qt.Icon as Icon,
|
qt.QuickTaskTemplateDetails as Details,
|
||||||
qt.Color as Color,
|
qt.QuickTaskTemplateIcon as Icon,
|
||||||
qt.SortOrder as SortOrder,
|
qt.QuickTaskTemplateColor as Color,
|
||||||
qt.IsActive as IsActive,
|
qt.QuickTaskTemplateSortOrder as SortOrder,
|
||||||
tc.Name as Name,
|
qt.QuickTaskTemplateIsActive as IsActive,
|
||||||
tc.Color as CategoryColor
|
tc.TaskCategoryName as CategoryName,
|
||||||
|
tc.TaskCategoryColor as CategoryColor
|
||||||
FROM QuickTaskTemplates qt
|
FROM QuickTaskTemplates qt
|
||||||
LEFT JOIN TaskCategories tc ON qt.TaskCategoryID = tc.ID
|
LEFT JOIN TaskCategories tc ON qt.QuickTaskTemplateCategoryID = tc.TaskCategoryID
|
||||||
WHERE qt.BusinessID = :businessID
|
WHERE qt.QuickTaskTemplateBusinessID = :businessID
|
||||||
AND qt.IsActive = 1
|
AND qt.QuickTaskTemplateIsActive = 1
|
||||||
ORDER BY qt.SortOrder, qt.ID
|
ORDER BY qt.QuickTaskTemplateSortOrder, qt.QuickTaskTemplateID
|
||||||
", {
|
", {
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
@ -68,16 +69,17 @@ try {
|
||||||
templates = [];
|
templates = [];
|
||||||
for (row in q) {
|
for (row in q) {
|
||||||
arrayAppend(templates, {
|
arrayAppend(templates, {
|
||||||
"QuickTaskTemplateID": row.ID,
|
"QuickTaskTemplateID": row.QuickTaskTemplateID,
|
||||||
"Name": row.Name,
|
"Name": row.Name,
|
||||||
"CategoryID": isNull(row.CategoryID) ? "" : row.CategoryID,
|
"CategoryID": isNull(row.CategoryID) ? "" : row.CategoryID,
|
||||||
|
"TypeID": isNull(row.TypeID) ? "" : row.TypeID,
|
||||||
"Title": row.Title,
|
"Title": row.Title,
|
||||||
"Details": isNull(row.Details) ? "" : row.Details,
|
"Details": isNull(row.Details) ? "" : row.Details,
|
||||||
"Icon": isNull(row.Icon) ? "add_box" : row.Icon,
|
"Icon": isNull(row.Icon) ? "add_box" : row.Icon,
|
||||||
"Color": isNull(row.Color) ? "##6366f1" : row.Color,
|
"Color": isNull(row.Color) ? "##6366f1" : row.Color,
|
||||||
"SortOrder": row.SortOrder,
|
"SortOrder": row.SortOrder,
|
||||||
"IsActive": row.IsActive,
|
"IsActive": row.IsActive,
|
||||||
"Name": isNull(row.Name) ? "" : row.Name,
|
"CategoryName": isNull(row.CategoryName) ? "" : row.CategoryName,
|
||||||
"CategoryColor": isNull(row.CategoryColor) ? "" : row.CategoryColor
|
"CategoryColor": isNull(row.CategoryColor) ? "" : row.CategoryColor
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfsetting enablecfoutputonly="true">
|
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
||||||
|
|
||||||
<cfscript>
|
|
||||||
try {
|
|
||||||
// Delete all Quick Task templates for business 1
|
|
||||||
queryExecute("DELETE FROM QuickTaskTemplates WHERE BusinessID = 1", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"MESSAGE": "All Quick Task templates purged"
|
|
||||||
}));
|
|
||||||
} catch (any e) {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": false,
|
|
||||||
"ERROR": e.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<cfscript>
|
<cfscript>
|
||||||
// Create or update a quick task template
|
// Create or update a quick task template
|
||||||
// Input: BusinessID (required), QuickTaskTemplateID (optional - for update),
|
// Input: BusinessID (required), QuickTaskTemplateID (optional - for update),
|
||||||
// Name, Title, Details, CategoryID, Icon, Color
|
// Name, Title, Details, CategoryID, TypeID, Icon, Color
|
||||||
// Output: { OK: true, TEMPLATE_ID: int }
|
// Output: { OK: true, TEMPLATE_ID: int }
|
||||||
|
|
||||||
function apiAbort(required struct payload) {
|
function apiAbort(required struct payload) {
|
||||||
|
|
@ -46,12 +46,8 @@ try {
|
||||||
templateName = structKeyExists(data, "Name") ? trim(toString(data.Name)) : "";
|
templateName = structKeyExists(data, "Name") ? trim(toString(data.Name)) : "";
|
||||||
templateTitle = structKeyExists(data, "Title") ? trim(toString(data.Title)) : "";
|
templateTitle = structKeyExists(data, "Title") ? trim(toString(data.Title)) : "";
|
||||||
templateDetails = structKeyExists(data, "Details") ? trim(toString(data.Details)) : "";
|
templateDetails = structKeyExists(data, "Details") ? trim(toString(data.Details)) : "";
|
||||||
hasCategory = false;
|
categoryID = structKeyExists(data, "CategoryID") && isNumeric(data.CategoryID) && data.CategoryID > 0 ? int(data.CategoryID) : javaCast("null", "");
|
||||||
catID = 0;
|
typeID = structKeyExists(data, "TypeID") && isNumeric(data.TypeID) && data.TypeID > 0 ? int(data.TypeID) : javaCast("null", "");
|
||||||
if (structKeyExists(data, "CategoryID") && isNumeric(data.CategoryID) && data.CategoryID > 0) {
|
|
||||||
catID = int(data.CategoryID);
|
|
||||||
hasCategory = true;
|
|
||||||
}
|
|
||||||
templateIcon = structKeyExists(data, "Icon") && len(trim(data.Icon)) ? trim(toString(data.Icon)) : "add_box";
|
templateIcon = structKeyExists(data, "Icon") && len(trim(data.Icon)) ? trim(toString(data.Icon)) : "add_box";
|
||||||
templateColor = structKeyExists(data, "Color") && len(trim(data.Color)) ? trim(toString(data.Color)) : "##6366f1";
|
templateColor = structKeyExists(data, "Color") && len(trim(data.Color)) ? trim(toString(data.Color)) : "##6366f1";
|
||||||
|
|
||||||
|
|
@ -62,15 +58,12 @@ try {
|
||||||
if (!len(templateTitle)) {
|
if (!len(templateTitle)) {
|
||||||
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "Title is required" });
|
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "Title is required" });
|
||||||
}
|
}
|
||||||
if (!hasCategory) {
|
|
||||||
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "Please select a category" });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (templateID > 0) {
|
if (templateID > 0) {
|
||||||
// UPDATE existing template
|
// UPDATE existing template
|
||||||
qCheck = queryExecute("
|
qCheck = queryExecute("
|
||||||
SELECT QuickTaskTemplateID FROM QuickTaskTemplates
|
SELECT QuickTaskTemplateID FROM QuickTaskTemplates
|
||||||
WHERE ID = :id AND BusinessID = :businessID
|
WHERE QuickTaskTemplateID = :id AND QuickTaskTemplateBusinessID = :businessID
|
||||||
", {
|
", {
|
||||||
id: { value: templateID, cfsqltype: "cf_sql_integer" },
|
id: { value: templateID, cfsqltype: "cf_sql_integer" },
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -82,18 +75,20 @@ try {
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE QuickTaskTemplates SET
|
UPDATE QuickTaskTemplates SET
|
||||||
Name = :name,
|
QuickTaskTemplateName = :name,
|
||||||
Title = :title,
|
QuickTaskTemplateTitle = :title,
|
||||||
Details = :details,
|
QuickTaskTemplateDetails = :details,
|
||||||
TaskCategoryID = :categoryID,
|
QuickTaskTemplateCategoryID = :categoryID,
|
||||||
Icon = :icon,
|
QuickTaskTemplateTypeID = :typeID,
|
||||||
Color = :color
|
QuickTaskTemplateIcon = :icon,
|
||||||
WHERE ID = :id
|
QuickTaskTemplateColor = :color
|
||||||
|
WHERE QuickTaskTemplateID = :id
|
||||||
", {
|
", {
|
||||||
name: { value: templateName, cfsqltype: "cf_sql_varchar" },
|
name: { value: templateName, cfsqltype: "cf_sql_varchar" },
|
||||||
title: { value: templateTitle, cfsqltype: "cf_sql_varchar" },
|
title: { value: templateTitle, cfsqltype: "cf_sql_varchar" },
|
||||||
details: { value: templateDetails, cfsqltype: "cf_sql_longvarchar", null: !len(templateDetails) },
|
details: { value: templateDetails, cfsqltype: "cf_sql_longvarchar", null: !len(templateDetails) },
|
||||||
categoryID: { value: catID, cfsqltype: "cf_sql_integer", null: !hasCategory },
|
categoryID: { value: categoryID, cfsqltype: "cf_sql_integer", null: isNull(categoryID) },
|
||||||
|
typeID: { value: typeID, cfsqltype: "cf_sql_integer", null: isNull(typeID) },
|
||||||
icon: { value: templateIcon, cfsqltype: "cf_sql_varchar" },
|
icon: { value: templateIcon, cfsqltype: "cf_sql_varchar" },
|
||||||
color: { value: templateColor, cfsqltype: "cf_sql_varchar" },
|
color: { value: templateColor, cfsqltype: "cf_sql_varchar" },
|
||||||
id: { value: templateID, cfsqltype: "cf_sql_integer" }
|
id: { value: templateID, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -109,8 +104,8 @@ try {
|
||||||
// INSERT new template
|
// INSERT new template
|
||||||
// Get next sort order
|
// Get next sort order
|
||||||
qSort = queryExecute("
|
qSort = queryExecute("
|
||||||
SELECT COALESCE(MAX(SortOrder), 0) + 1 as nextSort
|
SELECT COALESCE(MAX(QuickTaskTemplateSortOrder), 0) + 1 as nextSort
|
||||||
FROM QuickTaskTemplates WHERE BusinessID = :businessID
|
FROM QuickTaskTemplates WHERE QuickTaskTemplateBusinessID = :businessID
|
||||||
", {
|
", {
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
@ -119,18 +114,19 @@ try {
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO QuickTaskTemplates (
|
INSERT INTO QuickTaskTemplates (
|
||||||
BusinessID, Name, Title,
|
QuickTaskTemplateBusinessID, QuickTaskTemplateName, QuickTaskTemplateTitle,
|
||||||
Details, TaskCategoryID,
|
QuickTaskTemplateDetails, QuickTaskTemplateCategoryID, QuickTaskTemplateTypeID,
|
||||||
Icon, Color, SortOrder
|
QuickTaskTemplateIcon, QuickTaskTemplateColor, QuickTaskTemplateSortOrder
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:businessID, :name, :title, :details, :categoryID, :icon, :color, :sortOrder
|
:businessID, :name, :title, :details, :categoryID, :typeID, :icon, :color, :sortOrder
|
||||||
)
|
)
|
||||||
", {
|
", {
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
||||||
name: { value: templateName, cfsqltype: "cf_sql_varchar" },
|
name: { value: templateName, cfsqltype: "cf_sql_varchar" },
|
||||||
title: { value: templateTitle, cfsqltype: "cf_sql_varchar" },
|
title: { value: templateTitle, cfsqltype: "cf_sql_varchar" },
|
||||||
details: { value: templateDetails, cfsqltype: "cf_sql_longvarchar", null: !len(templateDetails) },
|
details: { value: templateDetails, cfsqltype: "cf_sql_longvarchar", null: !len(templateDetails) },
|
||||||
categoryID: { value: catID, cfsqltype: "cf_sql_integer", null: !hasCategory },
|
categoryID: { value: categoryID, cfsqltype: "cf_sql_integer", null: isNull(categoryID) },
|
||||||
|
typeID: { value: typeID, cfsqltype: "cf_sql_integer", null: isNull(typeID) },
|
||||||
icon: { value: templateIcon, cfsqltype: "cf_sql_varchar" },
|
icon: { value: templateIcon, cfsqltype: "cf_sql_varchar" },
|
||||||
color: { value: templateColor, cfsqltype: "cf_sql_varchar" },
|
color: { value: templateColor, cfsqltype: "cf_sql_varchar" },
|
||||||
sortOrder: { value: nextSort, cfsqltype: "cf_sql_integer" }
|
sortOrder: { value: nextSort, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -149,10 +145,7 @@ try {
|
||||||
apiAbort({
|
apiAbort({
|
||||||
"OK": false,
|
"OK": false,
|
||||||
"ERROR": "server_error",
|
"ERROR": "server_error",
|
||||||
"MESSAGE": e.message,
|
"MESSAGE": e.message
|
||||||
"DETAIL": structKeyExists(e, "detail") ? e.detail : "none",
|
|
||||||
"TYPE": structKeyExists(e, "type") ? e.type : "none",
|
|
||||||
"TAG": (structKeyExists(e, "tagContext") && isArray(e.tagContext) && arrayLen(e.tagContext) > 0) ? serializeJSON(e.tagContext[1]) : "none"
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</cfscript>
|
</cfscript>
|
||||||
|
|
|
||||||
|
|
@ -15,20 +15,20 @@ try {
|
||||||
// Create QuickTaskTemplates table
|
// Create QuickTaskTemplates table
|
||||||
queryExecute("
|
queryExecute("
|
||||||
CREATE TABLE IF NOT EXISTS QuickTaskTemplates (
|
CREATE TABLE IF NOT EXISTS QuickTaskTemplates (
|
||||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
QuickTaskTemplateID INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
BusinessID INT NOT NULL,
|
QuickTaskTemplateBusinessID INT NOT NULL,
|
||||||
Name VARCHAR(100) NOT NULL,
|
QuickTaskTemplateName VARCHAR(100) NOT NULL,
|
||||||
TaskCategoryID INT NULL,
|
QuickTaskTemplateCategoryID INT NULL,
|
||||||
TaskTypeID INT NULL,
|
QuickTaskTemplateTypeID INT NULL,
|
||||||
Title VARCHAR(255) NOT NULL,
|
QuickTaskTemplateTitle VARCHAR(255) NOT NULL,
|
||||||
Details TEXT NULL,
|
QuickTaskTemplateDetails TEXT NULL,
|
||||||
Icon VARCHAR(30) DEFAULT 'add_box',
|
QuickTaskTemplateIcon VARCHAR(30) DEFAULT 'add_box',
|
||||||
Color VARCHAR(20) DEFAULT '##6366f1',
|
QuickTaskTemplateColor VARCHAR(20) DEFAULT '##6366f1',
|
||||||
SortOrder INT DEFAULT 0,
|
QuickTaskTemplateSortOrder INT DEFAULT 0,
|
||||||
IsActive BIT(1) DEFAULT b'1',
|
QuickTaskTemplateIsActive BIT(1) DEFAULT b'1',
|
||||||
CreatedOn DATETIME DEFAULT CURRENT_TIMESTAMP,
|
QuickTaskTemplateCreatedOn DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
INDEX idx_business_active (BusinessID, IsActive),
|
INDEX idx_business_active (QuickTaskTemplateBusinessID, QuickTaskTemplateIsActive),
|
||||||
INDEX idx_sort (BusinessID, SortOrder)
|
INDEX idx_sort (QuickTaskTemplateBusinessID, QuickTaskTemplateSortOrder)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||||
", [], { datasource: "payfrit" });
|
", [], { datasource: "payfrit" });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,42 +5,42 @@
|
||||||
<cfscript>
|
<cfscript>
|
||||||
businessId = 27; // Big Dean's
|
businessId = 27; // Big Dean's
|
||||||
|
|
||||||
// Categories are items with ParentItemID=0 AND IsCollapsible=0
|
// Categories are items with ItemParentItemID=0 AND ItemIsCollapsible=0
|
||||||
// Modifier templates are items with ParentItemID=0 AND IsCollapsible=1
|
// Modifier templates are items with ItemParentItemID=0 AND ItemIsCollapsible=1
|
||||||
// Menu items are children of categories
|
// Menu items are children of categories
|
||||||
// Modifiers are children of menu items or modifier templates
|
// Modifiers are children of menu items or modifier templates
|
||||||
|
|
||||||
// Get category IDs (NOT modifier templates)
|
// Get category IDs (NOT modifier templates)
|
||||||
categoryIds = queryExecute("
|
categoryIds = queryExecute("
|
||||||
SELECT ID
|
SELECT ItemID
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE BusinessID = :bizId
|
WHERE ItemBusinessID = :bizId
|
||||||
AND ParentItemID = 0
|
AND ItemParentItemID = 0
|
||||||
AND IsCollapsible = 0
|
AND ItemIsCollapsible = 0
|
||||||
", { bizId: businessId }, { datasource: "payfrit" });
|
", { bizId: businessId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
catIdList = "";
|
catIdList = "";
|
||||||
for (cat in categoryIds) {
|
for (cat in categoryIds) {
|
||||||
catIdList = listAppend(catIdList, cat.ID);
|
catIdList = listAppend(catIdList, cat.ItemID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now get actual menu items (direct children of categories)
|
// Now get actual menu items (direct children of categories)
|
||||||
// Exclude items that are template options (their parent is a collapsible modifier group)
|
// Exclude items that are template options (their parent is a collapsible modifier group)
|
||||||
items = queryExecute("
|
items = queryExecute("
|
||||||
SELECT i.ID, i.Name
|
SELECT i.ItemID, i.ItemName
|
||||||
FROM Items i
|
FROM Items i
|
||||||
WHERE i.BusinessID = :bizId
|
WHERE i.ItemBusinessID = :bizId
|
||||||
AND i.ParentItemID IN (#catIdList#)
|
AND i.ItemParentItemID IN (#catIdList#)
|
||||||
AND i.IsCollapsible = 0
|
AND i.ItemIsCollapsible = 0
|
||||||
AND NOT EXISTS (
|
AND NOT EXISTS (
|
||||||
SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = i.ID
|
SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = i.ItemID
|
||||||
)
|
)
|
||||||
", { bizId: businessId }, { datasource: "payfrit" });
|
", { bizId: businessId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
updated = [];
|
updated = [];
|
||||||
|
|
||||||
for (item in items) {
|
for (item in items) {
|
||||||
itemName = lcase(item.Name);
|
itemName = lcase(item.ItemName);
|
||||||
newPrice = 0;
|
newPrice = 0;
|
||||||
|
|
||||||
// Drinks - $3-6
|
// Drinks - $3-6
|
||||||
|
|
@ -99,13 +99,13 @@ for (item in items) {
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET Price = :price
|
SET ItemPrice = :price
|
||||||
WHERE ItemID = :itemId
|
WHERE ItemID = :itemId
|
||||||
", { price: newPrice, itemId: item.ID }, { datasource: "payfrit" });
|
", { price: newPrice, itemId: item.ItemID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(updated, {
|
arrayAppend(updated, {
|
||||||
"ItemID": item.ID,
|
"ItemID": item.ItemID,
|
||||||
"Name": item.Name,
|
"ItemName": item.ItemName,
|
||||||
"NewPrice": newPrice
|
"NewPrice": newPrice
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -113,15 +113,15 @@ for (item in items) {
|
||||||
// Update modifier prices (children of menu items, NOT direct children of categories)
|
// Update modifier prices (children of menu items, NOT direct children of categories)
|
||||||
// Modifiers are items whose parent is NOT a category (i.e., parent is a menu item or modifier group)
|
// Modifiers are items whose parent is NOT a category (i.e., parent is a menu item or modifier group)
|
||||||
modifiers = queryExecute("
|
modifiers = queryExecute("
|
||||||
SELECT ID, Name
|
SELECT ItemID, ItemName
|
||||||
FROM Items
|
FROM Items
|
||||||
WHERE BusinessID = :bizId
|
WHERE ItemBusinessID = :bizId
|
||||||
AND ParentItemID > 0
|
AND ItemParentItemID > 0
|
||||||
AND ParentItemID NOT IN (#catIdList#)
|
AND ItemParentItemID NOT IN (#catIdList#)
|
||||||
", { bizId: businessId }, { datasource: "payfrit" });
|
", { bizId: businessId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
for (mod in modifiers) {
|
for (mod in modifiers) {
|
||||||
modName = lcase(mod.Name);
|
modName = lcase(mod.ItemName);
|
||||||
modPrice = 0;
|
modPrice = 0;
|
||||||
|
|
||||||
// Proteins are expensive add-ons
|
// Proteins are expensive add-ons
|
||||||
|
|
@ -150,7 +150,7 @@ for (mod in modifiers) {
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET Price = :price
|
SET ItemPrice = :price
|
||||||
WHERE ItemID = :itemId
|
WHERE ItemID = :itemId
|
||||||
", { price: modPrice, itemId: mod.ItemID }, { datasource: "payfrit" });
|
", { price: modPrice, itemId: mod.ItemID }, { datasource: "payfrit" });
|
||||||
}
|
}
|
||||||
|
|
@ -158,17 +158,17 @@ for (mod in modifiers) {
|
||||||
// Reset category prices to $0 (shouldn't have prices for reporting)
|
// Reset category prices to $0 (shouldn't have prices for reporting)
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET Price = 0
|
SET ItemPrice = 0
|
||||||
WHERE BusinessID = :bizId
|
WHERE ItemBusinessID = :bizId
|
||||||
AND ParentItemID = 0
|
AND ItemParentItemID = 0
|
||||||
", { bizId: businessId }, { datasource: "payfrit" });
|
", { bizId: businessId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Reset modifier group prices to $0 (only options have prices)
|
// Reset modifier group prices to $0 (only options have prices)
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Items
|
UPDATE Items
|
||||||
SET Price = 0
|
SET ItemPrice = 0
|
||||||
WHERE BusinessID = :bizId
|
WHERE ItemBusinessID = :bizId
|
||||||
AND IsCollapsible = 1
|
AND ItemIsCollapsible = 1
|
||||||
", { bizId: businessId }, { datasource: "payfrit" });
|
", { bizId: businessId }, { datasource: "payfrit" });
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ try {
|
||||||
// Verify exists and belongs to business
|
// Verify exists and belongs to business
|
||||||
qCheck = queryExecute("
|
qCheck = queryExecute("
|
||||||
SELECT ScheduledTaskID FROM ScheduledTaskDefinitions
|
SELECT ScheduledTaskID FROM ScheduledTaskDefinitions
|
||||||
WHERE ID = :id AND BusinessID = :businessID
|
WHERE ScheduledTaskID = :id AND ScheduledTaskBusinessID = :businessID
|
||||||
", {
|
", {
|
||||||
id: { value: taskID, cfsqltype: "cf_sql_integer" },
|
id: { value: taskID, cfsqltype: "cf_sql_integer" },
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -62,7 +62,7 @@ try {
|
||||||
|
|
||||||
// Hard delete the definition
|
// Hard delete the definition
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM ScheduledTaskDefinitions WHERE ID = :id
|
DELETE FROM ScheduledTaskDefinitions WHERE ScheduledTaskID = :id
|
||||||
", {
|
", {
|
||||||
id: { value: taskID, cfsqltype: "cf_sql_integer" }
|
id: { value: taskID, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
|
||||||
|
|
@ -45,24 +45,23 @@ try {
|
||||||
// Get scheduled task definitions for this business
|
// Get scheduled task definitions for this business
|
||||||
q = queryExecute("
|
q = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
st.ID,
|
st.ScheduledTaskID,
|
||||||
st.Name as Name,
|
st.ScheduledTaskName as Name,
|
||||||
st.TaskCategoryID as CategoryID,
|
st.ScheduledTaskCategoryID as CategoryID,
|
||||||
st.Title as Title,
|
st.ScheduledTaskTypeID as TypeID,
|
||||||
st.Details as Details,
|
st.ScheduledTaskTitle as Title,
|
||||||
st.CronExpression as CronExpression,
|
st.ScheduledTaskDetails as Details,
|
||||||
COALESCE(st.ScheduleType, 'cron') as ScheduleType,
|
st.ScheduledTaskCronExpression as CronExpression,
|
||||||
st.IntervalMinutes as IntervalMinutes,
|
st.ScheduledTaskIsActive as IsActive,
|
||||||
st.IsActive as IsActive,
|
st.ScheduledTaskLastRunOn as LastRunOn,
|
||||||
st.LastRunOn as LastRunOn,
|
st.ScheduledTaskNextRunOn as NextRunOn,
|
||||||
st.NextRunOn as NextRunOn,
|
st.ScheduledTaskCreatedOn as CreatedOn,
|
||||||
st.CreatedOn as CreatedOn,
|
tc.TaskCategoryName as CategoryName,
|
||||||
tc.Name as Name,
|
tc.TaskCategoryColor as CategoryColor
|
||||||
tc.Color as CategoryColor
|
|
||||||
FROM ScheduledTaskDefinitions st
|
FROM ScheduledTaskDefinitions st
|
||||||
LEFT JOIN TaskCategories tc ON st.TaskCategoryID = tc.ID
|
LEFT JOIN TaskCategories tc ON st.ScheduledTaskCategoryID = tc.TaskCategoryID
|
||||||
WHERE st.BusinessID = :businessID
|
WHERE st.ScheduledTaskBusinessID = :businessID
|
||||||
ORDER BY st.IsActive DESC, st.Name
|
ORDER BY st.ScheduledTaskIsActive DESC, st.ScheduledTaskName
|
||||||
", {
|
", {
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
@ -70,19 +69,18 @@ try {
|
||||||
scheduledTasks = [];
|
scheduledTasks = [];
|
||||||
for (row in q) {
|
for (row in q) {
|
||||||
arrayAppend(scheduledTasks, {
|
arrayAppend(scheduledTasks, {
|
||||||
"ScheduledTaskID": row.ID,
|
"ScheduledTaskID": row.ScheduledTaskID,
|
||||||
"Name": row.Name,
|
"Name": row.Name,
|
||||||
"CategoryID": isNull(row.CategoryID) ? "" : row.CategoryID,
|
"CategoryID": isNull(row.CategoryID) ? "" : row.CategoryID,
|
||||||
|
"TypeID": isNull(row.TypeID) ? "" : row.TypeID,
|
||||||
"Title": row.Title,
|
"Title": row.Title,
|
||||||
"Details": isNull(row.Details) ? "" : row.Details,
|
"Details": isNull(row.Details) ? "" : row.Details,
|
||||||
"CronExpression": row.CronExpression,
|
"CronExpression": row.CronExpression,
|
||||||
"ScheduleType": row.ScheduleType,
|
|
||||||
"IntervalMinutes": isNull(row.IntervalMinutes) ? "" : row.IntervalMinutes,
|
|
||||||
"IsActive": row.IsActive ? true : false,
|
"IsActive": row.IsActive ? true : false,
|
||||||
"LastRunOn": isNull(row.LastRunOn) ? "" : dateTimeFormat(row.LastRunOn, "yyyy-mm-dd HH:nn:ss"),
|
"LastRunOn": isNull(row.LastRunOn) ? "" : dateTimeFormat(row.LastRunOn, "yyyy-mm-dd HH:nn:ss"),
|
||||||
"NextRunOn": isNull(row.NextRunOn) ? "" : dateTimeFormat(row.NextRunOn, "yyyy-mm-dd HH:nn:ss"),
|
"NextRunOn": isNull(row.NextRunOn) ? "" : dateTimeFormat(row.NextRunOn, "yyyy-mm-dd HH:nn:ss"),
|
||||||
"CreatedOn": dateTimeFormat(row.CreatedOn, "yyyy-mm-dd HH:nn:ss"),
|
"CreatedOn": dateTimeFormat(row.CreatedOn, "yyyy-mm-dd HH:nn:ss"),
|
||||||
"Name": isNull(row.Name) ? "" : row.Name,
|
"CategoryName": isNull(row.CategoryName) ? "" : row.CategoryName,
|
||||||
"CategoryColor": isNull(row.CategoryColor) ? "" : row.CategoryColor
|
"CategoryColor": isNull(row.CategoryColor) ? "" : row.CategoryColor
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,12 @@ try {
|
||||||
// Get scheduled task definition
|
// Get scheduled task definition
|
||||||
qDef = queryExecute("
|
qDef = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
Title as Title,
|
ScheduledTaskTitle as Title,
|
||||||
Details as Details,
|
ScheduledTaskDetails as Details,
|
||||||
TaskCategoryID as CategoryID
|
ScheduledTaskCategoryID as CategoryID,
|
||||||
|
ScheduledTaskTypeID as TypeID
|
||||||
FROM ScheduledTaskDefinitions
|
FROM ScheduledTaskDefinitions
|
||||||
WHERE ID = :id AND BusinessID = :businessID
|
WHERE ScheduledTaskID = :id AND ScheduledTaskBusinessID = :businessID
|
||||||
", {
|
", {
|
||||||
id: { value: scheduledTaskID, cfsqltype: "cf_sql_integer" },
|
id: { value: scheduledTaskID, cfsqltype: "cf_sql_integer" },
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -65,21 +66,24 @@ try {
|
||||||
apiAbort({ "OK": false, "ERROR": "not_found", "MESSAGE": "Scheduled task not found" });
|
apiAbort({ "OK": false, "ERROR": "not_found", "MESSAGE": "Scheduled task not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the task (ClaimedByUserID=0 means unclaimed/pending)
|
// Create the task
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Tasks (
|
INSERT INTO Tasks (
|
||||||
BusinessID, CategoryID, TaskTypeID,
|
TaskBusinessID, TaskCategoryID, TaskTypeID,
|
||||||
Title, Details, CreatedOn, ClaimedByUserID
|
TaskTitle, TaskDetails, TaskStatusID, TaskAddedOn,
|
||||||
|
TaskSourceType, TaskSourceID
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:businessID, :categoryID, :typeID,
|
:businessID, :categoryID, :typeID,
|
||||||
:title, :details, NOW(), 0
|
:title, :details, 0, NOW(),
|
||||||
|
'scheduled_manual', :scheduledTaskID
|
||||||
)
|
)
|
||||||
", {
|
", {
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
||||||
categoryID: { value: qDef.CategoryID, cfsqltype: "cf_sql_integer", null: isNull(qDef.CategoryID) },
|
categoryID: { value: qDef.CategoryID, cfsqltype: "cf_sql_integer", null: isNull(qDef.CategoryID) },
|
||||||
typeID: { value: 0, cfsqltype: "cf_sql_integer" },
|
typeID: { value: qDef.TypeID, cfsqltype: "cf_sql_integer", null: isNull(qDef.TypeID) },
|
||||||
title: { value: qDef.Title, cfsqltype: "cf_sql_varchar" },
|
title: { value: qDef.Title, cfsqltype: "cf_sql_varchar" },
|
||||||
details: { value: qDef.Details, cfsqltype: "cf_sql_longvarchar", null: isNull(qDef.Details) }
|
details: { value: qDef.Details, cfsqltype: "cf_sql_longvarchar", null: isNull(qDef.Details) },
|
||||||
|
scheduledTaskID: { value: scheduledTaskID, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
qNew = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" });
|
qNew = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" });
|
||||||
|
|
|
||||||
|
|
@ -68,65 +68,57 @@ try {
|
||||||
dueTasks = queryExecute("
|
dueTasks = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
ScheduledTaskID,
|
ScheduledTaskID,
|
||||||
BusinessID as BusinessID,
|
ScheduledTaskBusinessID as BusinessID,
|
||||||
TaskCategoryID as CategoryID,
|
ScheduledTaskCategoryID as CategoryID,
|
||||||
Title as Title,
|
ScheduledTaskTypeID as TypeID,
|
||||||
Details as Details,
|
ScheduledTaskTitle as Title,
|
||||||
CronExpression as CronExpression,
|
ScheduledTaskDetails as Details,
|
||||||
COALESCE(ScheduleType, 'cron') as ScheduleType,
|
ScheduledTaskCronExpression as CronExpression
|
||||||
IntervalMinutes as IntervalMinutes
|
|
||||||
FROM ScheduledTaskDefinitions
|
FROM ScheduledTaskDefinitions
|
||||||
WHERE IsActive = 1
|
WHERE ScheduledTaskIsActive = 1
|
||||||
AND NextRunOn <= NOW()
|
AND ScheduledTaskNextRunOn <= NOW()
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
createdTasks = [];
|
createdTasks = [];
|
||||||
|
|
||||||
for (task in dueTasks) {
|
for (task in dueTasks) {
|
||||||
// Create the actual task (ClaimedByUserID=0 means unclaimed/pending)
|
// Create the actual task
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Tasks (
|
INSERT INTO Tasks (
|
||||||
BusinessID, CategoryID, TaskTypeID,
|
TaskBusinessID, TaskCategoryID, TaskTypeID,
|
||||||
Title, Details, CreatedOn, ClaimedByUserID
|
TaskTitle, TaskDetails, TaskStatusID, TaskAddedOn,
|
||||||
|
TaskSourceType, TaskSourceID
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:businessID, :categoryID, :typeID,
|
:businessID, :categoryID, :typeID,
|
||||||
:title, :details, NOW(), 0
|
:title, :details, 0, NOW(),
|
||||||
|
'scheduled', :scheduledTaskID
|
||||||
)
|
)
|
||||||
", {
|
", {
|
||||||
businessID: { value: task.BusinessID, cfsqltype: "cf_sql_integer" },
|
businessID: { value: task.BusinessID, cfsqltype: "cf_sql_integer" },
|
||||||
categoryID: { value: task.CategoryID, cfsqltype: "cf_sql_integer", null: isNull(task.CategoryID) },
|
categoryID: { value: task.CategoryID, cfsqltype: "cf_sql_integer", null: isNull(task.CategoryID) },
|
||||||
typeID: { value: 0, cfsqltype: "cf_sql_integer" },
|
typeID: { value: task.TypeID, cfsqltype: "cf_sql_integer", null: isNull(task.TypeID) },
|
||||||
title: { value: task.Title, cfsqltype: "cf_sql_varchar" },
|
title: { value: task.Title, cfsqltype: "cf_sql_varchar" },
|
||||||
details: { value: task.Details, cfsqltype: "cf_sql_longvarchar", null: isNull(task.Details) }
|
details: { value: task.Details, cfsqltype: "cf_sql_longvarchar", null: isNull(task.Details) },
|
||||||
|
scheduledTaskID: { value: task.ScheduledTaskID, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
qNew = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" });
|
qNew = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" });
|
||||||
|
|
||||||
// Calculate next run based on schedule type
|
// Calculate next run and update the scheduled task
|
||||||
if (task.ScheduleType == "interval_after_completion" && !isNull(task.IntervalMinutes) && task.IntervalMinutes > 0) {
|
nextRun = calculateNextRun(task.CronExpression);
|
||||||
// After-completion interval: don't schedule next run until task is completed
|
|
||||||
// Set to far future (effectively paused until task completion triggers recalculation)
|
|
||||||
nextRun = javaCast("null", "");
|
|
||||||
} else if (task.ScheduleType == "interval" && !isNull(task.IntervalMinutes) && task.IntervalMinutes > 0) {
|
|
||||||
// Fixed interval: next run = NOW + interval minutes
|
|
||||||
nextRun = dateAdd("n", task.IntervalMinutes, now());
|
|
||||||
} else {
|
|
||||||
// Cron-based: use cron parser
|
|
||||||
nextRun = calculateNextRun(task.CronExpression);
|
|
||||||
}
|
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE ScheduledTaskDefinitions SET
|
UPDATE ScheduledTaskDefinitions SET
|
||||||
LastRunOn = NOW(),
|
ScheduledTaskLastRunOn = NOW(),
|
||||||
NextRunOn = :nextRun
|
ScheduledTaskNextRunOn = :nextRun
|
||||||
WHERE ID = :id
|
WHERE ScheduledTaskID = :id
|
||||||
", {
|
", {
|
||||||
nextRun: { value: nextRun, cfsqltype: "cf_sql_timestamp", null: isNull(nextRun) },
|
nextRun: { value: nextRun, cfsqltype: "cf_sql_timestamp" },
|
||||||
id: { value: task.ID, cfsqltype: "cf_sql_integer" }
|
id: { value: task.ScheduledTaskID, cfsqltype: "cf_sql_integer" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
arrayAppend(createdTasks, {
|
arrayAppend(createdTasks, {
|
||||||
"ScheduledTaskID": task.ID,
|
"ScheduledTaskID": task.ScheduledTaskID,
|
||||||
"TaskID": qNew.newID,
|
"TaskID": qNew.newID,
|
||||||
"BusinessID": task.BusinessID,
|
"BusinessID": task.BusinessID,
|
||||||
"Title": task.Title
|
"Title": task.Title
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@
|
||||||
<cfscript>
|
<cfscript>
|
||||||
// Create or update a scheduled task definition
|
// Create or update a scheduled task definition
|
||||||
// Input: BusinessID (required), ScheduledTaskID (optional - for update),
|
// Input: BusinessID (required), ScheduledTaskID (optional - for update),
|
||||||
// Name, Title, Details, CategoryID, TypeID, CronExpression, IsActive,
|
// Name, Title, Details, CategoryID, TypeID, CronExpression, IsActive
|
||||||
// ScheduleType ('cron' or 'interval'), IntervalMinutes (for interval type)
|
|
||||||
// Output: { OK: true, SCHEDULED_TASK_ID: int }
|
// Output: { OK: true, SCHEDULED_TASK_ID: int }
|
||||||
|
|
||||||
function apiAbort(required struct payload) {
|
function apiAbort(required struct payload) {
|
||||||
|
|
@ -109,13 +108,10 @@ try {
|
||||||
taskTitle = structKeyExists(data, "Title") ? trim(toString(data.Title)) : "";
|
taskTitle = structKeyExists(data, "Title") ? trim(toString(data.Title)) : "";
|
||||||
taskDetails = structKeyExists(data, "Details") ? trim(toString(data.Details)) : "";
|
taskDetails = structKeyExists(data, "Details") ? trim(toString(data.Details)) : "";
|
||||||
categoryID = structKeyExists(data, "CategoryID") && isNumeric(data.CategoryID) && data.CategoryID > 0 ? int(data.CategoryID) : javaCast("null", "");
|
categoryID = structKeyExists(data, "CategoryID") && isNumeric(data.CategoryID) && data.CategoryID > 0 ? int(data.CategoryID) : javaCast("null", "");
|
||||||
|
typeID = structKeyExists(data, "TypeID") && isNumeric(data.TypeID) && data.TypeID > 0 ? int(data.TypeID) : javaCast("null", "");
|
||||||
cronExpression = structKeyExists(data, "CronExpression") ? trim(toString(data.CronExpression)) : "";
|
cronExpression = structKeyExists(data, "CronExpression") ? trim(toString(data.CronExpression)) : "";
|
||||||
isActive = structKeyExists(data, "IsActive") ? (data.IsActive ? 1 : 0) : 1;
|
isActive = structKeyExists(data, "IsActive") ? (data.IsActive ? 1 : 0) : 1;
|
||||||
|
|
||||||
// New interval scheduling fields
|
|
||||||
scheduleType = structKeyExists(data, "ScheduleType") ? trim(toString(data.ScheduleType)) : "cron";
|
|
||||||
intervalMinutes = structKeyExists(data, "IntervalMinutes") && isNumeric(data.IntervalMinutes) ? int(data.IntervalMinutes) : javaCast("null", "");
|
|
||||||
|
|
||||||
// Validate required fields
|
// Validate required fields
|
||||||
if (!len(taskName)) {
|
if (!len(taskName)) {
|
||||||
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "Name is required" });
|
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "Name is required" });
|
||||||
|
|
@ -123,42 +119,24 @@ try {
|
||||||
if (!len(taskTitle)) {
|
if (!len(taskTitle)) {
|
||||||
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "Title is required" });
|
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "Title is required" });
|
||||||
}
|
}
|
||||||
|
if (!len(cronExpression)) {
|
||||||
// Validate based on schedule type
|
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "CronExpression is required" });
|
||||||
if (scheduleType == "interval" || scheduleType == "interval_after_completion") {
|
|
||||||
// Interval-based scheduling
|
|
||||||
if (isNull(intervalMinutes) || intervalMinutes < 1) {
|
|
||||||
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "IntervalMinutes is required for interval scheduling (minimum 1)" });
|
|
||||||
}
|
|
||||||
// Set a placeholder cron expression for interval type
|
|
||||||
if (!len(cronExpression)) {
|
|
||||||
cronExpression = "* * * * *";
|
|
||||||
}
|
|
||||||
// For NEW tasks: run immediately. For UPDATES: next run = NOW + interval
|
|
||||||
if (taskID == 0) {
|
|
||||||
nextRunOn = now(); // Run immediately on first creation
|
|
||||||
} else {
|
|
||||||
nextRunOn = dateAdd("n", intervalMinutes, now());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Cron-based scheduling
|
|
||||||
if (!len(cronExpression)) {
|
|
||||||
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "CronExpression is required" });
|
|
||||||
}
|
|
||||||
// Validate cron format (5 parts)
|
|
||||||
cronParts = listToArray(cronExpression, " ");
|
|
||||||
if (arrayLen(cronParts) != 5) {
|
|
||||||
apiAbort({ "OK": false, "ERROR": "invalid_cron", "MESSAGE": "Cron expression must have 5 parts: minute hour day month weekday" });
|
|
||||||
}
|
|
||||||
// Calculate next run time from cron
|
|
||||||
nextRunOn = calculateNextRun(cronExpression);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate cron format (5 parts)
|
||||||
|
cronParts = listToArray(cronExpression, " ");
|
||||||
|
if (arrayLen(cronParts) != 5) {
|
||||||
|
apiAbort({ "OK": false, "ERROR": "invalid_cron", "MESSAGE": "Cron expression must have 5 parts: minute hour day month weekday" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate next run time
|
||||||
|
nextRunOn = calculateNextRun(cronExpression);
|
||||||
|
|
||||||
if (taskID > 0) {
|
if (taskID > 0) {
|
||||||
// UPDATE existing
|
// UPDATE existing
|
||||||
qCheck = queryExecute("
|
qCheck = queryExecute("
|
||||||
SELECT ScheduledTaskID FROM ScheduledTaskDefinitions
|
SELECT ScheduledTaskID FROM ScheduledTaskDefinitions
|
||||||
WHERE ID = :id AND BusinessID = :businessID
|
WHERE ScheduledTaskID = :id AND ScheduledTaskBusinessID = :businessID
|
||||||
", {
|
", {
|
||||||
id: { value: taskID, cfsqltype: "cf_sql_integer" },
|
id: { value: taskID, cfsqltype: "cf_sql_integer" },
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -170,24 +148,22 @@ try {
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE ScheduledTaskDefinitions SET
|
UPDATE ScheduledTaskDefinitions SET
|
||||||
Name = :name,
|
ScheduledTaskName = :name,
|
||||||
Title = :title,
|
ScheduledTaskTitle = :title,
|
||||||
Details = :details,
|
ScheduledTaskDetails = :details,
|
||||||
TaskCategoryID = :categoryID,
|
ScheduledTaskCategoryID = :categoryID,
|
||||||
CronExpression = :cron,
|
ScheduledTaskTypeID = :typeID,
|
||||||
ScheduleType = :scheduleType,
|
ScheduledTaskCronExpression = :cron,
|
||||||
IntervalMinutes = :intervalMinutes,
|
ScheduledTaskIsActive = :isActive,
|
||||||
IsActive = :isActive,
|
ScheduledTaskNextRunOn = :nextRun
|
||||||
NextRunOn = :nextRun
|
WHERE ScheduledTaskID = :id
|
||||||
WHERE ID = :id
|
|
||||||
", {
|
", {
|
||||||
name: { value: taskName, cfsqltype: "cf_sql_varchar" },
|
name: { value: taskName, cfsqltype: "cf_sql_varchar" },
|
||||||
title: { value: taskTitle, cfsqltype: "cf_sql_varchar" },
|
title: { value: taskTitle, cfsqltype: "cf_sql_varchar" },
|
||||||
details: { value: taskDetails, cfsqltype: "cf_sql_longvarchar", null: !len(taskDetails) },
|
details: { value: taskDetails, cfsqltype: "cf_sql_longvarchar", null: !len(taskDetails) },
|
||||||
categoryID: { value: categoryID, cfsqltype: "cf_sql_integer", null: isNull(categoryID) },
|
categoryID: { value: categoryID, cfsqltype: "cf_sql_integer", null: isNull(categoryID) },
|
||||||
|
typeID: { value: typeID, cfsqltype: "cf_sql_integer", null: isNull(typeID) },
|
||||||
cron: { value: cronExpression, cfsqltype: "cf_sql_varchar" },
|
cron: { value: cronExpression, cfsqltype: "cf_sql_varchar" },
|
||||||
scheduleType: { value: scheduleType, cfsqltype: "cf_sql_varchar" },
|
|
||||||
intervalMinutes: { value: intervalMinutes, cfsqltype: "cf_sql_integer", null: isNull(intervalMinutes) },
|
|
||||||
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
||||||
nextRun: { value: nextRunOn, cfsqltype: "cf_sql_timestamp" },
|
nextRun: { value: nextRunOn, cfsqltype: "cf_sql_timestamp" },
|
||||||
id: { value: taskID, cfsqltype: "cf_sql_integer" }
|
id: { value: taskID, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -204,12 +180,11 @@ try {
|
||||||
// INSERT new
|
// INSERT new
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO ScheduledTaskDefinitions (
|
INSERT INTO ScheduledTaskDefinitions (
|
||||||
BusinessID, Name, Title,
|
ScheduledTaskBusinessID, ScheduledTaskName, ScheduledTaskTitle,
|
||||||
Details, TaskCategoryID,
|
ScheduledTaskDetails, ScheduledTaskCategoryID, ScheduledTaskTypeID,
|
||||||
CronExpression, ScheduleType, IntervalMinutes,
|
ScheduledTaskCronExpression, ScheduledTaskIsActive, ScheduledTaskNextRunOn
|
||||||
IsActive, NextRunOn
|
|
||||||
) VALUES (
|
) VALUES (
|
||||||
:businessID, :name, :title, :details, :categoryID, :cron, :scheduleType, :intervalMinutes, :isActive, :nextRun
|
:businessID, :name, :title, :details, :categoryID, :typeID, :cron, :isActive, :nextRun
|
||||||
)
|
)
|
||||||
", {
|
", {
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
||||||
|
|
@ -217,65 +192,19 @@ try {
|
||||||
title: { value: taskTitle, cfsqltype: "cf_sql_varchar" },
|
title: { value: taskTitle, cfsqltype: "cf_sql_varchar" },
|
||||||
details: { value: taskDetails, cfsqltype: "cf_sql_longvarchar", null: !len(taskDetails) },
|
details: { value: taskDetails, cfsqltype: "cf_sql_longvarchar", null: !len(taskDetails) },
|
||||||
categoryID: { value: categoryID, cfsqltype: "cf_sql_integer", null: isNull(categoryID) },
|
categoryID: { value: categoryID, cfsqltype: "cf_sql_integer", null: isNull(categoryID) },
|
||||||
|
typeID: { value: typeID, cfsqltype: "cf_sql_integer", null: isNull(typeID) },
|
||||||
cron: { value: cronExpression, cfsqltype: "cf_sql_varchar" },
|
cron: { value: cronExpression, cfsqltype: "cf_sql_varchar" },
|
||||||
scheduleType: { value: scheduleType, cfsqltype: "cf_sql_varchar" },
|
|
||||||
intervalMinutes: { value: intervalMinutes, cfsqltype: "cf_sql_integer", null: isNull(intervalMinutes) },
|
|
||||||
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
||||||
nextRun: { value: nextRunOn, cfsqltype: "cf_sql_timestamp" }
|
nextRun: { value: nextRunOn, cfsqltype: "cf_sql_timestamp" }
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
qNew = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" });
|
qNew = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" });
|
||||||
newScheduledTaskID = qNew.newID;
|
|
||||||
|
|
||||||
// Create the first task immediately
|
|
||||||
queryExecute("
|
|
||||||
INSERT INTO Tasks (
|
|
||||||
BusinessID, CategoryID, TaskTypeID,
|
|
||||||
Title, Details, CreatedOn, ClaimedByUserID
|
|
||||||
) VALUES (
|
|
||||||
:businessID, :categoryID, :typeID,
|
|
||||||
:title, :details, NOW(), 0
|
|
||||||
)
|
|
||||||
", {
|
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
|
||||||
categoryID: { value: categoryID, cfsqltype: "cf_sql_integer", null: isNull(categoryID) },
|
|
||||||
typeID: { value: 0, cfsqltype: "cf_sql_integer" },
|
|
||||||
title: { value: taskTitle, cfsqltype: "cf_sql_varchar" },
|
|
||||||
details: { value: taskDetails, cfsqltype: "cf_sql_longvarchar", null: !len(taskDetails) }
|
|
||||||
}, { datasource: "payfrit" });
|
|
||||||
|
|
||||||
qTask = queryExecute("SELECT LAST_INSERT_ID() as taskID", [], { datasource: "payfrit" });
|
|
||||||
|
|
||||||
// Now set the NEXT run time (not the immediate one we just created)
|
|
||||||
if (scheduleType == "interval" || scheduleType == "interval_after_completion") {
|
|
||||||
if (scheduleType == "interval_after_completion") {
|
|
||||||
// After-completion: don't schedule next until task is completed
|
|
||||||
actualNextRun = javaCast("null", "");
|
|
||||||
} else {
|
|
||||||
// Fixed interval: next run = NOW + interval
|
|
||||||
actualNextRun = dateAdd("n", intervalMinutes, now());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Cron-based
|
|
||||||
actualNextRun = calculateNextRun(cronExpression);
|
|
||||||
}
|
|
||||||
|
|
||||||
queryExecute("
|
|
||||||
UPDATE ScheduledTaskDefinitions
|
|
||||||
SET LastRunOn = NOW(),
|
|
||||||
NextRunOn = :nextRun
|
|
||||||
WHERE ID = :id
|
|
||||||
", {
|
|
||||||
nextRun: { value: actualNextRun, cfsqltype: "cf_sql_timestamp", null: isNull(actualNextRun) },
|
|
||||||
id: { value: newScheduledTaskID, cfsqltype: "cf_sql_integer" }
|
|
||||||
}, { datasource: "payfrit" });
|
|
||||||
|
|
||||||
apiAbort({
|
apiAbort({
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"SCHEDULED_TASK_ID": newScheduledTaskID,
|
"SCHEDULED_TASK_ID": qNew.newID,
|
||||||
"TASK_ID": qTask.taskID,
|
"NEXT_RUN": dateTimeFormat(nextRunOn, "yyyy-mm-dd HH:nn:ss"),
|
||||||
"NEXT_RUN": isNull(actualNextRun) ? "" : dateTimeFormat(actualNextRun, "yyyy-mm-dd HH:nn:ss"),
|
"MESSAGE": "Scheduled task created"
|
||||||
"MESSAGE": "Scheduled task created and first task added"
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,48 +15,27 @@ try {
|
||||||
// Create ScheduledTaskDefinitions table
|
// Create ScheduledTaskDefinitions table
|
||||||
queryExecute("
|
queryExecute("
|
||||||
CREATE TABLE IF NOT EXISTS ScheduledTaskDefinitions (
|
CREATE TABLE IF NOT EXISTS ScheduledTaskDefinitions (
|
||||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
ScheduledTaskID INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
BusinessID INT NOT NULL,
|
ScheduledTaskBusinessID INT NOT NULL,
|
||||||
Name VARCHAR(100) NOT NULL,
|
ScheduledTaskName VARCHAR(100) NOT NULL,
|
||||||
TaskCategoryID INT NULL,
|
ScheduledTaskCategoryID INT NULL,
|
||||||
TaskTypeID INT NULL,
|
ScheduledTaskTypeID INT NULL,
|
||||||
Title VARCHAR(255) NOT NULL,
|
ScheduledTaskTitle VARCHAR(255) NOT NULL,
|
||||||
Details TEXT NULL,
|
ScheduledTaskDetails TEXT NULL,
|
||||||
CronExpression VARCHAR(100) NOT NULL,
|
ScheduledTaskCronExpression VARCHAR(100) NOT NULL,
|
||||||
ScheduleType VARCHAR(20) DEFAULT 'cron',
|
ScheduledTaskIsActive BIT(1) DEFAULT b'1',
|
||||||
IntervalMinutes INT NULL,
|
ScheduledTaskLastRunOn DATETIME NULL,
|
||||||
IsActive BIT(1) DEFAULT b'1',
|
ScheduledTaskNextRunOn DATETIME NULL,
|
||||||
LastRunOn DATETIME NULL,
|
ScheduledTaskCreatedOn DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
NextRunOn DATETIME NULL,
|
ScheduledTaskCreatedByUserID INT NULL,
|
||||||
CreatedOn DATETIME DEFAULT CURRENT_TIMESTAMP,
|
INDEX idx_business (ScheduledTaskBusinessID),
|
||||||
CreatedByUserID INT NULL,
|
INDEX idx_active_next (ScheduledTaskIsActive, ScheduledTaskNextRunOn)
|
||||||
INDEX idx_business (BusinessID),
|
|
||||||
INDEX idx_active_next (IsActive, NextRunOn)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||||
", [], { datasource: "payfrit" });
|
", [], { datasource: "payfrit" });
|
||||||
|
|
||||||
// Add new columns if they don't exist (for existing tables)
|
|
||||||
try {
|
|
||||||
queryExecute("
|
|
||||||
ALTER TABLE ScheduledTaskDefinitions
|
|
||||||
ADD COLUMN ScheduleType VARCHAR(20) DEFAULT 'cron' AFTER CronExpression
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
} catch (any e) {
|
|
||||||
// Column likely already exists
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
queryExecute("
|
|
||||||
ALTER TABLE ScheduledTaskDefinitions
|
|
||||||
ADD COLUMN IntervalMinutes INT NULL AFTER ScheduleType
|
|
||||||
", [], { datasource: "payfrit" });
|
|
||||||
} catch (any e) {
|
|
||||||
// Column likely already exists
|
|
||||||
}
|
|
||||||
|
|
||||||
apiAbort({
|
apiAbort({
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"MESSAGE": "ScheduledTaskDefinitions table created/verified with interval support"
|
"MESSAGE": "ScheduledTaskDefinitions table created/verified"
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
|
|
|
||||||
|
|
@ -97,13 +97,11 @@ try {
|
||||||
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "ScheduledTaskID is required" });
|
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "ScheduledTaskID is required" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify exists and get cron expression and schedule type
|
// Verify exists and get cron expression
|
||||||
qCheck = queryExecute("
|
qCheck = queryExecute("
|
||||||
SELECT ScheduledTaskID, CronExpression as CronExpression,
|
SELECT ScheduledTaskID, ScheduledTaskCronExpression as CronExpression
|
||||||
COALESCE(ScheduleType, 'cron') as ScheduleType,
|
|
||||||
IntervalMinutes as IntervalMinutes
|
|
||||||
FROM ScheduledTaskDefinitions
|
FROM ScheduledTaskDefinitions
|
||||||
WHERE ID = :id AND BusinessID = :businessID
|
WHERE ScheduledTaskID = :id AND ScheduledTaskBusinessID = :businessID
|
||||||
", {
|
", {
|
||||||
id: { value: taskID, cfsqltype: "cf_sql_integer" },
|
id: { value: taskID, cfsqltype: "cf_sql_integer" },
|
||||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
@ -113,26 +111,20 @@ try {
|
||||||
apiAbort({ "OK": false, "ERROR": "not_found", "MESSAGE": "Scheduled task not found" });
|
apiAbort({ "OK": false, "ERROR": "not_found", "MESSAGE": "Scheduled task not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// If enabling, recalculate next run time based on schedule type
|
// If enabling, recalculate next run time
|
||||||
nextRunUpdate = "";
|
nextRunUpdate = "";
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
if ((qCheck.ScheduleType == "interval" || qCheck.ScheduleType == "interval_after_completion") && !isNull(qCheck.IntervalMinutes) && qCheck.IntervalMinutes > 0) {
|
nextRunOn = calculateNextRun(qCheck.CronExpression);
|
||||||
// Interval-based: next run = NOW + interval minutes
|
nextRunUpdate = ", ScheduledTaskNextRunOn = :nextRun";
|
||||||
nextRunOn = dateAdd("n", qCheck.IntervalMinutes, now());
|
|
||||||
} else {
|
|
||||||
// Cron-based: use cron parser
|
|
||||||
nextRunOn = calculateNextRun(qCheck.CronExpression);
|
|
||||||
}
|
|
||||||
nextRunUpdate = ", NextRunOn = :nextRun";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update status
|
// Update status
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE ScheduledTaskDefinitions SET
|
UPDATE ScheduledTaskDefinitions SET
|
||||||
IsActive = :isActive,
|
ScheduledTaskIsActive = :isActive,
|
||||||
NextRunOn = :nextRun
|
ScheduledTaskNextRunOn = :nextRun
|
||||||
WHERE ID = :id
|
WHERE ScheduledTaskID = :id
|
||||||
", {
|
", {
|
||||||
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
||||||
nextRun: { value: nextRunOn, cfsqltype: "cf_sql_timestamp" },
|
nextRun: { value: nextRunOn, cfsqltype: "cf_sql_timestamp" },
|
||||||
|
|
@ -140,8 +132,8 @@ try {
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
} else {
|
} else {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE ScheduledTaskDefinitions SET IsActive = :isActive
|
UPDATE ScheduledTaskDefinitions SET ScheduledTaskIsActive = :isActive
|
||||||
WHERE ID = :id
|
WHERE ScheduledTaskID = :id
|
||||||
", {
|
", {
|
||||||
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
||||||
id: { value: taskID, cfsqltype: "cf_sql_integer" }
|
id: { value: taskID, cfsqltype: "cf_sql_integer" }
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ if (businessId <= 0 || userId <= 0) {
|
||||||
try {
|
try {
|
||||||
// Update employee record
|
// Update employee record
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Employees
|
UPDATE lt_Users_Businesses_Employees
|
||||||
SET IsActive = ?
|
SET EmployeeIsActive = ?
|
||||||
WHERE BusinessID = ? AND UserID = ?
|
WHERE BusinessID = ? AND UserID = ?
|
||||||
", [
|
", [
|
||||||
{ value: isActive, cfsqltype: "cf_sql_bit" },
|
{ value: isActive, cfsqltype: "cf_sql_bit" },
|
||||||
|
|
@ -32,12 +32,12 @@ try {
|
||||||
|
|
||||||
// Get updated record
|
// Get updated record
|
||||||
q = queryExecute("
|
q = queryExecute("
|
||||||
SELECT e.ID, e.BusinessID, e.UserID, e.StatusID,
|
SELECT e.EmployeeID, e.BusinessID, e.UserID, e.EmployeeStatusID,
|
||||||
CAST(e.IsActive AS UNSIGNED) AS IsActive,
|
CAST(e.EmployeeIsActive AS UNSIGNED) AS EmployeeIsActive,
|
||||||
b.Name, u.FirstName, u.LastName
|
b.BusinessName, u.UserFirstName, u.UserLastName
|
||||||
FROM Employees e
|
FROM lt_Users_Businesses_Employees e
|
||||||
JOIN Businesses b ON e.BusinessID = b.ID
|
JOIN Businesses b ON e.BusinessID = b.BusinessID
|
||||||
JOIN Users u ON e.UserID = u.ID
|
JOIN Users u ON e.UserID = u.UserID
|
||||||
WHERE e.BusinessID = ? AND e.UserID = ?
|
WHERE e.BusinessID = ? AND e.UserID = ?
|
||||||
", [
|
", [
|
||||||
{ value: businessId, cfsqltype: "cf_sql_integer" },
|
{ value: businessId, cfsqltype: "cf_sql_integer" },
|
||||||
|
|
@ -49,13 +49,13 @@ try {
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"MESSAGE": "Employee updated",
|
"MESSAGE": "Employee updated",
|
||||||
"EMPLOYEE": {
|
"EMPLOYEE": {
|
||||||
"EmployeeID": q.ID,
|
"EmployeeID": q.EmployeeID,
|
||||||
"BusinessID": q.BusinessID,
|
"BusinessID": q.BusinessID,
|
||||||
"Name": q.Name,
|
"BusinessName": q.BusinessName,
|
||||||
"UserID": q.UserID,
|
"UserID": q.UserID,
|
||||||
"UserName": trim(q.FirstName & " " & q.LastName),
|
"UserName": trim(q.UserFirstName & " " & q.UserLastName),
|
||||||
"StatusID": q.StatusID,
|
"StatusID": q.EmployeeStatusID,
|
||||||
"IsActive": q.IsActive
|
"IsActive": q.EmployeeIsActive
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ response = { "OK": false };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Businesses SET HeaderImageExtension = 'jpg' WHERE ID = 37
|
UPDATE Businesses SET BusinessHeaderImageExtension = 'jpg' WHERE BusinessID = 37
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
response.OK = true;
|
response.OK = true;
|
||||||
response.message = "Set HeaderImageExtension to 'jpg' for business 37";
|
response.message = "Set BusinessHeaderImageExtension to 'jpg' for business 37";
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
response.error = e.message;
|
response.error = e.message;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<cfscript>
|
<cfscript>
|
||||||
/**
|
/**
|
||||||
* Setup Lazy Daisy Beacons
|
* Setup Lazy Daisy Beacons
|
||||||
* Creates a beacon for each service point and assigns them
|
* Creates a beacon for each service point and links them
|
||||||
*/
|
*/
|
||||||
response = { "OK": false, "steps": [] };
|
response = { "OK": false, "steps": [] };
|
||||||
|
|
||||||
|
|
@ -14,10 +14,10 @@ try {
|
||||||
|
|
||||||
// Get all service points for Lazy Daisy
|
// Get all service points for Lazy Daisy
|
||||||
qServicePoints = queryExecute("
|
qServicePoints = queryExecute("
|
||||||
SELECT ID, Name
|
SELECT ServicePointID, ServicePointName
|
||||||
FROM ServicePoints
|
FROM ServicePoints
|
||||||
WHERE BusinessID = :bizID AND IsActive = 1
|
WHERE ServicePointBusinessID = :bizID AND ServicePointIsActive = 1
|
||||||
ORDER BY SortOrder, ID
|
ORDER BY ServicePointID
|
||||||
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
response.steps.append("Found " & qServicePoints.recordCount & " service points for Lazy Daisy");
|
response.steps.append("Found " & qServicePoints.recordCount & " service points for Lazy Daisy");
|
||||||
|
|
@ -25,20 +25,20 @@ try {
|
||||||
// Create a beacon for each service point
|
// Create a beacon for each service point
|
||||||
beaconsCreated = 0;
|
beaconsCreated = 0;
|
||||||
for (sp in qServicePoints) {
|
for (sp in qServicePoints) {
|
||||||
beaconName = "Beacon - " & sp.Name;
|
beaconName = "Beacon - " & sp.ServicePointName;
|
||||||
|
|
||||||
// Check if beacon already exists for this business with this name
|
// Check if beacon already exists for this business with this name
|
||||||
qExisting = queryExecute("
|
qExisting = queryExecute("
|
||||||
SELECT ID FROM Beacons
|
SELECT BeaconID FROM Beacons
|
||||||
WHERE BusinessID = :bizId AND Name = :name
|
WHERE BeaconBusinessID = :bizId AND BeaconName = :name
|
||||||
", { bizId: lazyDaisyID, name: beaconName }, { datasource: "payfrit" });
|
", { bizId: lazyDaisyID, name: beaconName }, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qExisting.recordCount == 0) {
|
if (qExisting.recordCount == 0) {
|
||||||
// Generate a unique UUID for this beacon (32 hex chars, no dashes)
|
// Generate a unique UUID for this beacon (32 hex chars, no dashes)
|
||||||
beaconUUID = "PAYFRIT00037" & numberFormat(sp.ID, "0000000000000000000");
|
beaconUUID = "PAYFRIT00037" & numberFormat(sp.ServicePointID, "0000000000000000000");
|
||||||
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Beacons (BusinessID, Name, UUID, IsActive)
|
INSERT INTO Beacons (BeaconBusinessID, BeaconName, BeaconUUID, BeaconIsActive)
|
||||||
VALUES (:bizId, :name, :uuid, 1)
|
VALUES (:bizId, :name, :uuid, 1)
|
||||||
", {
|
", {
|
||||||
bizId: lazyDaisyID,
|
bizId: lazyDaisyID,
|
||||||
|
|
@ -49,18 +49,18 @@ try {
|
||||||
qNewBeacon = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
qNewBeacon = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
||||||
newBeaconId = qNewBeacon.id;
|
newBeaconId = qNewBeacon.id;
|
||||||
|
|
||||||
// Assign beacon directly to service point
|
// Create assignment to service point
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE ServicePoints
|
INSERT INTO lt_Beacon_Businesses_ServicePoints
|
||||||
SET BeaconID = :beaconId, AssignedByUserID = 1
|
(BeaconID, BusinessID, ServicePointID, lt_Beacon_Businesses_ServicePointAssignedByUserID)
|
||||||
WHERE ID = :spId AND BusinessID = :bizId
|
VALUES (:beaconId, :bizId, :spId, 1)
|
||||||
", {
|
", {
|
||||||
beaconId: newBeaconId,
|
beaconId: newBeaconId,
|
||||||
bizId: lazyDaisyID,
|
bizId: lazyDaisyID,
|
||||||
spId: sp.ID
|
spId: sp.ServicePointID
|
||||||
}, { datasource: "payfrit" });
|
}, { datasource: "payfrit" });
|
||||||
|
|
||||||
response.steps.append("Created beacon '" & beaconName & "' (ID: " & newBeaconId & ") -> " & sp.Name);
|
response.steps.append("Created beacon '" & beaconName & "' (ID: " & newBeaconId & ") -> " & sp.ServicePointName);
|
||||||
beaconsCreated++;
|
beaconsCreated++;
|
||||||
} else {
|
} else {
|
||||||
response.steps.append("Beacon '" & beaconName & "' already exists, skipping");
|
response.steps.append("Beacon '" & beaconName & "' already exists, skipping");
|
||||||
|
|
@ -69,14 +69,13 @@ try {
|
||||||
|
|
||||||
// Get final status
|
// Get final status
|
||||||
qFinal = queryExecute("
|
qFinal = queryExecute("
|
||||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
SELECT lt.BeaconID, b.BeaconUUID, b.BeaconName, lt.BusinessID, biz.BusinessName, lt.ServicePointID, sp.ServicePointName
|
||||||
b.Name AS BeaconName, b.UUID, sp.Name AS ServicePointName,
|
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||||
biz.Name AS BusinessName
|
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||||
FROM ServicePoints sp
|
JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
WHERE lt.BusinessID = :bizId
|
||||||
WHERE sp.BusinessID = :bizId AND sp.BeaconID IS NOT NULL
|
ORDER BY sp.ServicePointName
|
||||||
ORDER BY sp.Name
|
|
||||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
beacons = [];
|
beacons = [];
|
||||||
|
|
@ -84,9 +83,8 @@ try {
|
||||||
arrayAppend(beacons, {
|
arrayAppend(beacons, {
|
||||||
"BeaconID": qFinal.BeaconID[i],
|
"BeaconID": qFinal.BeaconID[i],
|
||||||
"BeaconName": qFinal.BeaconName[i],
|
"BeaconName": qFinal.BeaconName[i],
|
||||||
"UUID": qFinal.UUID[i],
|
"UUID": qFinal.BeaconUUID[i],
|
||||||
"BusinessName": qFinal.BusinessName[i],
|
"BusinessName": qFinal.BusinessName[i],
|
||||||
"ServicePointID": qFinal.ServicePointID[i],
|
|
||||||
"ServicePointName": qFinal.ServicePointName[i]
|
"ServicePointName": qFinal.ServicePointName[i]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,19 +13,19 @@ try {
|
||||||
// Hours: Mon-Thu: 11am-10pm, Fri-Sat: 11am-11pm, Sun: 11am-10pm
|
// Hours: Mon-Thu: 11am-10pm, Fri-Sat: 11am-11pm, Sun: 11am-10pm
|
||||||
|
|
||||||
// Get California StateID
|
// Get California StateID
|
||||||
qState = queryExecute("SELECT tt_StateID FROM tt_States WHERE Abbreviation = 'CA' LIMIT 1");
|
qState = queryExecute("SELECT tt_StateID FROM tt_States WHERE tt_StateAbbreviation = 'CA' LIMIT 1");
|
||||||
stateId = qState.recordCount > 0 ? qState.tt_StateID : 5; // Default to 5 if not found
|
stateId = qState.recordCount > 0 ? qState.tt_StateID : 5; // Default to 5 if not found
|
||||||
|
|
||||||
// Check if Big Dean's already has an address
|
// Check if Big Dean's already has an address
|
||||||
existingAddr = queryExecute("
|
existingAddr = queryExecute("
|
||||||
SELECT ID FROM Addresses
|
SELECT AddressID FROM Addresses
|
||||||
WHERE BusinessID = :bizId AND UserID = 0
|
WHERE AddressBusinessID = :bizId AND AddressUserID = 0
|
||||||
", { bizId: businessId });
|
", { bizId: businessId });
|
||||||
|
|
||||||
if (existingAddr.recordCount == 0) {
|
if (existingAddr.recordCount == 0) {
|
||||||
// Insert new address
|
// Insert new address
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Addresses (UserID, BusinessID, AddressTypeID, Line1, City, StateID, ZIPCode, IsDeleted, AddedOn)
|
INSERT INTO Addresses (AddressUserID, AddressBusinessID, AddressTypeID, AddressLine1, AddressCity, AddressStateID, AddressZIPCode, AddressIsDeleted, AddressAddedOn)
|
||||||
VALUES (0, :bizId, '2', :line1, :city, :stateId, :zip, 0, NOW())
|
VALUES (0, :bizId, '2', :line1, :city, :stateId, :zip, 0, NOW())
|
||||||
", {
|
", {
|
||||||
bizId: businessId,
|
bizId: businessId,
|
||||||
|
|
@ -39,8 +39,8 @@ try {
|
||||||
// Update existing address
|
// Update existing address
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Addresses
|
UPDATE Addresses
|
||||||
SET Line1 = :line1, City = :city, StateID = :stateId, ZIPCode = :zip
|
SET AddressLine1 = :line1, AddressCity = :city, AddressStateID = :stateId, AddressZIPCode = :zip
|
||||||
WHERE BusinessID = :bizId AND UserID = 0
|
WHERE AddressBusinessID = :bizId AND AddressUserID = 0
|
||||||
", {
|
", {
|
||||||
bizId: businessId,
|
bizId: businessId,
|
||||||
line1: "1615 Ocean Front Walk",
|
line1: "1615 Ocean Front Walk",
|
||||||
|
|
@ -53,7 +53,7 @@ try {
|
||||||
|
|
||||||
// Check existing hours for this business
|
// Check existing hours for this business
|
||||||
existingHours = queryExecute("
|
existingHours = queryExecute("
|
||||||
SELECT COUNT(*) as cnt FROM Hours WHERE BusinessID = :bizId
|
SELECT COUNT(*) as cnt FROM Hours WHERE HoursBusinessID = :bizId
|
||||||
", { bizId: businessId });
|
", { bizId: businessId });
|
||||||
|
|
||||||
if (existingHours.cnt == 0) {
|
if (existingHours.cnt == 0) {
|
||||||
|
|
@ -64,39 +64,39 @@ try {
|
||||||
// Sun: 11am-10pm (day 1)
|
// Sun: 11am-10pm (day 1)
|
||||||
|
|
||||||
// Sunday (1): 11am-10pm
|
// Sunday (1): 11am-10pm
|
||||||
queryExecute("INSERT INTO Hours (BusinessID, DayID, OpenTime, ClosingTime) VALUES (:bizId, 1, '11:00:00', '22:00:00')", { bizId: businessId });
|
queryExecute("INSERT INTO Hours (HoursBusinessID, HoursDayID, HoursOpenTime, HoursClosingTime) VALUES (:bizId, 1, '11:00:00', '22:00:00')", { bizId: businessId });
|
||||||
|
|
||||||
// Monday (2): 11am-10pm
|
// Monday (2): 11am-10pm
|
||||||
queryExecute("INSERT INTO Hours (BusinessID, DayID, OpenTime, ClosingTime) VALUES (:bizId, 2, '11:00:00', '22:00:00')", { bizId: businessId });
|
queryExecute("INSERT INTO Hours (HoursBusinessID, HoursDayID, HoursOpenTime, HoursClosingTime) VALUES (:bizId, 2, '11:00:00', '22:00:00')", { bizId: businessId });
|
||||||
|
|
||||||
// Tuesday (3): 11am-10pm
|
// Tuesday (3): 11am-10pm
|
||||||
queryExecute("INSERT INTO Hours (BusinessID, DayID, OpenTime, ClosingTime) VALUES (:bizId, 3, '11:00:00', '22:00:00')", { bizId: businessId });
|
queryExecute("INSERT INTO Hours (HoursBusinessID, HoursDayID, HoursOpenTime, HoursClosingTime) VALUES (:bizId, 3, '11:00:00', '22:00:00')", { bizId: businessId });
|
||||||
|
|
||||||
// Wednesday (4): 11am-10pm
|
// Wednesday (4): 11am-10pm
|
||||||
queryExecute("INSERT INTO Hours (BusinessID, DayID, OpenTime, ClosingTime) VALUES (:bizId, 4, '11:00:00', '22:00:00')", { bizId: businessId });
|
queryExecute("INSERT INTO Hours (HoursBusinessID, HoursDayID, HoursOpenTime, HoursClosingTime) VALUES (:bizId, 4, '11:00:00', '22:00:00')", { bizId: businessId });
|
||||||
|
|
||||||
// Thursday (5): 11am-10pm
|
// Thursday (5): 11am-10pm
|
||||||
queryExecute("INSERT INTO Hours (BusinessID, DayID, OpenTime, ClosingTime) VALUES (:bizId, 5, '11:00:00', '22:00:00')", { bizId: businessId });
|
queryExecute("INSERT INTO Hours (HoursBusinessID, HoursDayID, HoursOpenTime, HoursClosingTime) VALUES (:bizId, 5, '11:00:00', '22:00:00')", { bizId: businessId });
|
||||||
|
|
||||||
// Friday (6): 11am-11pm
|
// Friday (6): 11am-11pm
|
||||||
queryExecute("INSERT INTO Hours (BusinessID, DayID, OpenTime, ClosingTime) VALUES (:bizId, 6, '11:00:00', '23:00:00')", { bizId: businessId });
|
queryExecute("INSERT INTO Hours (HoursBusinessID, HoursDayID, HoursOpenTime, HoursClosingTime) VALUES (:bizId, 6, '11:00:00', '23:00:00')", { bizId: businessId });
|
||||||
|
|
||||||
// Saturday (7): 11am-11pm
|
// Saturday (7): 11am-11pm
|
||||||
queryExecute("INSERT INTO Hours (BusinessID, DayID, OpenTime, ClosingTime) VALUES (:bizId, 7, '11:00:00', '23:00:00')", { bizId: businessId });
|
queryExecute("INSERT INTO Hours (HoursBusinessID, HoursDayID, HoursOpenTime, HoursClosingTime) VALUES (:bizId, 7, '11:00:00', '23:00:00')", { bizId: businessId });
|
||||||
|
|
||||||
response["HOURS_ACTION"] = "inserted 7 days";
|
response["HOURS_ACTION"] = "inserted 7 days";
|
||||||
} else {
|
} else {
|
||||||
// Update existing hours
|
// Update existing hours
|
||||||
// Mon-Thu: 11am-10pm
|
// Mon-Thu: 11am-10pm
|
||||||
queryExecute("UPDATE Hours SET OpenTime = '11:00:00', ClosingTime = '22:00:00' WHERE BusinessID = :bizId AND DayID IN (1, 2, 3, 4, 5)", { bizId: businessId });
|
queryExecute("UPDATE Hours SET HoursOpenTime = '11:00:00', HoursClosingTime = '22:00:00' WHERE HoursBusinessID = :bizId AND HoursDayID IN (1, 2, 3, 4, 5)", { bizId: businessId });
|
||||||
// Fri-Sat: 11am-11pm
|
// Fri-Sat: 11am-11pm
|
||||||
queryExecute("UPDATE Hours SET OpenTime = '11:00:00', ClosingTime = '23:00:00' WHERE BusinessID = :bizId AND DayID IN (6, 7)", { bizId: businessId });
|
queryExecute("UPDATE Hours SET HoursOpenTime = '11:00:00', HoursClosingTime = '23:00:00' WHERE HoursBusinessID = :bizId AND HoursDayID IN (6, 7)", { bizId: businessId });
|
||||||
response["HOURS_ACTION"] = "updated";
|
response["HOURS_ACTION"] = "updated";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update phone on Businesses table (if column exists)
|
// Update phone on Businesses table (if column exists)
|
||||||
try {
|
try {
|
||||||
queryExecute("UPDATE Businesses SET Phone = :phone WHERE ID = :bizId", {
|
queryExecute("UPDATE Businesses SET BusinessPhone = :phone WHERE BusinessID = :bizId", {
|
||||||
phone: "(310) 393-2666",
|
phone: "(310) 393-2666",
|
||||||
bizId: businessId
|
bizId: businessId
|
||||||
});
|
});
|
||||||
|
|
@ -107,35 +107,35 @@ try {
|
||||||
|
|
||||||
// Verify the data
|
// Verify the data
|
||||||
address = queryExecute("
|
address = queryExecute("
|
||||||
SELECT a.*, s.Abbreviation
|
SELECT a.*, s.tt_StateAbbreviation
|
||||||
FROM Addresses a
|
FROM Addresses a
|
||||||
LEFT JOIN tt_States s ON s.ID = a.StateID
|
LEFT JOIN tt_States s ON s.tt_StateID = a.AddressStateID
|
||||||
WHERE a.BusinessID = :bizId AND a.UserID = 0
|
WHERE a.AddressBusinessID = :bizId AND a.AddressUserID = 0
|
||||||
", { bizId: businessId });
|
", { bizId: businessId });
|
||||||
|
|
||||||
hours = queryExecute("
|
hours = queryExecute("
|
||||||
SELECT h.*, d.tt_DayName
|
SELECT h.*, d.tt_DayName
|
||||||
FROM Hours h
|
FROM Hours h
|
||||||
JOIN tt_Days d ON d.ID = h.DayID
|
JOIN tt_Days d ON d.tt_DayID = h.HoursDayID
|
||||||
WHERE h.BusinessID = :bizId
|
WHERE h.HoursBusinessID = :bizId
|
||||||
ORDER BY h.DayID
|
ORDER BY h.HoursDayID
|
||||||
", { bizId: businessId });
|
", { bizId: businessId });
|
||||||
|
|
||||||
response["OK"] = true;
|
response["OK"] = true;
|
||||||
response["BUSINESS_ID"] = businessId;
|
response["BUSINESS_ID"] = businessId;
|
||||||
response["ADDRESS"] = address.recordCount > 0 ? {
|
response["ADDRESS"] = address.recordCount > 0 ? {
|
||||||
"line1": address.Line1,
|
"line1": address.AddressLine1,
|
||||||
"city": address.City,
|
"city": address.AddressCity,
|
||||||
"state": address.Abbreviation,
|
"state": address.tt_StateAbbreviation,
|
||||||
"zip": address.ZIPCode
|
"zip": address.AddressZIPCode
|
||||||
} : "not found";
|
} : "not found";
|
||||||
|
|
||||||
hoursArr = [];
|
hoursArr = [];
|
||||||
for (h in hours) {
|
for (h in hours) {
|
||||||
arrayAppend(hoursArr, {
|
arrayAppend(hoursArr, {
|
||||||
"day": h.tt_DayName,
|
"day": h.tt_DayName,
|
||||||
"open": timeFormat(h.OpenTime, "h:mm tt"),
|
"open": timeFormat(h.HoursOpenTime, "h:mm tt"),
|
||||||
"close": timeFormat(h.ClosingTime, "h:mm tt")
|
"close": timeFormat(h.HoursClosingTime, "h:mm tt")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
response["HOURS"] = hoursArr;
|
response["HOURS"] = hoursArr;
|
||||||
|
|
|
||||||
|
|
@ -9,19 +9,19 @@ response = { "OK": false };
|
||||||
try {
|
try {
|
||||||
// Check if Big Dean's already has stations
|
// Check if Big Dean's already has stations
|
||||||
existing = queryExecute("
|
existing = queryExecute("
|
||||||
SELECT COUNT(*) as cnt FROM Stations WHERE BusinessID = :bizId
|
SELECT COUNT(*) as cnt FROM Stations WHERE StationBusinessID = :bizId
|
||||||
", { bizId: businessId });
|
", { bizId: businessId });
|
||||||
|
|
||||||
if (existing.cnt == 0) {
|
if (existing.cnt == 0) {
|
||||||
// Insert Kitchen station
|
// Insert Kitchen station
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Stations (BusinessID, Name, Color, SortOrder, IsActive)
|
INSERT INTO Stations (StationBusinessID, StationName, StationColor, StationSortOrder, StationIsActive)
|
||||||
VALUES (:bizId, 'Kitchen', :color1, 1, 1)
|
VALUES (:bizId, 'Kitchen', :color1, 1, 1)
|
||||||
", { bizId: businessId, color1: "##FF5722" });
|
", { bizId: businessId, color1: "##FF5722" });
|
||||||
|
|
||||||
// Insert Bar station
|
// Insert Bar station
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO Stations (BusinessID, Name, Color, SortOrder, IsActive)
|
INSERT INTO Stations (StationBusinessID, StationName, StationColor, StationSortOrder, StationIsActive)
|
||||||
VALUES (:bizId, 'Bar', :color2, 2, 1)
|
VALUES (:bizId, 'Bar', :color2, 2, 1)
|
||||||
", { bizId: businessId, color2: "##2196F3" });
|
", { bizId: businessId, color2: "##2196F3" });
|
||||||
|
|
||||||
|
|
@ -32,18 +32,18 @@ try {
|
||||||
|
|
||||||
// Get current stations
|
// Get current stations
|
||||||
stations = queryExecute("
|
stations = queryExecute("
|
||||||
SELECT ID, Name, Color, SortOrder
|
SELECT StationID, StationName, StationColor, StationSortOrder
|
||||||
FROM Stations
|
FROM Stations
|
||||||
WHERE BusinessID = :bizId AND IsActive = 1
|
WHERE StationBusinessID = :bizId AND StationIsActive = 1
|
||||||
ORDER BY SortOrder
|
ORDER BY StationSortOrder
|
||||||
", { bizId: businessId });
|
", { bizId: businessId });
|
||||||
|
|
||||||
stationArr = [];
|
stationArr = [];
|
||||||
for (s in stations) {
|
for (s in stations) {
|
||||||
arrayAppend(stationArr, {
|
arrayAppend(stationArr, {
|
||||||
"StationID": s.ID,
|
"StationID": s.StationID,
|
||||||
"Name": s.Name,
|
"StationName": s.StationName,
|
||||||
"Color": s.Color
|
"StationColor": s.StationColor
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,62 +9,67 @@ try {
|
||||||
lazyDaisyID = 37;
|
lazyDaisyID = 37;
|
||||||
|
|
||||||
// Get all beacons
|
// Get all beacons
|
||||||
qBeacons = queryExecute("SELECT ID, UUID FROM Beacons", {}, { datasource: "payfrit" });
|
qBeacons = queryExecute("SELECT BeaconID, BeaconUUID FROM Beacons", {}, { datasource: "payfrit" });
|
||||||
response.steps.append("Found " & qBeacons.recordCount & " beacons");
|
response.steps.append("Found " & qBeacons.recordCount & " beacons");
|
||||||
|
|
||||||
// Create service point for Table 1 if it doesn't exist
|
// Create service point for Table 1 if it doesn't exist
|
||||||
qSP = queryExecute("
|
qSP = queryExecute("
|
||||||
SELECT ID FROM ServicePoints
|
SELECT ServicePointID FROM ServicePoints
|
||||||
WHERE BusinessID = :bizID AND Name = 'Table 1'
|
WHERE ServicePointBusinessID = :bizID AND ServicePointName = 'Table 1'
|
||||||
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
if (qSP.recordCount == 0) {
|
if (qSP.recordCount == 0) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
INSERT INTO ServicePoints (BusinessID, Name)
|
INSERT INTO ServicePoints (ServicePointBusinessID, ServicePointName, ServicePointTypeID)
|
||||||
VALUES (:bizID, 'Table 1')
|
VALUES (:bizID, 'Table 1', 1)
|
||||||
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||||
qSP = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
qSP = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
||||||
servicePointID = qSP.id;
|
servicePointID = qSP.id;
|
||||||
response.steps.append("Created service point 'Table 1' (ID: " & servicePointID & ")");
|
response.steps.append("Created service point 'Table 1' (ID: " & servicePointID & ")");
|
||||||
} else {
|
} else {
|
||||||
servicePointID = qSP.ID;
|
servicePointID = qSP.ServicePointID;
|
||||||
response.steps.append("Found existing service point 'Table 1' (ID: " & servicePointID & ")");
|
response.steps.append("Found existing service point 'Table 1' (ID: " & servicePointID & ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign all beacons to the Table 1 service point
|
// Map all beacons to Lazy Daisy with Table 1
|
||||||
for (i = 1; i <= qBeacons.recordCount; i++) {
|
for (i = 1; i <= qBeacons.recordCount; i++) {
|
||||||
beaconID = qBeacons.ID[i];
|
beaconID = qBeacons.BeaconID[i];
|
||||||
|
|
||||||
// Unassign this beacon from any other service point first
|
// Check if mapping exists
|
||||||
queryExecute("
|
qMap = queryExecute("
|
||||||
UPDATE ServicePoints SET BeaconID = NULL, AssignedByUserID = NULL
|
SELECT * FROM lt_Beacon_Businesses_ServicePoints WHERE BeaconID = :beaconID
|
||||||
WHERE BeaconID = :beaconID
|
|
||||||
", { beaconID: beaconID }, { datasource: "payfrit" });
|
", { beaconID: beaconID }, { datasource: "payfrit" });
|
||||||
|
|
||||||
// Assign beacon to Table 1 service point
|
if (qMap.recordCount == 0) {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE ServicePoints SET BeaconID = :beaconID, AssignedByUserID = 1
|
INSERT INTO lt_Beacon_Businesses_ServicePoints (BeaconID, BusinessID, ServicePointID)
|
||||||
WHERE ID = :spID AND BusinessID = :bizID
|
VALUES (:beaconID, :bizID, :spID)
|
||||||
", { beaconID: beaconID, bizID: lazyDaisyID, spID: servicePointID }, { datasource: "payfrit" });
|
", { beaconID: beaconID, bizID: lazyDaisyID, spID: servicePointID }, { datasource: "payfrit" });
|
||||||
response.steps.append("Assigned beacon " & beaconID & " to Table 1");
|
response.steps.append("Created mapping for beacon " & beaconID);
|
||||||
|
} else {
|
||||||
|
queryExecute("
|
||||||
|
UPDATE lt_Beacon_Businesses_ServicePoints
|
||||||
|
SET BusinessID = :bizID, ServicePointID = :spID
|
||||||
|
WHERE BeaconID = :beaconID
|
||||||
|
", { beaconID: beaconID, bizID: lazyDaisyID, spID: servicePointID }, { datasource: "payfrit" });
|
||||||
|
response.steps.append("Updated mapping for beacon " & beaconID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get final status
|
// Get final status
|
||||||
qFinal = queryExecute("
|
qFinal = queryExecute("
|
||||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
SELECT lt.BeaconID, b.BeaconUUID, lt.BusinessID, biz.BusinessName, lt.ServicePointID, sp.ServicePointName
|
||||||
b.Name AS BeaconName, b.UUID, sp.Name AS ServicePointName,
|
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||||
biz.Name AS BusinessName
|
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||||
FROM ServicePoints sp
|
JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
|
||||||
WHERE sp.BeaconID IS NOT NULL
|
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
beacons = [];
|
beacons = [];
|
||||||
for (i = 1; i <= qFinal.recordCount; i++) {
|
for (i = 1; i <= qFinal.recordCount; i++) {
|
||||||
arrayAppend(beacons, {
|
arrayAppend(beacons, {
|
||||||
"BeaconID": qFinal.BeaconID[i],
|
"BeaconID": qFinal.BeaconID[i],
|
||||||
"UUID": qFinal.UUID[i],
|
"UUID": qFinal.BeaconUUID[i],
|
||||||
"BusinessID": qFinal.BusinessID[i],
|
"BusinessID": qFinal.BusinessID[i],
|
||||||
"BusinessName": qFinal.BusinessName[i],
|
"BusinessName": qFinal.BusinessName[i],
|
||||||
"ServicePointID": qFinal.ServicePointID[i],
|
"ServicePointID": qFinal.ServicePointID[i],
|
||||||
|
|
|
||||||
|
|
@ -11,32 +11,32 @@
|
||||||
<cfscript>
|
<cfscript>
|
||||||
/**
|
/**
|
||||||
* Setup Modifier Templates system
|
* Setup Modifier Templates system
|
||||||
* 1. Add IsModifierTemplate column to Items
|
* 1. Add ItemIsModifierTemplate column to Items
|
||||||
* 2. Create lt_ItemID_TemplateItemID table
|
* 2. Create ItemTemplateLinks table
|
||||||
*/
|
*/
|
||||||
|
|
||||||
response = { "OK": false, "steps": [] };
|
response = { "OK": false, "steps": [] };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Step 1: Add IsModifierTemplate column if it doesn't exist
|
// Step 1: Add ItemIsModifierTemplate column if it doesn't exist
|
||||||
try {
|
try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
ALTER TABLE Items ADD COLUMN IsModifierTemplate TINYINT(1) DEFAULT 0
|
ALTER TABLE Items ADD COLUMN ItemIsModifierTemplate TINYINT(1) DEFAULT 0
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
arrayAppend(response.steps, "Added IsModifierTemplate column");
|
arrayAppend(response.steps, "Added ItemIsModifierTemplate column");
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
if (findNoCase("Duplicate column", e.message)) {
|
if (findNoCase("Duplicate column", e.message)) {
|
||||||
arrayAppend(response.steps, "IsModifierTemplate column already exists");
|
arrayAppend(response.steps, "ItemIsModifierTemplate column already exists");
|
||||||
} else {
|
} else {
|
||||||
arrayAppend(response.steps, "Error adding column: " & e.message);
|
arrayAppend(response.steps, "Error adding column: " & e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: Create lt_ItemID_TemplateItemID table if it doesn't exist
|
// Step 2: Create ItemTemplateLinks table if it doesn't exist
|
||||||
try {
|
try {
|
||||||
queryExecute("
|
queryExecute("
|
||||||
CREATE TABLE IF NOT EXISTS lt_ItemID_TemplateItemID (
|
CREATE TABLE IF NOT EXISTS ItemTemplateLinks (
|
||||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
LinkID INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
ItemID INT NOT NULL,
|
ItemID INT NOT NULL,
|
||||||
TemplateItemID INT NOT NULL,
|
TemplateItemID INT NOT NULL,
|
||||||
SortOrder INT DEFAULT 0,
|
SortOrder INT DEFAULT 0,
|
||||||
|
|
@ -45,9 +45,9 @@ try {
|
||||||
INDEX idx_template (TemplateItemID)
|
INDEX idx_template (TemplateItemID)
|
||||||
)
|
)
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
arrayAppend(response.steps, "Created lt_ItemID_TemplateItemID table");
|
arrayAppend(response.steps, "Created ItemTemplateLinks table");
|
||||||
} catch (any e) {
|
} catch (any e) {
|
||||||
arrayAppend(response.steps, "lt_ItemID_TemplateItemID: " & e.message);
|
arrayAppend(response.steps, "ItemTemplateLinks: " & e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
response["OK"] = true;
|
response["OK"] = true;
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,20 @@
|
||||||
<cfset queryExecute("
|
<cfset queryExecute("
|
||||||
CREATE TABLE IF NOT EXISTS Stations (
|
CREATE TABLE IF NOT EXISTS Stations (
|
||||||
StationID INT AUTO_INCREMENT PRIMARY KEY,
|
StationID INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
BusinessID INT NOT NULL,
|
StationBusinessID INT NOT NULL,
|
||||||
Name VARCHAR(100) NOT NULL,
|
StationName VARCHAR(100) NOT NULL,
|
||||||
Color VARCHAR(7) DEFAULT '##666666',
|
StationColor VARCHAR(7) DEFAULT '##666666',
|
||||||
SortOrder INT DEFAULT 0,
|
StationSortOrder INT DEFAULT 0,
|
||||||
IsActive TINYINT(1) DEFAULT 1,
|
StationIsActive TINYINT(1) DEFAULT 1,
|
||||||
AddedOn DATETIME DEFAULT NOW(),
|
StationAddedOn DATETIME DEFAULT NOW(),
|
||||||
FOREIGN KEY (BusinessID) REFERENCES Businesses(BusinessID)
|
FOREIGN KEY (StationBusinessID) REFERENCES Businesses(BusinessID)
|
||||||
)
|
)
|
||||||
", [], { datasource = "payfrit" })>
|
", [], { datasource = "payfrit" })>
|
||||||
|
|
||||||
<!--- Add StationID column to Items table if it doesn't exist --->
|
<!--- Add ItemStationID column to Items table if it doesn't exist --->
|
||||||
<cftry>
|
<cftry>
|
||||||
<cfset queryExecute("
|
<cfset queryExecute("
|
||||||
ALTER TABLE Items ADD COLUMN StationID INT DEFAULT NULL
|
ALTER TABLE Items ADD COLUMN ItemStationID INT DEFAULT NULL
|
||||||
", [], { datasource = "payfrit" })>
|
", [], { datasource = "payfrit" })>
|
||||||
<cfset stationColumnAdded = true>
|
<cfset stationColumnAdded = true>
|
||||||
<cfcatch>
|
<cfcatch>
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
<cfif stationColumnAdded>
|
<cfif stationColumnAdded>
|
||||||
<cftry>
|
<cftry>
|
||||||
<cfset queryExecute("
|
<cfset queryExecute("
|
||||||
ALTER TABLE Items ADD FOREIGN KEY (StationID) REFERENCES Stations(StationID)
|
ALTER TABLE Items ADD FOREIGN KEY (ItemStationID) REFERENCES Stations(StationID)
|
||||||
", [], { datasource = "payfrit" })>
|
", [], { datasource = "payfrit" })>
|
||||||
<cfcatch></cfcatch>
|
<cfcatch></cfcatch>
|
||||||
</cftry>
|
</cftry>
|
||||||
|
|
@ -47,12 +47,12 @@
|
||||||
|
|
||||||
<!--- Create some default stations for business 1 (In and Out Burger) if none exist --->
|
<!--- Create some default stations for business 1 (In and Out Burger) if none exist --->
|
||||||
<cfset qCheck = queryExecute("
|
<cfset qCheck = queryExecute("
|
||||||
SELECT COUNT(*) AS cnt FROM Stations WHERE BusinessID = 1
|
SELECT COUNT(*) AS cnt FROM Stations WHERE StationBusinessID = 1
|
||||||
", [], { datasource = "payfrit" })>
|
", [], { datasource = "payfrit" })>
|
||||||
|
|
||||||
<cfif qCheck.cnt EQ 0>
|
<cfif qCheck.cnt EQ 0>
|
||||||
<cfset queryExecute("
|
<cfset queryExecute("
|
||||||
INSERT INTO Stations (BusinessID, Name, Color, SortOrder) VALUES
|
INSERT INTO Stations (StationBusinessID, StationName, StationColor, StationSortOrder) VALUES
|
||||||
(1, 'Grill', '##FF5722', 1),
|
(1, 'Grill', '##FF5722', 1),
|
||||||
(1, 'Fry', '##FFC107', 2),
|
(1, 'Fry', '##FFC107', 2),
|
||||||
(1, 'Drinks', '##2196F3', 3),
|
(1, 'Drinks', '##2196F3', 3),
|
||||||
|
|
|
||||||
|
|
@ -3,57 +3,36 @@
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||||
|
|
||||||
<cfscript>
|
<cfscript>
|
||||||
// Switch beacon mapping from one business to another via join table.
|
// Switch all beacons from one business to another
|
||||||
// Beacons.BusinessID (owner) is NOT touched.
|
|
||||||
fromBiz = 17; // In-N-Out
|
fromBiz = 17; // In-N-Out
|
||||||
toBiz = 27; // Big Dean's
|
toBiz = 27; // Big Dean's
|
||||||
|
|
||||||
// Remove mapping for source business
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM lt_BeaconsID_BusinessesID
|
UPDATE lt_Beacon_Businesses_ServicePoints
|
||||||
WHERE BusinessID = :fromBiz
|
SET BusinessID = :toBiz
|
||||||
", { fromBiz: fromBiz }, { datasource: "payfrit" });
|
WHERE BusinessID = :fromBiz
|
||||||
|
|
||||||
// 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" });
|
", { 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
|
// Get current state
|
||||||
q = queryExecute("
|
q = queryExecute("
|
||||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
SELECT lt.*, b.BusinessName
|
||||||
b.Name AS BeaconName, biz.Name AS BusinessName,
|
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||||
sp.Name AS ServicePointName
|
JOIN Businesses b ON b.BusinessID = lt.BusinessID
|
||||||
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" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
rows = [];
|
rows = [];
|
||||||
for (row in q) {
|
for (row in q) {
|
||||||
arrayAppend(rows, {
|
arrayAppend(rows, {
|
||||||
"BeaconID": row.BeaconID,
|
"BeaconID": row.BeaconID,
|
||||||
"BeaconName": row.BeaconName,
|
"BusinessID": row.BusinessID,
|
||||||
"BusinessID": row.BusinessID,
|
"BusinessName": row.BusinessName,
|
||||||
"BusinessName": row.BusinessName,
|
"ServicePointID": row.ServicePointID
|
||||||
"ServicePointID": row.ServicePointID,
|
});
|
||||||
"ServicePointName": row.ServicePointName
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"MESSAGE": "Switched beacons from BusinessID #fromBiz# to #toBiz#",
|
"MESSAGE": "Switched beacons from BusinessID #fromBiz# to #toBiz#",
|
||||||
"MAPPINGS": rows
|
"MAPPINGS": rows
|
||||||
}));
|
}));
|
||||||
</cfscript>
|
</cfscript>
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@
|
||||||
<cfset queryExecute(
|
<cfset queryExecute(
|
||||||
"
|
"
|
||||||
INSERT INTO Tasks (
|
INSERT INTO Tasks (
|
||||||
BusinessID,
|
TaskBusinessID,
|
||||||
OrderID,
|
TaskOrderID,
|
||||||
ClaimedByUserID,
|
TaskClaimedByUserID,
|
||||||
CreatedOn
|
TaskAddedOn
|
||||||
) VALUES (
|
) VALUES (
|
||||||
1,
|
1,
|
||||||
999,
|
999,
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||||
<cfscript>
|
<cfscript>
|
||||||
qTask = queryExecute("
|
qTask = queryExecute("
|
||||||
SELECT ID, TaskTypeID, ClaimedByUserID, CompletedOn
|
SELECT TaskID, TaskTypeID, TaskClaimedByUserID, TaskCompletedOn
|
||||||
FROM Tasks
|
FROM Tasks
|
||||||
WHERE ID = 57
|
WHERE TaskID = 57
|
||||||
", [], { datasource: "payfrit" });
|
", [], { datasource: "payfrit" });
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"TaskID": qTask.ID,
|
"TaskID": qTask.TaskID,
|
||||||
"TaskTypeID": qTask.TaskTypeID,
|
"TaskTypeID": qTask.TaskTypeID,
|
||||||
"ClaimedByUserID": qTask.ClaimedByUserID,
|
"TaskClaimedByUserID": qTask.TaskClaimedByUserID,
|
||||||
"CompletedOn": qTask.CompletedOn
|
"TaskCompletedOn": qTask.TaskCompletedOn
|
||||||
}));
|
}));
|
||||||
</cfscript>
|
</cfscript>
|
||||||
|
|
|
||||||
|
|
@ -3,65 +3,50 @@
|
||||||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||||
|
|
||||||
<cfscript>
|
<cfscript>
|
||||||
// Update beacon mapping via join table. Owner (Beacons.BusinessID) is NOT changed.
|
// Update Beacon 2 to point to In-N-Out (BusinessID 17)
|
||||||
beaconId = 2;
|
beaconId = 2;
|
||||||
oldBusinessId = 37; // previous mapping
|
|
||||||
newBusinessId = 17;
|
newBusinessId = 17;
|
||||||
|
|
||||||
// Remove old mapping
|
|
||||||
queryExecute("
|
queryExecute("
|
||||||
DELETE FROM lt_BeaconsID_BusinessesID
|
UPDATE lt_Beacon_Businesses_ServicePoints
|
||||||
WHERE BeaconID = :beaconId AND BusinessID = :oldBizId
|
SET BusinessID = :newBizId
|
||||||
", { beaconId: beaconId, oldBizId: oldBusinessId }, { datasource: "payfrit" });
|
WHERE BeaconID = :beaconId
|
||||||
|
", { newBizId: newBusinessId, beaconId: beaconId }, { 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
|
// Get current state
|
||||||
q = queryExecute("
|
q = queryExecute("
|
||||||
SELECT
|
SELECT
|
||||||
b.ID AS BeaconID,
|
b.BeaconID,
|
||||||
b.UUID,
|
b.BeaconUUID,
|
||||||
b.Name AS BeaconName,
|
b.BeaconName,
|
||||||
b.BusinessID AS BeaconBusinessID,
|
lt.BusinessID,
|
||||||
sp.ID AS ServicePointID,
|
lt.ServicePointID,
|
||||||
sp.Name AS ServicePointName,
|
biz.BusinessName,
|
||||||
sp.BusinessID AS ServicePointBusinessID,
|
sp.ServicePointName
|
||||||
biz.Name AS BusinessName
|
FROM Beacons b
|
||||||
FROM Beacons b
|
LEFT JOIN lt_Beacon_Businesses_ServicePoints lt ON lt.BeaconID = b.BeaconID
|
||||||
LEFT JOIN ServicePoints sp ON sp.BeaconID = b.ID
|
LEFT JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||||
LEFT JOIN Businesses biz ON biz.ID = b.BusinessID
|
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||||
WHERE b.IsActive = 1
|
WHERE b.BeaconIsActive = 1
|
||||||
ORDER BY b.ID
|
ORDER BY b.BeaconID
|
||||||
", {}, { datasource: "payfrit" });
|
", {}, { datasource: "payfrit" });
|
||||||
|
|
||||||
rows = [];
|
rows = [];
|
||||||
for (row in q) {
|
for (row in q) {
|
||||||
arrayAppend(rows, {
|
arrayAppend(rows, {
|
||||||
"BeaconID": row.BeaconID,
|
"BeaconID": row.BeaconID,
|
||||||
"UUID": row.UUID,
|
"BeaconUUID": row.BeaconUUID,
|
||||||
"BeaconName": row.BeaconName,
|
"BeaconName": row.BeaconName ?: "",
|
||||||
"BeaconBusinessID": row.BeaconBusinessID,
|
"BusinessID": row.BusinessID ?: 0,
|
||||||
"BusinessName": row.BusinessName,
|
"BusinessName": row.BusinessName ?: "",
|
||||||
"ServicePointID": row.ServicePointID ?: 0,
|
"ServicePointID": row.ServicePointID ?: 0,
|
||||||
"ServicePointName": row.ServicePointName ?: ""
|
"ServicePointName": row.ServicePointName ?: ""
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"MESSAGE": "Updated beacon #beaconId# to BusinessID #newBusinessId#",
|
"MESSAGE": "Updated beacon #beaconId# to BusinessID #newBusinessId#",
|
||||||
"BEACONS": rows
|
"BEACONS": rows
|
||||||
}));
|
}));
|
||||||
</cfscript>
|
</cfscript>
|
||||||
|
|
|
||||||
|
|
@ -6,68 +6,72 @@
|
||||||
// Update Big Dean's business info
|
// Update Big Dean's business info
|
||||||
businessId = 27;
|
businessId = 27;
|
||||||
|
|
||||||
// Big Dean's actual info
|
// Big Dean's actual address and hours
|
||||||
|
address = "1615 Ocean Front Walk, Santa Monica, CA 90401";
|
||||||
phone = "(310) 393-2666";
|
phone = "(310) 393-2666";
|
||||||
hours = "Mon-Thu: 11am-10pm, Fri-Sat: 11am-11pm, Sun: 11am-10pm";
|
hours = "Mon-Thu: 11am-10pm, Fri-Sat: 11am-11pm, Sun: 11am-10pm";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Update phone and hours on Businesses table
|
// 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
|
||||||
queryExecute("
|
queryExecute("
|
||||||
UPDATE Businesses
|
UPDATE Businesses
|
||||||
SET Phone = :phone,
|
SET BusinessAddress = :address,
|
||||||
Hours = :hours
|
BusinessPhone = :phone,
|
||||||
WHERE ID = :bizId
|
BusinessHours = :hours
|
||||||
|
WHERE BusinessID = :bizId
|
||||||
", {
|
", {
|
||||||
|
address: address,
|
||||||
phone: phone,
|
phone: phone,
|
||||||
hours: hours,
|
hours: hours,
|
||||||
bizId: businessId
|
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
|
// Get updated record
|
||||||
updated = queryExecute("
|
updated = queryExecute("
|
||||||
SELECT ID, Name, Phone, Hours
|
SELECT BusinessID, BusinessName, BusinessAddress, BusinessPhone, BusinessHours
|
||||||
FROM Businesses
|
FROM Businesses
|
||||||
WHERE ID = :bizId
|
WHERE BusinessID = :bizId
|
||||||
", { bizId: businessId }, { datasource: "payfrit" });
|
", { bizId: businessId });
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
writeOutput(serializeJSON({
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"MESSAGE": "Updated Big Dean's info",
|
"MESSAGE": "Updated Big Dean's info",
|
||||||
|
"COLUMNS_EXISTED": { "address": hasAddress, "phone": hasPhone, "hours": hasHours },
|
||||||
"BUSINESS": {
|
"BUSINESS": {
|
||||||
"BusinessID": updated.ID,
|
"BusinessID": updated.BusinessID,
|
||||||
"Name": updated.Name,
|
"BusinessName": updated.BusinessName,
|
||||||
"Phone": updated.Phone,
|
"BusinessAddress": updated.BusinessAddress,
|
||||||
"Hours": updated.Hours
|
"BusinessPhone": updated.BusinessPhone,
|
||||||
|
"BusinessHours": updated.BusinessHours
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
<cfsetting showdebugoutput="false">
|
|
||||||
<cfsetting enablecfoutputonly="true">
|
|
||||||
<cfcontent type="application/json; charset=utf-8">
|
|
||||||
|
|
||||||
<!---
|
|
||||||
About Screen Content API
|
|
||||||
Returns content for the mobile app's About screen.
|
|
||||||
Edit this file to update the app's about information without releasing a new app version.
|
|
||||||
--->
|
|
||||||
<cfscript>
|
|
||||||
try {
|
|
||||||
// Features displayed on the About screen
|
|
||||||
// icon: Flutter icon name (see AboutFeature._iconMap in about_info.dart)
|
|
||||||
features = [
|
|
||||||
{
|
|
||||||
"ICON": "qr_code_scanner",
|
|
||||||
"TITLE": "Scan & Order",
|
|
||||||
"DESCRIPTION": "Scan the table beacon to browse the menu and order directly from your phone"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ICON": "group",
|
|
||||||
"TITLE": "Group Orders",
|
|
||||||
"DESCRIPTION": "Invite friends to join your order and split the bill easily"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ICON": "delivery_dining",
|
|
||||||
"TITLE": "Delivery & Takeaway",
|
|
||||||
"DESCRIPTION": "Order for delivery or pick up when dining in isn't an option"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ICON": "payment",
|
|
||||||
"TITLE": "Easy Payment",
|
|
||||||
"DESCRIPTION": "Pay your share securely with just a few taps"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// Contact links displayed on the About screen
|
|
||||||
// icon: Flutter icon name (see AboutContact._iconMap in about_info.dart)
|
|
||||||
contacts = [
|
|
||||||
{
|
|
||||||
"ICON": "help_outline",
|
|
||||||
"LABEL": "help.payfrit.com",
|
|
||||||
"URL": "https://help.payfrit.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ICON": "language",
|
|
||||||
"LABEL": "www.payfrit.com",
|
|
||||||
"URL": "https://www.payfrit.com"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": true,
|
|
||||||
"DESCRIPTION": "Payfrit makes dining out easier. Order from your table, split the bill with friends, and pay without waiting.",
|
|
||||||
"FEATURES": features,
|
|
||||||
"CONTACTS": contacts,
|
|
||||||
"COPYRIGHT": "© #year(now())# Payfrit. All rights reserved."
|
|
||||||
}));
|
|
||||||
|
|
||||||
} catch (any e) {
|
|
||||||
writeOutput(serializeJSON({
|
|
||||||
"OK": false,
|
|
||||||
"ERROR": "server_error",
|
|
||||||
"MESSAGE": e.message
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
</cfscript>
|
|
||||||
|
|
@ -34,20 +34,28 @@ if (!structKeyExists(request,"BusinessID") || !isNumeric(request.BusinessID) ||
|
||||||
/* ---------- INPUT ---------- */
|
/* ---------- INPUT ---------- */
|
||||||
data = readJsonBody();
|
data = readJsonBody();
|
||||||
|
|
||||||
if (!structKeyExists(data,"ServicePointID") || !isNumeric(data.ServicePointID) || int(data.ServicePointID) LTE 0){
|
if (
|
||||||
apiAbort({OK=false,ERROR="missing_ServicePointID"});
|
!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"});
|
||||||
}
|
}
|
||||||
|
|
||||||
ServicePointID = int(data.ServicePointID);
|
RelID = int(data.lt_Beacon_Businesses_ServicePointID);
|
||||||
</cfscript>
|
</cfscript>
|
||||||
|
|
||||||
<!--- Confirm the service point exists for this business and has a beacon assigned --->
|
<!--- Confirm the row exists for this BusinessID (and capture what it was) --->
|
||||||
<cfquery name="qFind" datasource="payfrit">
|
<cfquery name="qFind" datasource="payfrit">
|
||||||
SELECT ID, BeaconID
|
SELECT
|
||||||
FROM ServicePoints
|
lt_Beacon_Businesses_ServicePointID,
|
||||||
WHERE ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#ServicePointID#">
|
BeaconID,
|
||||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
ServicePointID
|
||||||
AND BeaconID IS NOT NULL
|
FROM lt_Beacon_Businesses_ServicePoints
|
||||||
|
WHERE lt_Beacon_Businesses_ServicePointID =
|
||||||
|
<cfqueryparam cfsqltype="cf_sql_integer" value="#RelID#">
|
||||||
|
AND BusinessID =
|
||||||
|
<cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
</cfquery>
|
</cfquery>
|
||||||
|
|
||||||
|
|
@ -55,28 +63,28 @@ ServicePointID = int(data.ServicePointID);
|
||||||
<cfoutput>#serializeJSON({
|
<cfoutput>#serializeJSON({
|
||||||
"OK"=false,
|
"OK"=false,
|
||||||
"ERROR"="not_found",
|
"ERROR"="not_found",
|
||||||
"ServicePointID"=ServicePointID,
|
"lt_Beacon_Businesses_ServicePointID"=RelID,
|
||||||
"BusinessID"=(request.BusinessID & "")
|
"BusinessID"=(request.BusinessID & "")
|
||||||
})#</cfoutput>
|
})#</cfoutput>
|
||||||
<cfabort>
|
<cfabort>
|
||||||
</cfif>
|
</cfif>
|
||||||
|
|
||||||
<cfset removedBeaconID = qFind.BeaconID>
|
<!--- Delete it --->
|
||||||
|
|
||||||
<!--- Unassign beacon from service point --->
|
|
||||||
<cfquery datasource="payfrit">
|
<cfquery datasource="payfrit">
|
||||||
UPDATE ServicePoints
|
DELETE FROM lt_Beacon_Businesses_ServicePoints
|
||||||
SET BeaconID = NULL,
|
WHERE lt_Beacon_Businesses_ServicePointID =
|
||||||
AssignedByUserID = NULL
|
<cfqueryparam cfsqltype="cf_sql_integer" value="#RelID#">
|
||||||
WHERE ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#ServicePointID#">
|
AND BusinessID =
|
||||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
<cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||||
|
LIMIT 1
|
||||||
</cfquery>
|
</cfquery>
|
||||||
|
|
||||||
<cfoutput>#serializeJSON({
|
<cfoutput>#serializeJSON({
|
||||||
"OK"=true,
|
"OK"=true,
|
||||||
"ERROR"="",
|
"ERROR"="",
|
||||||
"ACTION"="unassigned",
|
"ACTION"="deleted",
|
||||||
"ServicePointID"=ServicePointID,
|
"lt_Beacon_Businesses_ServicePointID"=RelID,
|
||||||
"BeaconID"=removedBeaconID,
|
"BeaconID"=qFind.BeaconID,
|
||||||
|
"ServicePointID"=qFind.ServicePointID,
|
||||||
"BusinessID"=(request.BusinessID & "")
|
"BusinessID"=(request.BusinessID & "")
|
||||||
})#</cfoutput>
|
})#</cfoutput>
|
||||||
|
|
|
||||||
|
|
@ -17,29 +17,32 @@ if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) ||
|
||||||
|
|
||||||
<cfquery name="q" datasource="payfrit">
|
<cfquery name="q" datasource="payfrit">
|
||||||
SELECT
|
SELECT
|
||||||
sp.ID AS ServicePointID,
|
lt.lt_Beacon_Businesses_ServicePointID,
|
||||||
sp.BeaconID,
|
lt.BeaconID,
|
||||||
sp.BusinessID,
|
lt.BusinessID,
|
||||||
sp.AssignedByUserID,
|
lt.ServicePointID,
|
||||||
b.Name AS BeaconName,
|
lt.lt_Beacon_Businesses_ServicePointNotes,
|
||||||
b.UUID,
|
b.BeaconName,
|
||||||
sp.Name AS ServicePointName
|
b.BeaconUUID,
|
||||||
FROM ServicePoints sp
|
sp.ServicePointName
|
||||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||||
WHERE sp.BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||||
AND sp.BeaconID IS NOT NULL
|
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||||
ORDER BY b.Name, sp.Name
|
WHERE lt.BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||||
|
ORDER BY b.BeaconName, sp.ServicePointName
|
||||||
</cfquery>
|
</cfquery>
|
||||||
|
|
||||||
<cfset assignments = []>
|
<cfset assignments = []>
|
||||||
<cfloop query="q">
|
<cfloop query="q">
|
||||||
<cfset arrayAppend(assignments, {
|
<cfset arrayAppend(assignments, {
|
||||||
"ServicePointID" = q.ServicePointID,
|
"lt_Beacon_Businesses_ServicePointID" = q.lt_Beacon_Businesses_ServicePointID,
|
||||||
"BeaconID" = q.BeaconID,
|
"BeaconID" = q.BeaconID,
|
||||||
"BusinessID" = q.BusinessID,
|
"BusinessID" = q.BusinessID,
|
||||||
|
"ServicePointID" = q.ServicePointID,
|
||||||
"BeaconName" = q.BeaconName,
|
"BeaconName" = q.BeaconName,
|
||||||
"UUID" = q.UUID,
|
"BeaconUUID" = q.BeaconUUID,
|
||||||
"ServicePointName"= q.ServicePointName
|
"ServicePointName"= q.ServicePointName,
|
||||||
|
"lt_Beacon_Businesses_ServicePointNotes" = q.lt_Beacon_Businesses_ServicePointNotes
|
||||||
})>
|
})>
|
||||||
</cfloop>
|
</cfloop>
|
||||||
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue