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>
|
||||
|
||||
<cfquery name="check_user" datasource="#application.datasource#">
|
||||
SELECT FirstName, Balance, ImageExtension
|
||||
SELECT UserFirstName, UserBalance, UserImageExtension
|
||||
FROM Users
|
||||
WHERE ID = #request.UserID#
|
||||
WHERE UserID = #request.UserID#
|
||||
</cfquery>
|
||||
|
||||
</cfif>
|
||||
|
|
@ -320,8 +320,8 @@
|
|||
<cfif find("logout.cfm", request.cgiPath) EQ 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>
|
||||
Hi, <cfif check_user.FirstName gt "">#check_user.FirstName#<br>#dollarformat(check_user.Balance)#<cfelse>Payfrit User</cfif><br>
|
||||
<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.UserFirstName gt "">#check_user.UserFirstName#<br>#dollarformat(check_user.UserBalance)#<cfelse>Payfrit User</cfif><br>
|
||||
<cfelse>
|
||||
|
||||
<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>
|
||||
|
||||
<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
|
||||
WHERE A.UserID = D.UserID
|
||||
AND
|
||||
A.ItemID = C.ItemID
|
||||
AND
|
||||
B.ID = C.BusinessID
|
||||
B.BusinessID = C.BusinessID
|
||||
AND
|
||||
C.BusinessID = #form.bizid#
|
||||
AND
|
||||
|
|
@ -170,11 +170,11 @@
|
|||
</CFQUERY>
|
||||
|
||||
<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
|
||||
WHERE O.BusinessID = M.BusinessID
|
||||
AND
|
||||
M.UserID = U.ID
|
||||
M.UserID = U.UserID
|
||||
ORDER BY O.AddedOn DESC
|
||||
</CFQUERY>
|
||||
|
||||
|
|
@ -185,7 +185,7 @@
|
|||
)
|
||||
VALUES
|
||||
(
|
||||
#get_last_inserted.ID#,
|
||||
#get_last_inserted.OrderID#,
|
||||
#get_queued_food.CartID#
|
||||
)
|
||||
</CFQUERY>
|
||||
|
|
@ -268,7 +268,7 @@
|
|||
<CFQUERY name="get_user_104_balance" datasource="#application.datasource#" dbtype="ODBC">
|
||||
SELECT balance
|
||||
FROM Users
|
||||
WHERE ID = 104
|
||||
WHERE UserID = 104
|
||||
</CFQUERY>
|
||||
|
||||
<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">
|
||||
SELECT balance
|
||||
FROM Users
|
||||
WHERE ID = 104
|
||||
WHERE UserID = 104
|
||||
</CFQUERY>
|
||||
|
||||
<CFQUERY name="transfer_fees_to_UserID_104" datasource="#application.datasource#" dbtype="ODBC">
|
||||
|
|
|
|||
|
|
@ -164,8 +164,8 @@ async function refreshAssignments(){
|
|||
const tr = document.createElement("tr");
|
||||
tr.innerHTML = `
|
||||
<td>${a.lt_Beacon_Businesses_ServicePointID}</td>
|
||||
<td>${escapeHtml((a.Name || "") + " (ID " + a.BeaconID + ")")}</td>
|
||||
<td>${escapeHtml((a.Name || "") + " (ID " + a.ServicePointID + ")")}</td>
|
||||
<td>${escapeHtml((a.BeaconName || "") + " (ID " + a.BeaconID + ")")}</td>
|
||||
<td>${escapeHtml((a.ServicePointName || "") + " (ID " + a.ServicePointID + ")")}</td>
|
||||
<td>${escapeHtml(a.lt_Beacon_Businesses_ServicePointNotes || "")}</td>
|
||||
<td>${escapeHtml(a.CreatedAt || "")}</td>
|
||||
`;
|
||||
|
|
@ -183,12 +183,12 @@ async function refreshBeacons(assignedBeaconIDs, keepSelectedBeaconID){
|
|||
setSelectPlaceholder(sel, "-- Select Beacon --");
|
||||
|
||||
(out.BEACONS || []).forEach(b => {
|
||||
const isAssigned = assignedBeaconIDs.has(String(b.ID));
|
||||
const isAssigned = assignedBeaconIDs.has(String(b.BeaconID));
|
||||
if (HIDE_ASSIGNED_BEACONS && isAssigned) return;
|
||||
|
||||
const opt = document.createElement("option");
|
||||
opt.value = b.ID;
|
||||
opt.textContent = String(b.ID) + " - " + (b.Name || "");
|
||||
opt.value = b.BeaconID;
|
||||
opt.textContent = String(b.BeaconID) + " - " + (b.BeaconName || "");
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
|
||||
|
|
@ -203,12 +203,12 @@ async function refreshServicePoints(assignedServicePointIDs, keepSelectedService
|
|||
setSelectPlaceholder(sel, "-- Select ServicePoint --");
|
||||
|
||||
(out.SERVICEPOINTS || []).forEach(sp => {
|
||||
const isAssigned = assignedServicePointIDs.has(String(sp.ID));
|
||||
const isAssigned = assignedServicePointIDs.has(String(sp.ServicePointID));
|
||||
if (HIDE_ASSIGNED_SERVICEPOINTS && isAssigned) return;
|
||||
|
||||
const opt = document.createElement("option");
|
||||
opt.value = sp.ID;
|
||||
opt.textContent = String(sp.ID) + " - " + (sp.Name || "");
|
||||
opt.value = sp.ServicePointID;
|
||||
opt.textContent = String(sp.ServicePointID) + " - " + (sp.ServicePointName || "");
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<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="row">
|
||||
|
|
@ -38,8 +38,8 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label>Name (required)</label><br>
|
||||
<input id="Name" placeholder="Front Door" required>
|
||||
<label>BeaconName (required)</label><br>
|
||||
<input id="BeaconName" placeholder="Front Door" required>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -160,13 +160,13 @@ function escapeHtml(s){
|
|||
}
|
||||
|
||||
function loadIntoForm(b){
|
||||
document.getElementById("BeaconID").value = b.ID || "";
|
||||
document.getElementById("Name").value = b.Name || "";
|
||||
document.getElementById("BeaconID").value = b.BeaconID || "";
|
||||
document.getElementById("BeaconName").value = b.BeaconName || "";
|
||||
document.getElementById("UUID").value = b.UUID || "";
|
||||
document.getElementById("NamespaceId").value = b.NamespaceId || "";
|
||||
document.getElementById("InstanceId").value = b.InstanceId || "";
|
||||
document.getElementById("IsActive").value = ("" + (b.IsActive ?? 1));
|
||||
document.getElementById("DelBeaconID").value = b.ID || "";
|
||||
document.getElementById("DelBeaconID").value = b.BeaconID || "";
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
|
|
@ -180,8 +180,8 @@ async function refresh() {
|
|||
for (const b of items) {
|
||||
const tr = document.createElement("tr");
|
||||
tr.innerHTML = `
|
||||
<td>${b.ID}</td>
|
||||
<td>${escapeHtml(b.Name||"")}</td>
|
||||
<td>${b.BeaconID}</td>
|
||||
<td>${escapeHtml(b.BeaconName||"")}</td>
|
||||
<td>${escapeHtml(b.UUID||"")}</td>
|
||||
<td>${escapeHtml(b.NamespaceId||"")}</td>
|
||||
<td>${escapeHtml(b.InstanceId||"")}</td>
|
||||
|
|
@ -194,15 +194,15 @@ async function refresh() {
|
|||
}
|
||||
|
||||
async function saveBeacon() {
|
||||
const name = (document.getElementById("Name").value || "").trim();
|
||||
const name = (document.getElementById("BeaconName").value || "").trim();
|
||||
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;
|
||||
}
|
||||
|
||||
const body = {
|
||||
BeaconID: valIntOrNull("BeaconID"),
|
||||
Name: name,
|
||||
BeaconName: name,
|
||||
UUID: (document.getElementById("UUID").value || "").trim(),
|
||||
NamespaceId: (document.getElementById("NamespaceId").value || "").trim(),
|
||||
InstanceId: (document.getElementById("InstanceId").value || "").trim(),
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@
|
|||
<cfparam name="users_to_email" default="">
|
||||
|
||||
<cfquery name="select_users_to_email" datasource="#application.datasource#">
|
||||
SELECT U.EmailAddress
|
||||
SELECT U.UserEmailAddress
|
||||
FROM Users U
|
||||
WHERE UserID in (0,1,2)
|
||||
</cfquery>
|
||||
|
||||
<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>
|
||||
|
||||
|
|
@ -95,18 +95,18 @@
|
|||
<cfloop index="the_email_address" list="#users_to_email#">
|
||||
|
||||
<cfquery name="get_user_email" datasource="#application.datasource#">
|
||||
SELECT UUID
|
||||
SELECT UserUUID
|
||||
FROM Users
|
||||
WHERE EmailAddress = '#the_email_address#'
|
||||
WHERE UserEmailAddress = '#the_email_address#'
|
||||
AND
|
||||
UserIsEmailverified = 1
|
||||
AND
|
||||
IsContactVerified > 0
|
||||
UserIsContactVerified > 0
|
||||
</cfquery>
|
||||
|
||||
<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">
|
||||
#HTMLCodeFormat(form.this_email_body)#</cfmail>
|
||||
|
|
|
|||
|
|
@ -5,14 +5,14 @@
|
|||
<cfif form.mode eq "start">
|
||||
|
||||
<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
|
||||
WHERE U.IsEmailVerified = 1
|
||||
WHERE U.UserIsEmailVerified = 1
|
||||
AND
|
||||
U.UserIsCOntactVerified > 0
|
||||
AND
|
||||
U.ID > 435
|
||||
ORDER BY U.ID DESC
|
||||
U.UserID > 435
|
||||
ORDER BY U.UserID DESC
|
||||
</cfquery>
|
||||
|
||||
|
||||
|
|
@ -48,16 +48,16 @@
|
|||
</form>
|
||||
|
||||
</td>
|
||||
<td>#EmailAddress#</td>
|
||||
<td>#ContactNumber#</td>
|
||||
<td>#dateformat(AddedOn, "mmmm dd, YYYY")# at #timeformat(AddedOn, "hh:nn tt")#</td>
|
||||
<td>#UserEmailAddress#</td>
|
||||
<td>#UserContactNumber#</td>
|
||||
<td>#dateformat(UserAddedOn, "mmmm dd, YYYY")# at #timeformat(UserAddedOn, "hh:nn tt")#</td>
|
||||
<td>
|
||||
|
||||
<CFQUERY name="get_orders" datasource="#application.datasource#">
|
||||
SELECT O.UUID
|
||||
SELECT O.OrderUUID
|
||||
FROM Orders O
|
||||
WHERE O.UserID = #get_verified_users.ID#
|
||||
ORDER BY O.ID DESC
|
||||
WHERE O.OrderUserID = #get_verified_users.UserID#
|
||||
ORDER BY O.OrderID DESC
|
||||
</cfquery>
|
||||
|
||||
<cfparam name="looper" default="">
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
<cfloop query="get_orders">
|
||||
<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>
|
||||
|
||||
</td>
|
||||
|
|
@ -79,10 +79,10 @@
|
|||
<cfelseif form.mode eq "user_traffic">
|
||||
|
||||
<CFQUERY name="get_user_traffic" datasource="#application.datasource#">
|
||||
SELECT V.PageMode, V.AddedOn
|
||||
FROM VisitorTrackings V
|
||||
WHERE V.UserID = #form.chip#
|
||||
ORDER BY V.AddedOn DESC
|
||||
SELECT V.VisitorTrackingPageMode, V.VisitorTrackingAddedOn
|
||||
FROM VisitorTracking V
|
||||
WHERE V.VisitorTrackingUserID = #form.chip#
|
||||
ORDER BY V.VisitorTrackingAddedOn DESC
|
||||
</cfquery>
|
||||
|
||||
<table>
|
||||
|
|
@ -92,8 +92,8 @@
|
|||
</tr>
|
||||
<cfoutput query="get_user_traffic">
|
||||
<tr>
|
||||
<td>#PageMode#</td>
|
||||
<td>#AddedOn#</td>
|
||||
<td>#VisitorTrackingPageMode#</td>
|
||||
<td>#VisitorTrackingAddedOn#</td>
|
||||
</tr>
|
||||
</cfoutput>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<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="row">
|
||||
|
|
@ -38,18 +38,18 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label>Name (required)</label><br>
|
||||
<input id="Name" placeholder="Front Counter" required>
|
||||
<label>ServicePointName (required)</label><br>
|
||||
<input id="ServicePointName" placeholder="Front Counter" required>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>TypeID</label><br>
|
||||
<input id="TypeID" placeholder="0">
|
||||
<label>ServicePointTypeID</label><br>
|
||||
<input id="ServicePointTypeID" placeholder="0">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>Code</label><br>
|
||||
<input id="Code" placeholder="COUNTER">
|
||||
<label>ServicePointCode</label><br>
|
||||
<input id="ServicePointCode" placeholder="COUNTER">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
@ -160,14 +160,14 @@ function escapeHtml(s){
|
|||
}
|
||||
|
||||
function loadIntoForm(sp){
|
||||
document.getElementById("ServicePointID").value = sp.ID || "";
|
||||
document.getElementById("Name").value = sp.Name || "";
|
||||
document.getElementById("TypeID").value = (sp.TypeID ?? 0);
|
||||
document.getElementById("Code").value = sp.Code || "";
|
||||
document.getElementById("ServicePointID").value = sp.ServicePointID || "";
|
||||
document.getElementById("ServicePointName").value = sp.ServicePointName || "";
|
||||
document.getElementById("ServicePointTypeID").value = (sp.ServicePointTypeID ?? 0);
|
||||
document.getElementById("ServicePointCode").value = sp.ServicePointCode || "";
|
||||
document.getElementById("Description").value = sp.Description || "";
|
||||
document.getElementById("SortOrder").value = (sp.SortOrder ?? 0);
|
||||
document.getElementById("IsActive").value = ("" + (sp.IsActive ?? 1));
|
||||
document.getElementById("DelServicePointID").value = sp.ID || "";
|
||||
document.getElementById("DelServicePointID").value = sp.ServicePointID || "";
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
|
|
@ -181,10 +181,10 @@ async function refresh() {
|
|||
for (const sp of items) {
|
||||
const tr = document.createElement("tr");
|
||||
tr.innerHTML = `
|
||||
<td>${sp.ID}</td>
|
||||
<td>${escapeHtml(sp.Name||"")}</td>
|
||||
<td>${sp.TypeID}</td>
|
||||
<td>${escapeHtml(sp.Code||"")}</td>
|
||||
<td>${sp.ServicePointID}</td>
|
||||
<td>${escapeHtml(sp.ServicePointName||"")}</td>
|
||||
<td>${sp.ServicePointTypeID}</td>
|
||||
<td>${escapeHtml(sp.ServicePointCode||"")}</td>
|
||||
<td>${sp.SortOrder}</td>
|
||||
<td>${sp.IsActive}</td>
|
||||
`;
|
||||
|
|
@ -195,17 +195,17 @@ async function refresh() {
|
|||
}
|
||||
|
||||
async function saveSP() {
|
||||
const name = (document.getElementById("Name").value || "").trim();
|
||||
const name = (document.getElementById("ServicePointName").value || "").trim();
|
||||
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;
|
||||
}
|
||||
|
||||
const body = {
|
||||
ServicePointID: valIntOrNull("ServicePointID"),
|
||||
Name: name,
|
||||
TypeID: valIntOrZero("TypeID"),
|
||||
Code: (document.getElementById("Code").value || "").trim(),
|
||||
ServicePointName: name,
|
||||
ServicePointTypeID: valIntOrZero("ServicePointTypeID"),
|
||||
ServicePointCode: (document.getElementById("ServicePointCode").value || "").trim(),
|
||||
Description: (document.getElementById("Description").value || "").trim(),
|
||||
SortOrder: valIntOrZero("SortOrder"),
|
||||
IsActive: parseInt(document.getElementById("IsActive").value, 10)
|
||||
|
|
|
|||
|
|
@ -173,11 +173,6 @@ if (len(request._api_path)) {
|
|||
|
||||
// Worker app endpoints
|
||||
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
|
||||
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/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/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/listCategories.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/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
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -38,11 +38,9 @@ try {
|
|||
|
||||
// Optional fields
|
||||
line2 = trim(data.Line2 ?: "");
|
||||
label = trim(data.Label ?: "");
|
||||
setAsDefault = (data.SetAsDefault ?: false) == true;
|
||||
|
||||
// Hardcoded to delivery address type
|
||||
typeId = 2;
|
||||
|
||||
// Validation
|
||||
if (len(line1) == 0 || len(city) == 0 || stateId <= 0 || len(zipCode) == 0) {
|
||||
writeOutput(serializeJSON({
|
||||
|
|
@ -53,17 +51,16 @@ try {
|
|||
abort;
|
||||
}
|
||||
|
||||
// If setting as default, clear other defaults first (for same type)
|
||||
// If setting as default, clear other defaults first
|
||||
if (setAsDefault) {
|
||||
queryExecute("
|
||||
UPDATE Addresses
|
||||
SET AddressIsDefaultDelivery = 0
|
||||
WHERE UserID = :userId
|
||||
AND (BusinessID = 0 OR BusinessID IS NULL)
|
||||
AND AddressTypeID = :typeId
|
||||
WHERE AddressUserID = :userId
|
||||
AND (AddressBusinessID = 0 OR AddressBusinessID IS NULL)
|
||||
AND AddressTypeID LIKE '%2%'
|
||||
", {
|
||||
userId: { value: userId, cfsqltype: "cf_sql_integer" },
|
||||
typeId: { value: typeId, cfsqltype: "cf_sql_integer" }
|
||||
userId: { value: userId, cfsqltype: "cf_sql_integer" }
|
||||
}, { datasource: "payfrit" });
|
||||
}
|
||||
|
||||
|
|
@ -75,23 +72,23 @@ try {
|
|||
queryExecute("
|
||||
INSERT INTO Addresses (
|
||||
AddressID,
|
||||
UserID,
|
||||
BusinessID,
|
||||
AddressUserID,
|
||||
AddressBusinessID,
|
||||
AddressTypeID,
|
||||
AddressLabel,
|
||||
AddressIsDefaultDelivery,
|
||||
Line1,
|
||||
Line2,
|
||||
City,
|
||||
StateID,
|
||||
ZIPCode,
|
||||
IsDeleted,
|
||||
AddedOn
|
||||
AddressLine1,
|
||||
AddressLine2,
|
||||
AddressCity,
|
||||
AddressStateID,
|
||||
AddressZIPCode,
|
||||
AddressIsDeleted,
|
||||
AddressAddedOn
|
||||
) VALUES (
|
||||
:addressId,
|
||||
:userId,
|
||||
0,
|
||||
:typeId,
|
||||
'2',
|
||||
:label,
|
||||
:isDefault,
|
||||
:line1,
|
||||
|
|
@ -105,7 +102,6 @@ try {
|
|||
", {
|
||||
addressId: { value: newAddressId, 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" },
|
||||
isDefault: { value: setAsDefault ? 1 : 0, cfsqltype: "cf_sql_integer" },
|
||||
line1: { value: line1, cfsqltype: "cf_sql_varchar" },
|
||||
|
|
@ -117,7 +113,7 @@ try {
|
|||
}, { datasource: "payfrit" });
|
||||
|
||||
// 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" }
|
||||
}, { datasource: "payfrit" });
|
||||
|
||||
|
|
@ -128,7 +124,6 @@ try {
|
|||
"OK": true,
|
||||
"ADDRESS": {
|
||||
"AddressID": newAddressId,
|
||||
"TypeID": typeId,
|
||||
"Label": len(label) ? label : "Address",
|
||||
"IsDefault": setAsDefault,
|
||||
"Line1": line1,
|
||||
|
|
|
|||
|
|
@ -76,11 +76,11 @@ if (addressId <= 0) {
|
|||
try {
|
||||
// First, get the address details so we can find all matching duplicates
|
||||
qAddr = queryExecute("
|
||||
SELECT Line1, Line2, City, StateID, ZIPCode
|
||||
SELECT AddressLine1, AddressLine2, AddressCity, AddressStateID, AddressZIPCode
|
||||
FROM Addresses
|
||||
WHERE ID = :addressId
|
||||
AND UserID = :userId
|
||||
AND IsDeleted = 0
|
||||
WHERE AddressID = :addressId
|
||||
AND AddressUserID = :userId
|
||||
AND AddressIsDeleted = 0
|
||||
", {
|
||||
addressId: { value = addressId, 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
|
||||
qDelete = queryExecute("
|
||||
UPDATE Addresses
|
||||
SET IsDeleted = 1
|
||||
WHERE UserID = :userId
|
||||
AND Line1 = :line1
|
||||
AND Line2 = :line2
|
||||
AND City = :city
|
||||
AND StateID = :stateId
|
||||
AND ZIPCode = :zip
|
||||
AND IsDeleted = 0
|
||||
SET AddressIsDeleted = 1
|
||||
WHERE AddressUserID = :userId
|
||||
AND AddressLine1 = :line1
|
||||
AND AddressLine2 = :line2
|
||||
AND AddressCity = :city
|
||||
AND AddressStateID = :stateId
|
||||
AND AddressZIPCode = :zip
|
||||
AND AddressIsDeleted = 0
|
||||
", {
|
||||
userId: { value = userId, cfsqltype = "cf_sql_integer" },
|
||||
line1: { value = qAddr.Line1, cfsqltype = "cf_sql_varchar", null = !len(qAddr.Line1) },
|
||||
line2: { value = qAddr.Line2, cfsqltype = "cf_sql_varchar", null = !len(qAddr.Line2) },
|
||||
city: { value = qAddr.City, cfsqltype = "cf_sql_varchar", null = !len(qAddr.City) },
|
||||
stateId: { value = qAddr.StateID, cfsqltype = "cf_sql_integer" },
|
||||
zip: { value = qAddr.ZIPCode, cfsqltype = "cf_sql_varchar", null = !len(qAddr.ZIPCode) }
|
||||
line1: { value = qAddr.AddressLine1, cfsqltype = "cf_sql_varchar", null = !len(qAddr.AddressLine1) },
|
||||
line2: { value = qAddr.AddressLine2, cfsqltype = "cf_sql_varchar", null = !len(qAddr.AddressLine2) },
|
||||
city: { value = qAddr.AddressCity, cfsqltype = "cf_sql_varchar", null = !len(qAddr.AddressCity) },
|
||||
stateId: { value = qAddr.AddressStateID, cfsqltype = "cf_sql_integer" },
|
||||
zip: { value = qAddr.AddressZIPCode, cfsqltype = "cf_sql_varchar", null = !len(qAddr.AddressZIPCode) }
|
||||
});
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
|
|
|
|||
|
|
@ -46,25 +46,26 @@ if (userId <= 0) {
|
|||
}
|
||||
|
||||
try {
|
||||
// Get user's delivery addresses
|
||||
// Get user's delivery addresses with GROUP BY to show unique addresses only
|
||||
qAddresses = queryExecute("
|
||||
SELECT
|
||||
a.ID,
|
||||
a.IsDefaultDelivery,
|
||||
a.Line1,
|
||||
a.Line2,
|
||||
a.City,
|
||||
a.StateID,
|
||||
s.Abbreviation as StateAbbreviation,
|
||||
s.Name as StateName,
|
||||
a.ZIPCode
|
||||
MIN(a.AddressID) as AddressID,
|
||||
MAX(a.AddressLabel) as AddressLabel,
|
||||
MAX(a.AddressIsDefaultDelivery) as AddressIsDefaultDelivery,
|
||||
a.AddressLine1,
|
||||
a.AddressLine2,
|
||||
a.AddressCity,
|
||||
a.AddressStateID,
|
||||
MAX(s.tt_StateAbbreviation) as StateAbbreviation,
|
||||
MAX(s.tt_StateName) as StateName,
|
||||
a.AddressZIPCode
|
||||
FROM Addresses a
|
||||
LEFT JOIN tt_States s ON a.StateID = s.ID
|
||||
WHERE a.UserID = :userId
|
||||
AND (a.BusinessID = 0 OR a.BusinessID IS NULL)
|
||||
AND a.AddressTypeID = 2
|
||||
AND a.IsDeleted = 0
|
||||
ORDER BY a.IsDefaultDelivery DESC, a.ID DESC
|
||||
LEFT JOIN tt_States s ON a.AddressStateID = s.tt_StateID
|
||||
WHERE a.AddressUserID = :userId
|
||||
AND a.AddressTypeID LIKE '%2%'
|
||||
AND a.AddressIsDeleted = 0
|
||||
GROUP BY a.AddressLine1, a.AddressLine2, a.AddressCity, a.AddressStateID, a.AddressZIPCode
|
||||
ORDER BY MAX(a.AddressIsDefaultDelivery) DESC, MIN(a.AddressID) DESC
|
||||
", {
|
||||
userId: { value = userId, cfsqltype = "cf_sql_integer" }
|
||||
});
|
||||
|
|
@ -72,15 +73,17 @@ try {
|
|||
addresses = [];
|
||||
for (row in qAddresses) {
|
||||
arrayAppend(addresses, {
|
||||
"AddressID": row.ID,
|
||||
"IsDefault": row.IsDefaultDelivery == 1,
|
||||
"Line1": row.Line1,
|
||||
"Line2": row.Line2 ?: "",
|
||||
"City": row.City,
|
||||
"StateID": row.StateID,
|
||||
"AddressID": row.AddressID,
|
||||
"Label": len(row.AddressLabel) ? row.AddressLabel : "Address",
|
||||
"IsDefault": row.AddressIsDefaultDelivery == 1,
|
||||
"Line1": row.AddressLine1,
|
||||
"Line2": row.AddressLine2 ?: "",
|
||||
"City": row.AddressCity,
|
||||
"StateID": row.AddressStateID,
|
||||
"StateAbbr": row.StateAbbreviation ?: "",
|
||||
"ZIPCode": row.ZIPCode,
|
||||
"DisplayText": row.Line1 & (len(row.Line2) ? ", " & row.Line2 : "") & ", " & row.City & ", " & (row.StateAbbreviation ?: "") & " " & row.ZIPCode
|
||||
"StateName": row.StateName ?: "",
|
||||
"ZIPCode": row.AddressZIPCode,
|
||||
"DisplayText": row.AddressLine1 & (len(row.AddressLine2) ? ", " & row.AddressLine2 : "") & ", " & row.AddressCity & ", " & (row.StateAbbreviation ?: "") & " " & row.AddressZIPCode
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +96,8 @@ try {
|
|||
apiAbort({
|
||||
"OK": false,
|
||||
"ERROR": "server_error",
|
||||
"MESSAGE": e.message
|
||||
"MESSAGE": e.message,
|
||||
"LINE": e.tagContext[1].line ?: 0
|
||||
});
|
||||
}
|
||||
</cfscript>
|
||||
|
|
|
|||
|
|
@ -41,11 +41,11 @@ try {
|
|||
|
||||
// Verify address belongs to user
|
||||
qCheck = queryExecute("
|
||||
SELECT ID
|
||||
SELECT AddressID
|
||||
FROM Addresses
|
||||
WHERE ID = :addressId
|
||||
AND UserID = :userId
|
||||
AND IsDeleted = 0
|
||||
WHERE AddressID = :addressId
|
||||
AND AddressUserID = :userId
|
||||
AND AddressIsDeleted = 0
|
||||
", {
|
||||
addressId: { value: addressId, cfsqltype: "cf_sql_integer" },
|
||||
userId: { value: userId, cfsqltype: "cf_sql_integer" }
|
||||
|
|
@ -64,8 +64,8 @@ try {
|
|||
queryExecute("
|
||||
UPDATE Addresses
|
||||
SET AddressIsDefaultDelivery = 0
|
||||
WHERE UserID = :userId
|
||||
AND (BusinessID = 0 OR BusinessID IS NULL)
|
||||
WHERE AddressUserID = :userId
|
||||
AND (AddressBusinessID = 0 OR AddressBusinessID IS NULL)
|
||||
AND AddressTypeID LIKE '%2%'
|
||||
", {
|
||||
userId: { value: userId, cfsqltype: "cf_sql_integer" }
|
||||
|
|
@ -75,7 +75,7 @@ try {
|
|||
queryExecute("
|
||||
UPDATE Addresses
|
||||
SET AddressIsDefaultDelivery = 1
|
||||
WHERE ID = :addressId
|
||||
WHERE AddressID = :addressId
|
||||
", {
|
||||
addressId: { value: addressId, cfsqltype: "cf_sql_integer" }
|
||||
}, { datasource: "payfrit" });
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
<cfscript>
|
||||
try {
|
||||
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
|
||||
ORDER BY Name
|
||||
ORDER BY tt_StateName
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
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
|
||||
*
|
||||
* Adds time-based scheduling fields:
|
||||
* - ScheduleStart: TIME - Start time when category is available (e.g., 06:00:00 for breakfast)
|
||||
* - ScheduleEnd: TIME - End time when category stops being available (e.g., 11:00:00)
|
||||
* - ScheduleDays: VARCHAR(20) - Comma-separated list of day IDs (1=Sun, 2=Mon, etc.) or NULL for all days
|
||||
* - CategoryScheduleStart: TIME - Start time when category is available (e.g., 06:00:00 for breakfast)
|
||||
* - CategoryScheduleEnd: TIME - End time when category stops being available (e.g., 11:00:00)
|
||||
* - CategoryScheduleDays: VARCHAR(20) - Comma-separated list of day IDs (1=Sun, 2=Mon, etc.) or NULL for all days
|
||||
*
|
||||
* Run this once to migrate the schema.
|
||||
*/
|
||||
|
|
@ -24,38 +24,38 @@ try {
|
|||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'payfrit'
|
||||
AND TABLE_NAME = 'Categories'
|
||||
AND COLUMN_NAME IN ('ScheduleStart', 'ScheduleEnd', 'ScheduleDays')
|
||||
AND COLUMN_NAME IN ('CategoryScheduleStart', 'CategoryScheduleEnd', 'CategoryScheduleDays')
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
existingCols = valueList(qCheck.COLUMN_NAME);
|
||||
|
||||
added = [];
|
||||
|
||||
// Add ScheduleStart if not exists
|
||||
if (!listFindNoCase(existingCols, "ScheduleStart")) {
|
||||
// Add CategoryScheduleStart if not exists
|
||||
if (!listFindNoCase(existingCols, "CategoryScheduleStart")) {
|
||||
queryExecute("
|
||||
ALTER TABLE Categories
|
||||
ADD COLUMN ScheduleStart TIME NULL
|
||||
ADD COLUMN CategoryScheduleStart TIME NULL
|
||||
", {}, { datasource: "payfrit" });
|
||||
arrayAppend(added, "ScheduleStart");
|
||||
arrayAppend(added, "CategoryScheduleStart");
|
||||
}
|
||||
|
||||
// Add ScheduleEnd if not exists
|
||||
if (!listFindNoCase(existingCols, "ScheduleEnd")) {
|
||||
// Add CategoryScheduleEnd if not exists
|
||||
if (!listFindNoCase(existingCols, "CategoryScheduleEnd")) {
|
||||
queryExecute("
|
||||
ALTER TABLE Categories
|
||||
ADD COLUMN ScheduleEnd TIME NULL
|
||||
ADD COLUMN CategoryScheduleEnd TIME NULL
|
||||
", {}, { datasource: "payfrit" });
|
||||
arrayAppend(added, "ScheduleEnd");
|
||||
arrayAppend(added, "CategoryScheduleEnd");
|
||||
}
|
||||
|
||||
// Add ScheduleDays if not exists
|
||||
if (!listFindNoCase(existingCols, "ScheduleDays")) {
|
||||
// Add CategoryScheduleDays if not exists
|
||||
if (!listFindNoCase(existingCols, "CategoryScheduleDays")) {
|
||||
queryExecute("
|
||||
ALTER TABLE Categories
|
||||
ADD COLUMN ScheduleDays VARCHAR(20) NULL
|
||||
ADD COLUMN CategoryScheduleDays VARCHAR(20) NULL
|
||||
", {}, { datasource: "payfrit" });
|
||||
arrayAppend(added, "ScheduleDays");
|
||||
arrayAppend(added, "CategoryScheduleDays");
|
||||
}
|
||||
|
||||
response["OK"] = true;
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ try {
|
|||
|
||||
// Find the Fountain Soda item we created
|
||||
qFountain = queryExecute("
|
||||
SELECT ID, Name FROM Items
|
||||
WHERE BusinessID = :bizId AND Name = 'Fountain Soda'
|
||||
SELECT ItemID, ItemName FROM Items
|
||||
WHERE ItemBusinessID = :bizId AND ItemName = 'Fountain Soda'
|
||||
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
||||
|
||||
if (qFountain.recordCount == 0) {
|
||||
|
|
@ -31,13 +31,13 @@ try {
|
|||
// Update Fountain Soda to require child selection and be collapsible
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET RequiresChildSelection = 1, IsCollapsible = 1
|
||||
SET ItemRequiresChildSelection = 1, ItemIsCollapsible = 1
|
||||
WHERE ItemID = :itemId
|
||||
", { itemId: fountainId }, { datasource: "payfrit" });
|
||||
|
||||
// Check if modifiers already exist
|
||||
qExisting = queryExecute("
|
||||
SELECT COUNT(*) as cnt FROM Items WHERE ParentItemID = :parentId
|
||||
SELECT COUNT(*) as cnt FROM Items WHERE ItemParentItemID = :parentId
|
||||
", { parentId: fountainId }, { datasource: "payfrit" });
|
||||
|
||||
if (qExisting.cnt > 0) {
|
||||
|
|
@ -53,10 +53,10 @@ try {
|
|||
|
||||
queryExecute("
|
||||
INSERT INTO Items (
|
||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
||||
Name, Description, Price, IsActive,
|
||||
SortOrder, IsCollapsible, RequiresChildSelection,
|
||||
MaxNumSelectionReq, AddedOn
|
||||
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||
ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection,
|
||||
ItemMaxNumSelectionReq, ItemAddedOn
|
||||
) VALUES (
|
||||
:itemId, :bizId, 0, :parentId,
|
||||
'Size', 'Choose your size', 0, 1,
|
||||
|
|
@ -80,10 +80,10 @@ try {
|
|||
qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
||||
queryExecute("
|
||||
INSERT INTO Items (
|
||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
||||
Name, Description, Price, IsActive,
|
||||
SortOrder, IsCollapsible, IsCheckedByDefault,
|
||||
AddedOn
|
||||
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||
ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault,
|
||||
ItemAddedOn
|
||||
) VALUES (
|
||||
:itemId, :bizId, 0, :parentId,
|
||||
:name, '', :price, 1,
|
||||
|
|
@ -108,10 +108,10 @@ try {
|
|||
|
||||
queryExecute("
|
||||
INSERT INTO Items (
|
||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
||||
Name, Description, Price, IsActive,
|
||||
SortOrder, IsCollapsible, RequiresChildSelection,
|
||||
MaxNumSelectionReq, AddedOn
|
||||
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||
ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection,
|
||||
ItemMaxNumSelectionReq, ItemAddedOn
|
||||
) VALUES (
|
||||
:itemId, :bizId, 0, :parentId,
|
||||
'Flavor', 'Choose your drink', 0, 1,
|
||||
|
|
@ -139,10 +139,10 @@ try {
|
|||
qMaxItem = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
||||
queryExecute("
|
||||
INSERT INTO Items (
|
||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
||||
Name, Description, Price, IsActive,
|
||||
SortOrder, IsCollapsible, IsCheckedByDefault,
|
||||
AddedOn
|
||||
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||
ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault,
|
||||
ItemAddedOn
|
||||
) VALUES (
|
||||
:itemId, :bizId, 0, :parentId,
|
||||
:name, '', 0, 1,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
<cfscript>
|
||||
/**
|
||||
* Add CategoryID column to Items table
|
||||
* Add ItemCategoryID column to Items table
|
||||
*/
|
||||
|
||||
response = { "OK": false };
|
||||
|
|
@ -17,30 +17,30 @@ try {
|
|||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'payfrit'
|
||||
AND TABLE_NAME = 'Items'
|
||||
AND COLUMN_NAME = 'CategoryID'
|
||||
AND COLUMN_NAME = 'ItemCategoryID'
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
if (qCheck.recordCount > 0) {
|
||||
response["OK"] = true;
|
||||
response["MESSAGE"] = "CategoryID column already exists";
|
||||
response["MESSAGE"] = "ItemCategoryID column already exists";
|
||||
} else {
|
||||
// Add the column
|
||||
queryExecute("
|
||||
ALTER TABLE Items
|
||||
ADD COLUMN CategoryID INT NULL DEFAULT 0 AFTER ParentItemID
|
||||
ADD COLUMN ItemCategoryID INT NULL DEFAULT 0 AFTER ItemParentItemID
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
// Add index for performance
|
||||
try {
|
||||
queryExecute("
|
||||
CREATE INDEX idx_items_categoryid ON Items(CategoryID)
|
||||
CREATE INDEX idx_items_categoryid ON Items(ItemCategoryID)
|
||||
", {}, { datasource: "payfrit" });
|
||||
} catch (any indexErr) {
|
||||
// Index might already exist
|
||||
}
|
||||
|
||||
response["OK"] = true;
|
||||
response["MESSAGE"] = "CategoryID column added successfully";
|
||||
response["MESSAGE"] = "ItemCategoryID column added successfully";
|
||||
}
|
||||
|
||||
} catch (any e) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
try {
|
||||
// Check if columns already exist
|
||||
checkCols = queryExecute(
|
||||
"SHOW COLUMNS FROM Addresses LIKE 'Latitude'",
|
||||
"SHOW COLUMNS FROM Addresses LIKE 'AddressLat'",
|
||||
[],
|
||||
{ datasource = "payfrit" }
|
||||
);
|
||||
|
|
@ -15,8 +15,8 @@ try {
|
|||
// Add the columns
|
||||
queryExecute(
|
||||
"ALTER TABLE Addresses
|
||||
ADD COLUMN Latitude DECIMAL(10,7) NULL,
|
||||
ADD COLUMN Longitude DECIMAL(10,7) NULL",
|
||||
ADD COLUMN AddressLat DECIMAL(10,7) NULL,
|
||||
ADD COLUMN AddressLng DECIMAL(10,7) NULL",
|
||||
[],
|
||||
{ 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">
|
||||
|
||||
<cfscript>
|
||||
// Add SourceType and SourceID columns to Tasks table
|
||||
// Add TaskSourceType and TaskSourceID columns to Tasks table
|
||||
// These are needed for chat persistence feature
|
||||
|
||||
result = { "OK": true, "STEPS": [] };
|
||||
|
|
@ -15,30 +15,30 @@ try {
|
|||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'payfrit'
|
||||
AND TABLE_NAME = 'Tasks'
|
||||
AND COLUMN_NAME IN ('SourceType', 'SourceID')
|
||||
AND COLUMN_NAME IN ('TaskSourceType', 'TaskSourceID')
|
||||
", [], { datasource: "payfrit" });
|
||||
|
||||
existingCols = valueList(cols.COLUMN_NAME);
|
||||
arrayAppend(result.STEPS, "Existing columns: #existingCols#");
|
||||
|
||||
// Add SourceType if missing
|
||||
if (!listFindNoCase(existingCols, "SourceType")) {
|
||||
// Add TaskSourceType if missing
|
||||
if (!listFindNoCase(existingCols, "TaskSourceType")) {
|
||||
queryExecute("
|
||||
ALTER TABLE Tasks ADD COLUMN SourceType VARCHAR(50) NULL
|
||||
ALTER TABLE Tasks ADD COLUMN TaskSourceType VARCHAR(50) NULL
|
||||
", [], { datasource: "payfrit" });
|
||||
arrayAppend(result.STEPS, "Added SourceType column");
|
||||
arrayAppend(result.STEPS, "Added TaskSourceType column");
|
||||
} else {
|
||||
arrayAppend(result.STEPS, "SourceType already exists");
|
||||
arrayAppend(result.STEPS, "TaskSourceType already exists");
|
||||
}
|
||||
|
||||
// Add SourceID if missing
|
||||
if (!listFindNoCase(existingCols, "SourceID")) {
|
||||
// Add TaskSourceID if missing
|
||||
if (!listFindNoCase(existingCols, "TaskSourceID")) {
|
||||
queryExecute("
|
||||
ALTER TABLE Tasks ADD COLUMN SourceID INT NULL
|
||||
ALTER TABLE Tasks ADD COLUMN TaskSourceID INT NULL
|
||||
", [], { datasource: "payfrit" });
|
||||
arrayAppend(result.STEPS, "Added SourceID column");
|
||||
arrayAppend(result.STEPS, "Added TaskSourceID column");
|
||||
} else {
|
||||
arrayAppend(result.STEPS, "SourceID already exists");
|
||||
arrayAppend(result.STEPS, "TaskSourceID already exists");
|
||||
}
|
||||
|
||||
// Verify columns now exist
|
||||
|
|
@ -47,7 +47,7 @@ try {
|
|||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'payfrit'
|
||||
AND TABLE_NAME = 'Tasks'
|
||||
AND COLUMN_NAME IN ('SourceType', 'SourceID')
|
||||
AND COLUMN_NAME IN ('TaskSourceType', 'TaskSourceID')
|
||||
", [], { datasource: "payfrit" });
|
||||
|
||||
result.COLUMNS = [];
|
||||
|
|
|
|||
|
|
@ -6,49 +6,49 @@
|
|||
// Show all beacons with their current business/service point assignments
|
||||
q = queryExecute("
|
||||
SELECT
|
||||
b.ID,
|
||||
b.UUID,
|
||||
b.Name,
|
||||
sp_link.BusinessID,
|
||||
sp_link.ID,
|
||||
biz.Name,
|
||||
sp.Name
|
||||
b.BeaconID,
|
||||
b.BeaconUUID,
|
||||
b.BeaconName,
|
||||
lt.BusinessID,
|
||||
lt.ServicePointID,
|
||||
biz.BusinessName,
|
||||
sp.ServicePointName
|
||||
FROM Beacons b
|
||||
LEFT JOIN ServicePoints sp_link ON sp_link.BeaconID = b.ID
|
||||
LEFT JOIN Businesses biz ON biz.ID = sp_link.BusinessID
|
||||
LEFT JOIN ServicePoints sp ON sp.ID = sp_link.ID
|
||||
WHERE b.IsActive = 1
|
||||
ORDER BY b.ID
|
||||
LEFT JOIN lt_Beacon_Businesses_ServicePoints lt ON lt.BeaconID = b.BeaconID
|
||||
LEFT JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||
WHERE b.BeaconIsActive = 1
|
||||
ORDER BY b.BeaconID
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
rows = [];
|
||||
for (row in q) {
|
||||
arrayAppend(rows, {
|
||||
"BeaconID": row.ID,
|
||||
"UUID": row.UUID,
|
||||
"Name": row.Name ?: "",
|
||||
"BeaconID": row.BeaconID,
|
||||
"BeaconUUID": row.BeaconUUID,
|
||||
"BeaconName": row.BeaconName ?: "",
|
||||
"BusinessID": row.BusinessID ?: 0,
|
||||
"Name": row.Name ?: "",
|
||||
"BusinessName": row.BusinessName ?: "",
|
||||
"ServicePointID": row.ServicePointID ?: 0,
|
||||
"Name": row.Name ?: ""
|
||||
"ServicePointName": row.ServicePointName ?: ""
|
||||
});
|
||||
}
|
||||
|
||||
// Also get service points for reference
|
||||
spQuery = queryExecute("
|
||||
SELECT sp.ID, sp.Name, sp.BusinessID, b.Name
|
||||
SELECT sp.ServicePointID, sp.ServicePointName, sp.ServicePointBusinessID, b.BusinessName
|
||||
FROM ServicePoints sp
|
||||
JOIN Businesses b ON b.ID = sp.BusinessID
|
||||
ORDER BY sp.BusinessID, sp.ID
|
||||
JOIN Businesses b ON b.BusinessID = sp.ServicePointBusinessID
|
||||
ORDER BY sp.ServicePointBusinessID, sp.ServicePointID
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
servicePoints = [];
|
||||
for (sp in spQuery) {
|
||||
arrayAppend(servicePoints, {
|
||||
"ServicePointID": sp.ID,
|
||||
"Name": sp.Name,
|
||||
"BusinessID": sp.BusinessID,
|
||||
"Name": sp.Name
|
||||
"ServicePointID": sp.ServicePointID,
|
||||
"ServicePointName": sp.ServicePointName,
|
||||
"BusinessID": sp.ServicePointBusinessID,
|
||||
"BusinessName": sp.BusinessName
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@
|
|||
<cfscript>
|
||||
// Check Big Dean's owner
|
||||
q = queryExecute("
|
||||
SELECT b.ID, b.Name, b.UserID
|
||||
SELECT b.BusinessID, b.BusinessName, b.BusinessUserID
|
||||
FROM Businesses b
|
||||
WHERE b.ID = 27
|
||||
WHERE b.BusinessID = 27
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
// Get users
|
||||
users = queryExecute("
|
||||
SELECT *
|
||||
FROM Users
|
||||
ORDER BY ID
|
||||
ORDER BY UserID
|
||||
LIMIT 20
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
|
|
@ -23,9 +23,9 @@ colNames = users.getColumnNames();
|
|||
writeOutput(serializeJSON({
|
||||
"OK": true,
|
||||
"BigDeans": {
|
||||
"BusinessID": q.ID,
|
||||
"Name": q.Name,
|
||||
"UserID": q.UserID
|
||||
"BusinessID": q.BusinessID,
|
||||
"BusinessName": q.BusinessName,
|
||||
"BusinessUserID": q.BusinessUserID
|
||||
},
|
||||
"UserColumns": colNames,
|
||||
"UserCount": users.recordCount
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ if (!len(phone)) {
|
|||
}
|
||||
|
||||
q = queryExecute("
|
||||
SELECT ID, FirstName, LastName, EmailAddress, ContactNumber, IsContactVerified
|
||||
SELECT UserID, UserFirstName, UserLastName, UserEmail, UserPhone, UserIsContactVerified
|
||||
FROM Users
|
||||
WHERE ContactNumber = :phone OR EmailAddress = :phone
|
||||
WHERE UserPhone = :phone OR UserEmail = :phone
|
||||
LIMIT 1
|
||||
", { phone: phone }, { datasource: "payfrit" });
|
||||
|
||||
|
|
@ -25,11 +25,11 @@ if (q.recordCount EQ 0) {
|
|||
|
||||
writeOutput(serializeJSON({
|
||||
"OK": true,
|
||||
"UserID": q.ID,
|
||||
"FirstName": q.FirstName,
|
||||
"LastName": q.LastName,
|
||||
"Email": q.EmailAddress,
|
||||
"Phone": q.ContactNumber,
|
||||
"Verified": q.IsContactVerified
|
||||
"UserID": q.UserID,
|
||||
"FirstName": q.UserFirstName,
|
||||
"LastName": q.UserLastName,
|
||||
"Email": q.UserEmail,
|
||||
"Phone": q.UserPhone,
|
||||
"Verified": q.UserIsContactVerified
|
||||
}));
|
||||
</cfscript>
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@
|
|||
<cfscript>
|
||||
/**
|
||||
* Cleanup Lazy Daisy Beacons
|
||||
* - Unassigns beacons 7, 8, 9 from service points
|
||||
* - Deletes beacons 7, 8, 9
|
||||
* - Removes duplicate beacons created by setupBeaconTables
|
||||
* - Updates original beacons with proper names
|
||||
*/
|
||||
response = { "OK": false, "steps": [] };
|
||||
|
|
@ -14,50 +13,52 @@ response = { "OK": false, "steps": [] };
|
|||
try {
|
||||
lazyDaisyID = 37;
|
||||
|
||||
// Unassign beacons 7, 8, 9 from any service points
|
||||
// Delete duplicate assignments for beacons 7, 8, 9
|
||||
queryExecute("
|
||||
UPDATE ServicePoints
|
||||
SET BeaconID = NULL, AssignedByUserID = NULL
|
||||
DELETE FROM lt_Beacon_Businesses_ServicePoints
|
||||
WHERE BeaconID IN (7, 8, 9) AND BusinessID = :bizId
|
||||
", { 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
|
||||
queryExecute("
|
||||
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" });
|
||||
response.steps.append("Deleted duplicate beacons 7, 8, 9");
|
||||
|
||||
// Update original beacons with names based on their service point assignments
|
||||
// Beacon 4 -> Table 1 (ServicePointID 4)
|
||||
// Beacon 5 -> Table 2 (ServicePointID 5)
|
||||
// Beacon 6 -> Table 3 (ServicePointID 6)
|
||||
|
||||
queryExecute("
|
||||
UPDATE Beacons SET Name = 'Beacon - Table 1'
|
||||
WHERE ID = 4 AND BusinessID = :bizId
|
||||
UPDATE Beacons SET BeaconName = 'Beacon - Table 1'
|
||||
WHERE BeaconID = 4 AND BeaconBusinessID = :bizId
|
||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||
response.steps.append("Updated Beacon 4 name to 'Beacon - Table 1'");
|
||||
|
||||
queryExecute("
|
||||
UPDATE Beacons SET Name = 'Beacon - Table 2'
|
||||
WHERE ID = 5 AND BusinessID = :bizId
|
||||
UPDATE Beacons SET BeaconName = 'Beacon - Table 2'
|
||||
WHERE BeaconID = 5 AND BeaconBusinessID = :bizId
|
||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||
response.steps.append("Updated Beacon 5 name to 'Beacon - Table 2'");
|
||||
|
||||
queryExecute("
|
||||
UPDATE Beacons SET Name = 'Beacon - Table 3'
|
||||
WHERE ID = 6 AND BusinessID = :bizId
|
||||
UPDATE Beacons SET BeaconName = 'Beacon - Table 3'
|
||||
WHERE BeaconID = 6 AND BeaconBusinessID = :bizId
|
||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||
response.steps.append("Updated Beacon 6 name to 'Beacon - Table 3'");
|
||||
|
||||
// Get final status
|
||||
qFinal = queryExecute("
|
||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
||||
b.Name AS BeaconName, b.UUID, sp.Name AS ServicePointName,
|
||||
biz.Name AS BusinessName
|
||||
FROM ServicePoints sp
|
||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
||||
WHERE sp.BusinessID = :bizId AND sp.BeaconID IS NOT NULL
|
||||
ORDER BY sp.BeaconID
|
||||
SELECT lt.BeaconID, b.BeaconUUID, b.BeaconName, lt.BusinessID, biz.BusinessName, lt.ServicePointID, sp.ServicePointName
|
||||
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||
JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||
WHERE lt.BusinessID = :bizId
|
||||
ORDER BY lt.BeaconID
|
||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||
|
||||
beacons = [];
|
||||
|
|
@ -65,9 +66,8 @@ try {
|
|||
arrayAppend(beacons, {
|
||||
"BeaconID": qFinal.BeaconID[i],
|
||||
"BeaconName": qFinal.BeaconName[i],
|
||||
"UUID": qFinal.UUID[i],
|
||||
"UUID": qFinal.BeaconUUID[i],
|
||||
"BusinessName": qFinal.BusinessName[i],
|
||||
"ServicePointID": qFinal.ServicePointID[i],
|
||||
"ServicePointName": qFinal.ServicePointName[i]
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@
|
|||
* Cleanup Categories - Final step after migration verification
|
||||
*
|
||||
* 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)
|
||||
* 3. Drops CategoryID column
|
||||
* 4. Drops IsModifierTemplate column (derived from lt_ItemID_TemplateItemID now)
|
||||
* 3. Drops ItemCategoryID column
|
||||
* 4. Drops ItemIsModifierTemplate column (derived from ItemTemplateLinks now)
|
||||
* 5. Drops Categories table
|
||||
*
|
||||
* Query param: ?confirm=YES to actually execute (otherwise shows verification only)
|
||||
|
|
@ -30,7 +30,7 @@ try {
|
|||
// Verification Step 1: Check for items without BusinessID
|
||||
qNoBusinessID = queryExecute("
|
||||
SELECT COUNT(*) as cnt FROM Items
|
||||
WHERE BusinessID IS NULL OR BusinessID = 0
|
||||
WHERE ItemBusinessID IS NULL OR ItemBusinessID = 0
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
response.verification["itemsWithoutBusinessID"] = qNoBusinessID.cnt;
|
||||
|
|
@ -46,38 +46,38 @@ try {
|
|||
qCategoryItems = queryExecute("
|
||||
SELECT COUNT(DISTINCT p.ItemID) as cnt
|
||||
FROM Items p
|
||||
INNER JOIN Items c ON c.ParentItemID = p.ItemID
|
||||
WHERE p.ParentItemID = 0
|
||||
AND p.BusinessID > 0
|
||||
INNER JOIN Items c ON c.ItemParentItemID = p.ItemID
|
||||
WHERE p.ItemParentItemID = 0
|
||||
AND p.ItemBusinessID > 0
|
||||
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" });
|
||||
|
||||
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("
|
||||
SELECT COUNT(DISTINCT tl.TemplateItemID) as cnt
|
||||
FROM lt_ItemID_TemplateItemID tl
|
||||
FROM ItemTemplateLinks tl
|
||||
INNER JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
response.verification["templatesInLinks"] = qTemplates.cnt;
|
||||
|
||||
// Verification Step 5: Find orphans at ParentID=0
|
||||
// Orphan = ParentID=0, no children pointing to it, not in lt_ItemID_TemplateItemID
|
||||
// Orphan = ParentID=0, no children pointing to it, not in ItemTemplateLinks
|
||||
qOrphans = queryExecute("
|
||||
SELECT i.ID, i.Name, i.BusinessID
|
||||
SELECT i.ItemID, i.ItemName, i.ItemBusinessID
|
||||
FROM Items i
|
||||
WHERE i.ParentItemID = 0
|
||||
WHERE i.ItemParentItemID = 0
|
||||
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 (
|
||||
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" });
|
||||
|
||||
response.verification["orphanCount"] = qOrphans.recordCount;
|
||||
|
|
@ -85,8 +85,8 @@ try {
|
|||
for (orphan in qOrphans) {
|
||||
arrayAppend(response.orphans, {
|
||||
"ItemID": orphan.ItemID,
|
||||
"Name": orphan.Name,
|
||||
"BusinessID": orphan.BusinessID
|
||||
"ItemName": orphan.ItemName,
|
||||
"BusinessID": orphan.ItemBusinessID
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ try {
|
|||
|
||||
if (!safeToCleanup) {
|
||||
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;
|
||||
writeOutput(serializeJSON(response));
|
||||
abort;
|
||||
|
|
@ -119,31 +119,31 @@ try {
|
|||
// Execute cleanup
|
||||
arrayAppend(response.steps, "Executing cleanup...");
|
||||
|
||||
// Step 1: Drop CategoryID column
|
||||
// Step 1: Drop ItemCategoryID column
|
||||
try {
|
||||
queryExecute("
|
||||
ALTER TABLE Items DROP COLUMN CategoryID
|
||||
ALTER TABLE Items DROP COLUMN ItemCategoryID
|
||||
", {}, { datasource: "payfrit" });
|
||||
arrayAppend(response.steps, "Dropped CategoryID column from Items");
|
||||
arrayAppend(response.steps, "Dropped ItemCategoryID column from Items");
|
||||
} catch (any e) {
|
||||
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 {
|
||||
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 {
|
||||
queryExecute("
|
||||
ALTER TABLE Items DROP COLUMN IsModifierTemplate
|
||||
ALTER TABLE Items DROP COLUMN ItemIsModifierTemplate
|
||||
", {}, { datasource: "payfrit" });
|
||||
arrayAppend(response.steps, "Dropped IsModifierTemplate column from Items");
|
||||
arrayAppend(response.steps, "Dropped ItemIsModifierTemplate column from Items");
|
||||
} catch (any e) {
|
||||
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 {
|
||||
arrayAppend(response.steps, "Warning dropping IsModifierTemplate: " & e.message);
|
||||
arrayAppend(response.steps, "Warning dropping ItemIsModifierTemplate: " & e.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ if (businessId <= 0) {
|
|||
try {
|
||||
// Find duplicate UserIDs for this business (keep the one with highest status or oldest)
|
||||
qDupes = queryExecute("
|
||||
SELECT ID, COUNT(*) as cnt, MIN(ID) as keepId
|
||||
FROM Employees
|
||||
SELECT UserID, COUNT(*) as cnt, MIN(EmployeeID) as keepId
|
||||
FROM lt_Users_Businesses_Employees
|
||||
WHERE BusinessID = ?
|
||||
GROUP BY UserID
|
||||
HAVING COUNT(*) > 1
|
||||
|
|
@ -45,8 +45,8 @@ try {
|
|||
for (row in qDupes) {
|
||||
// Delete all but the one we want to keep (the one with lowest EmployeeID)
|
||||
qDel = queryExecute("
|
||||
DELETE FROM Employees
|
||||
WHERE BusinessID = ? AND UserID = ? AND ID != ?
|
||||
DELETE FROM lt_Users_Businesses_Employees
|
||||
WHERE BusinessID = ? AND UserID = ? AND EmployeeID != ?
|
||||
", [
|
||||
{ value: businessId, cfsqltype: "cf_sql_integer" },
|
||||
{ value: row.UserID, cfsqltype: "cf_sql_integer" },
|
||||
|
|
@ -57,19 +57,19 @@ try {
|
|||
|
||||
// Get remaining employees
|
||||
qRemaining = queryExecute("
|
||||
SELECT e.ID, e.UserID, u.FirstName, u.LastName
|
||||
FROM Employees e
|
||||
JOIN Users u ON e.UserID = u.ID
|
||||
SELECT e.EmployeeID, e.UserID, u.UserFirstName, u.UserLastName
|
||||
FROM lt_Users_Businesses_Employees e
|
||||
JOIN Users u ON e.UserID = u.UserID
|
||||
WHERE e.BusinessID = ?
|
||||
ORDER BY e.ID
|
||||
ORDER BY e.EmployeeID
|
||||
", [{ value: businessId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
||||
|
||||
remaining = [];
|
||||
for (r in qRemaining) {
|
||||
arrayAppend(remaining, {
|
||||
"EmployeeID": r.ID,
|
||||
"EmployeeID": r.EmployeeID,
|
||||
"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)
|
||||
keepBusinessID = 37;
|
||||
|
||||
// Unassign all beacons from service points of other businesses
|
||||
// First, reassign all beacons to Lazy Daisy
|
||||
queryExecute("
|
||||
UPDATE ServicePoints
|
||||
SET BeaconID = NULL, AssignedByUserID = NULL
|
||||
WHERE BusinessID != :keepID AND BeaconID IS NOT NULL
|
||||
UPDATE lt_Beacon_Businesses_ServicePoints
|
||||
SET BusinessID = :keepID
|
||||
", { 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
|
||||
qBiz = queryExecute("
|
||||
SELECT ID, Name FROM Businesses WHERE ID != :keepID
|
||||
SELECT BusinessID, BusinessName FROM Businesses WHERE BusinessID != :keepID
|
||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||
|
||||
deletedBusinesses = [];
|
||||
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");
|
||||
|
||||
// Delete related data first (foreign key constraints)
|
||||
// Delete lt_ItemID_TemplateItemID for items from other businesses
|
||||
// Delete ItemTemplateLinks for items from other businesses
|
||||
queryExecute("
|
||||
DELETE itl FROM lt_ItemID_TemplateItemID itl
|
||||
JOIN Items i ON i.ID = itl.ItemID
|
||||
WHERE i.BusinessID != :keepID
|
||||
DELETE itl FROM ItemTemplateLinks itl
|
||||
JOIN Items i ON i.ItemID = itl.ItemID
|
||||
WHERE i.ItemBusinessID != :keepID
|
||||
", { 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
|
||||
qItems = queryExecute("
|
||||
SELECT COUNT(*) as cnt FROM Items WHERE BusinessID != :keepID
|
||||
SELECT COUNT(*) as cnt FROM Items WHERE ItemBusinessID != :keepID
|
||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||
queryExecute("
|
||||
DELETE FROM Items WHERE BusinessID != :keepID
|
||||
DELETE FROM Items WHERE ItemBusinessID != :keepID
|
||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||
response.steps.append("Deleted " & qItems.cnt & " items from other businesses");
|
||||
|
||||
// Delete Categories for other businesses
|
||||
queryExecute("
|
||||
DELETE FROM Categories WHERE BusinessID != :keepID
|
||||
DELETE FROM Categories WHERE CategoryBusinessID != :keepID
|
||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||
response.steps.append("Deleted categories from other businesses");
|
||||
|
||||
// Delete Hours for other businesses
|
||||
queryExecute("
|
||||
DELETE FROM Hours WHERE BusinessID != :keepID
|
||||
DELETE FROM Hours WHERE HoursBusinessID != :keepID
|
||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||
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 {
|
||||
queryExecute("
|
||||
DELETE FROM Employees WHERE BusinessID != :keepID
|
||||
DELETE FROM Employees WHERE EmployeeBusinessID != :keepID
|
||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||
response.steps.append("Deleted employees from other businesses");
|
||||
} catch (any e) {
|
||||
response.steps.append("Skipped employees (table may not exist)");
|
||||
}
|
||||
|
||||
// Delete ServicePoints for other businesses
|
||||
// Delete ServicePoints for other businesses (skip if table doesn't exist)
|
||||
try {
|
||||
queryExecute("
|
||||
DELETE FROM ServicePoints WHERE BusinessID != :keepID
|
||||
DELETE FROM ServicePoints WHERE ServicePointBusinessID != :keepID
|
||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||
response.steps.append("Deleted service points from other businesses");
|
||||
} catch (any e) {
|
||||
response.steps.append("Skipped service points (table may not exist)");
|
||||
}
|
||||
|
||||
// Delete Stations for other businesses
|
||||
// Delete Stations for other businesses (skip if table doesn't exist)
|
||||
try {
|
||||
queryExecute("
|
||||
DELETE FROM Stations WHERE BusinessID != :keepID
|
||||
DELETE FROM Stations WHERE StationBusinessID != :keepID
|
||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||
response.steps.append("Deleted stations from other businesses");
|
||||
} catch (any e) {
|
||||
response.steps.append("Skipped stations (table may not exist)");
|
||||
}
|
||||
|
||||
// Delete beacon-business mappings for other businesses
|
||||
try {
|
||||
queryExecute("
|
||||
DELETE FROM lt_BeaconsID_BusinessesID WHERE BusinessID != :keepID
|
||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||
response.steps.append("Deleted beacon mappings for other businesses");
|
||||
} catch (any e) {
|
||||
response.steps.append("Skipped beacon mappings (table may not exist)");
|
||||
}
|
||||
|
||||
// Finally delete the businesses themselves
|
||||
queryExecute("
|
||||
DELETE FROM Businesses WHERE ID != :keepID
|
||||
DELETE FROM Businesses WHERE BusinessID != :keepID
|
||||
", { keepID: keepBusinessID }, { datasource: "payfrit" });
|
||||
response.steps.append("Deleted " & arrayLen(deletedBusinesses) & " businesses");
|
||||
|
||||
// Get beacon status
|
||||
qBeacons = queryExecute("
|
||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
||||
b.UUID, biz.Name AS BusinessName, sp.Name AS ServicePointName
|
||||
FROM ServicePoints sp
|
||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
||||
WHERE sp.BeaconID IS NOT NULL
|
||||
SELECT lt.BeaconID, b.BeaconUUID, lt.BusinessID, biz.BusinessName, lt.ServicePointID
|
||||
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||
JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
beacons = [];
|
||||
for (i = 1; i <= qBeacons.recordCount; i++) {
|
||||
arrayAppend(beacons, {
|
||||
"BeaconID": qBeacons.BeaconID[i],
|
||||
"UUID": qBeacons.UUID[i],
|
||||
"UUID": qBeacons.BeaconUUID[i],
|
||||
"BusinessID": qBeacons.BusinessID[i],
|
||||
"BusinessName": qBeacons.BusinessName[i],
|
||||
"ServicePointID": qBeacons.ServicePointID[i],
|
||||
"ServicePointName": qBeacons.ServicePointName[i]
|
||||
"ServicePointID": qBeacons.ServicePointID[i]
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ param name="url.action" default="check"; // "check" or "deactivate"
|
|||
|
||||
// Check the item first
|
||||
qItem = queryExecute("
|
||||
SELECT ID, Name, ParentItemID, IsActive, IsCollapsible
|
||||
SELECT ItemID, ItemName, ItemParentItemID, ItemIsActive, ItemIsCollapsible
|
||||
FROM Items
|
||||
WHERE ID = :itemId
|
||||
WHERE ItemID = :itemId
|
||||
", { itemId: url.itemId });
|
||||
|
||||
if (qItem.recordCount == 0) {
|
||||
|
|
@ -19,25 +19,25 @@ if (qItem.recordCount == 0) {
|
|||
|
||||
// Get all children (direct only for display)
|
||||
qChildren = queryExecute("
|
||||
SELECT ID, Name
|
||||
SELECT ItemID, ItemName
|
||||
FROM Items
|
||||
WHERE ParentItemID = :itemId
|
||||
WHERE ItemParentItemID = :itemId
|
||||
", { itemId: url.itemId });
|
||||
|
||||
childList = [];
|
||||
for (row in qChildren) {
|
||||
arrayAppend(childList, { "ItemID": row.ID, "Name": row.Name });
|
||||
arrayAppend(childList, { "ItemID": row.ItemID, "ItemName": row.ItemName });
|
||||
}
|
||||
|
||||
result = {
|
||||
"OK": true,
|
||||
"ACTION": url.action,
|
||||
"ITEM": {
|
||||
"ItemID": qItem.ID,
|
||||
"Name": qItem.Name,
|
||||
"ParentItemID": qItem.ParentItemID,
|
||||
"IsActive": qItem.IsActive,
|
||||
"IsCollapsible": qItem.IsCollapsible
|
||||
"ItemID": qItem.ItemID,
|
||||
"ItemName": qItem.ItemName,
|
||||
"ItemParentItemID": qItem.ItemParentItemID,
|
||||
"ItemIsActive": qItem.ItemIsActive,
|
||||
"ItemIsCollapsible": qItem.ItemIsCollapsible
|
||||
},
|
||||
"HAS_CHILDREN": qChildren.recordCount > 0,
|
||||
"CHILD_COUNT": qChildren.recordCount,
|
||||
|
|
@ -48,14 +48,14 @@ if (url.action == "deactivate") {
|
|||
// Deactivate children first
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET IsActive = 0
|
||||
WHERE ParentItemID = :itemId
|
||||
SET ItemIsActive = 0
|
||||
WHERE ItemParentItemID = :itemId
|
||||
", { itemId: url.itemId });
|
||||
|
||||
// Then deactivate the parent
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET IsActive = 0
|
||||
SET ItemIsActive = 0
|
||||
WHERE ItemID = :itemId
|
||||
", { itemId: url.itemId });
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
// Delete cart orders (status 0) to reset for testing
|
||||
result = queryExecute("
|
||||
DELETE FROM OrderLineItems
|
||||
WHERE OrderID IN (
|
||||
SELECT ID FROM Orders WHERE StatusID = 0
|
||||
WHERE OrderLineItemOrderID IN (
|
||||
SELECT OrderID FROM Orders WHERE OrderStatusID = 0
|
||||
)
|
||||
", {}, { datasource = "payfrit" });
|
||||
|
||||
result2 = queryExecute("
|
||||
DELETE FROM Orders WHERE StatusID = 0
|
||||
DELETE FROM Orders WHERE OrderStatusID = 0
|
||||
", {}, { datasource = "payfrit" });
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
|
|
|
|||
|
|
@ -10,27 +10,27 @@ try {
|
|||
businessIDs = [38, 39, 40, 41, 42];
|
||||
|
||||
for (bizID in businessIDs) {
|
||||
// Delete lt_ItemID_TemplateItemID for items belonging to this business
|
||||
// Delete ItemTemplateLinks for items belonging to this business
|
||||
queryExecute("
|
||||
DELETE itl FROM lt_ItemID_TemplateItemID itl
|
||||
INNER JOIN Items i ON i.ID = itl.ItemID
|
||||
WHERE i.BusinessID = :bizID
|
||||
DELETE itl FROM ItemTemplateLinks itl
|
||||
INNER JOIN Items i ON i.ItemID = itl.ItemID
|
||||
WHERE i.ItemBusinessID = :bizID
|
||||
", { bizID: bizID }, { datasource: "payfrit" });
|
||||
|
||||
// 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
|
||||
queryExecute("DELETE FROM Categories WHERE BusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
||||
queryExecute("DELETE FROM Categories WHERE CategoryBusinessID = :bizID", { bizID: bizID }, { datasource: "payfrit" });
|
||||
|
||||
// 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
|
||||
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
|
||||
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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
try {
|
||||
result = queryExecute("
|
||||
UPDATE Tasks
|
||||
SET CompletedOn = NOW()
|
||||
SET TaskCompletedOn = NOW()
|
||||
WHERE TaskTypeID = 2
|
||||
AND CompletedOn IS NULL
|
||||
AND TaskCompletedOn IS NULL
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
affected = result.recordCount ?: 0;
|
||||
|
|
|
|||
|
|
@ -15,24 +15,24 @@ try {
|
|||
|
||||
// First, check if Big Dean's has a Beverages/Drinks category
|
||||
qExistingCat = queryExecute("
|
||||
SELECT ID, Name FROM Categories
|
||||
WHERE BusinessID = :bizId AND (Name LIKE '%Drink%' OR Name LIKE '%Beverage%')
|
||||
SELECT CategoryID, CategoryName FROM Categories
|
||||
WHERE CategoryBusinessID = :bizId AND (CategoryName LIKE '%Drink%' OR CategoryName LIKE '%Beverage%')
|
||||
", { bizId: bigDeansBusinessId }, { datasource: "payfrit" });
|
||||
|
||||
if (qExistingCat.recordCount > 0) {
|
||||
drinksCategoryId = qExistingCat.CategoryID;
|
||||
response["CategoryNote"] = "Using existing category: " & qExistingCat.Name;
|
||||
response["CategoryNote"] = "Using existing category: " & qExistingCat.CategoryName;
|
||||
} else {
|
||||
// Create a new Beverages category for Big Dean's
|
||||
qMaxCat = queryExecute("SELECT COALESCE(MAX(CategoryID), 0) + 1 as nextId FROM Categories", {}, { datasource: "payfrit" });
|
||||
drinksCategoryId = qMaxCat.nextId;
|
||||
|
||||
qMaxSort = queryExecute("
|
||||
SELECT COALESCE(MAX(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" });
|
||||
|
||||
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())
|
||||
", {
|
||||
catId: drinksCategoryId,
|
||||
|
|
@ -61,8 +61,8 @@ try {
|
|||
for (drink in drinks) {
|
||||
// Check if item already exists
|
||||
qExists = queryExecute("
|
||||
SELECT ID FROM Items
|
||||
WHERE BusinessID = :bizId AND Name = :name AND CategoryID = :catId
|
||||
SELECT ItemID FROM Items
|
||||
WHERE ItemBusinessID = :bizId AND ItemName = :name AND ItemCategoryID = :catId
|
||||
", { bizId: bigDeansBusinessId, name: drink.name, catId: drinksCategoryId }, { datasource: "payfrit" });
|
||||
|
||||
if (qExists.recordCount == 0) {
|
||||
|
|
@ -72,10 +72,10 @@ try {
|
|||
|
||||
queryExecute("
|
||||
INSERT INTO Items (
|
||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
||||
Name, Description, Price, IsActive,
|
||||
SortOrder, IsCollapsible, RequiresChildSelection,
|
||||
AddedOn
|
||||
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||
ItemSortOrder, ItemIsCollapsible, ItemRequiresChildSelection,
|
||||
ItemAddedOn
|
||||
) VALUES (
|
||||
:itemId, :bizId, :catId, 0,
|
||||
:name, :desc, :price, 1,
|
||||
|
|
@ -103,10 +103,10 @@ try {
|
|||
qMaxOpt = queryExecute("SELECT COALESCE(MAX(ItemID), 0) + 1 as nextId FROM Items", {}, { datasource: "payfrit" });
|
||||
queryExecute("
|
||||
INSERT INTO Items (
|
||||
ItemID, BusinessID, CategoryID, ParentItemID,
|
||||
Name, Description, Price, IsActive,
|
||||
SortOrder, IsCollapsible, IsCheckedByDefault,
|
||||
AddedOn
|
||||
ItemID, ItemBusinessID, ItemCategoryID, ItemParentItemID,
|
||||
ItemName, ItemDescription, ItemPrice, ItemIsActive,
|
||||
ItemSortOrder, ItemIsCollapsible, ItemIsCheckedByDefault,
|
||||
ItemAddedOn
|
||||
) VALUES (
|
||||
:itemId, :bizId, 0, :parentId,
|
||||
:name, '', 0, 1,
|
||||
|
|
|
|||
|
|
@ -20,74 +20,69 @@ try {
|
|||
uuid = beaconUUIDs[i];
|
||||
|
||||
// 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) {
|
||||
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" });
|
||||
beaconID = qNew.id;
|
||||
response.steps.append("Created beacon " & beaconID & " with UUID: " & uuid);
|
||||
} else {
|
||||
beaconID = qB.ID;
|
||||
beaconID = qB.BeaconID;
|
||||
response.steps.append("Beacon exists: " & beaconID & " with UUID: " & uuid);
|
||||
}
|
||||
}
|
||||
|
||||
// Get service point Table 1
|
||||
qSP = queryExecute("
|
||||
SELECT ID FROM ServicePoints
|
||||
WHERE BusinessID = :bizID AND Name = 'Table 1'
|
||||
SELECT ServicePointID FROM ServicePoints
|
||||
WHERE ServicePointBusinessID = :bizID AND ServicePointName = 'Table 1'
|
||||
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||
|
||||
if (qSP.recordCount == 0) {
|
||||
queryExecute("
|
||||
INSERT INTO ServicePoints (BusinessID, Name)
|
||||
VALUES (:bizID, 'Table 1')
|
||||
INSERT INTO ServicePoints (ServicePointBusinessID, ServicePointName, ServicePointTypeID)
|
||||
VALUES (:bizID, 'Table 1', 1)
|
||||
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||
qSP = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
||||
servicePointID = qSP.id;
|
||||
response.steps.append("Created service point 'Table 1' (ID: " & servicePointID & ")");
|
||||
} else {
|
||||
servicePointID = qSP.ID;
|
||||
servicePointID = qSP.ServicePointID;
|
||||
response.steps.append("Found service point 'Table 1' (ID: " & servicePointID & ")");
|
||||
}
|
||||
|
||||
// Assign all beacons to the Table 1 service point
|
||||
qBeacons = queryExecute("SELECT ID, UUID FROM Beacons WHERE BusinessID = :bizID", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||
// Get all beacons and map them
|
||||
qBeacons = queryExecute("SELECT BeaconID, BeaconUUID FROM Beacons", {}, { datasource: "payfrit" });
|
||||
|
||||
for (i = 1; i <= qBeacons.recordCount; i++) {
|
||||
beaconID = qBeacons.ID[i];
|
||||
beaconID = qBeacons.BeaconID[i];
|
||||
|
||||
// Unassign this beacon from any existing service point
|
||||
queryExecute("
|
||||
UPDATE ServicePoints SET BeaconID = NULL, AssignedByUserID = NULL
|
||||
WHERE BeaconID = :beaconID
|
||||
", { beaconID: beaconID }, { datasource: "payfrit" });
|
||||
// Delete old mapping if exists
|
||||
queryExecute("DELETE FROM lt_Beacon_Businesses_ServicePoints WHERE BeaconID = :beaconID", { beaconID: beaconID }, { datasource: "payfrit" });
|
||||
|
||||
// Assign beacon to Table 1 service point
|
||||
// Create new mapping
|
||||
queryExecute("
|
||||
UPDATE ServicePoints SET BeaconID = :beaconID, AssignedByUserID = 1
|
||||
WHERE ID = :spID AND BusinessID = :bizID
|
||||
INSERT INTO lt_Beacon_Businesses_ServicePoints (BeaconID, BusinessID, ServicePointID)
|
||||
VALUES (:beaconID, :bizID, :spID)
|
||||
", { 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
|
||||
qFinal = queryExecute("
|
||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
||||
b.Name AS BeaconName, b.UUID, sp.Name AS ServicePointName,
|
||||
biz.Name AS BusinessName
|
||||
FROM ServicePoints sp
|
||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
||||
WHERE sp.BeaconID IS NOT NULL
|
||||
SELECT lt.BeaconID, b.BeaconUUID, lt.BusinessID, biz.BusinessName, lt.ServicePointID, sp.ServicePointName
|
||||
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||
JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
beacons = [];
|
||||
for (i = 1; i <= qFinal.recordCount; i++) {
|
||||
arrayAppend(beacons, {
|
||||
"BeaconID": qFinal.BeaconID[i],
|
||||
"UUID": qFinal.UUID[i],
|
||||
"UUID": qFinal.BeaconUUID[i],
|
||||
"BusinessID": qFinal.BusinessID[i],
|
||||
"BusinessName": qFinal.BusinessName[i],
|
||||
"ServicePointID": qFinal.ServicePointID[i],
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ try {
|
|||
// Create ChatMessages table
|
||||
queryExecute("
|
||||
CREATE TABLE IF NOT EXISTS ChatMessages (
|
||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
MessageID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
TaskID INT NOT NULL,
|
||||
SenderUserID INT NOT NULL,
|
||||
SenderType ENUM('customer', 'worker') NOT NULL,
|
||||
MessageBody TEXT NOT NULL,
|
||||
MessageText TEXT NOT NULL,
|
||||
IsRead TINYINT(1) DEFAULT 0,
|
||||
CreatedOn DATETIME DEFAULT NOW(),
|
||||
|
||||
|
|
@ -21,13 +21,13 @@ try {
|
|||
|
||||
// Also add a "Chat" category if it doesn't exist for business 17
|
||||
existing = queryExecute("
|
||||
SELECT ID FROM TaskCategories
|
||||
WHERE BusinessID = 17 AND Name = 'Chat'
|
||||
SELECT TaskCategoryID FROM TaskCategories
|
||||
WHERE TaskCategoryBusinessID = 17 AND TaskCategoryName = 'Chat'
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
if (existing.recordCount == 0) {
|
||||
queryExecute("
|
||||
INSERT INTO TaskCategories (BusinessID, Name, Color)
|
||||
INSERT INTO TaskCategories (TaskCategoryBusinessID, TaskCategoryName, TaskCategoryColor)
|
||||
VALUES (17, 'Chat', '##2196F3')
|
||||
", {}, { datasource: "payfrit" });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,47 +32,47 @@ try {
|
|||
queryExecute("
|
||||
CREATE TABLE Menus (
|
||||
MenuID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
BusinessID INT NOT NULL,
|
||||
Name VARCHAR(100) NOT NULL,
|
||||
Description VARCHAR(500) NULL,
|
||||
DaysActive INT NOT NULL DEFAULT 127,
|
||||
StartTime TIME NULL,
|
||||
EndTime TIME NULL,
|
||||
SortOrder INT NOT NULL DEFAULT 0,
|
||||
IsActive TINYINT NOT NULL DEFAULT 1,
|
||||
AddedOn DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_menus_business (BusinessID),
|
||||
INDEX idx_menus_active (BusinessID, IsActive)
|
||||
MenuBusinessID INT NOT NULL,
|
||||
MenuName VARCHAR(100) NOT NULL,
|
||||
MenuDescription VARCHAR(500) NULL,
|
||||
MenuDaysActive INT NOT NULL DEFAULT 127,
|
||||
MenuStartTime TIME NULL,
|
||||
MenuEndTime TIME NULL,
|
||||
MenuSortOrder INT NOT NULL DEFAULT 0,
|
||||
MenuIsActive TINYINT NOT NULL DEFAULT 1,
|
||||
MenuAddedOn DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_menus_business (MenuBusinessID),
|
||||
INDEX idx_menus_active (MenuBusinessID, MenuIsActive)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
response["OK"] = true;
|
||||
response["MESSAGE"] = "Menus table created successfully";
|
||||
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("
|
||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_SCHEMA = 'payfrit'
|
||||
AND TABLE_NAME = 'Categories'
|
||||
AND COLUMN_NAME = 'MenuID'
|
||||
AND COLUMN_NAME = 'CategoryMenuID'
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
if (qCatCol.recordCount == 0) {
|
||||
// Add MenuID column to Categories table
|
||||
// Add CategoryMenuID column to Categories table
|
||||
queryExecute("
|
||||
ALTER TABLE Categories
|
||||
ADD COLUMN MenuID INT NULL DEFAULT NULL AFTER BusinessID,
|
||||
ADD INDEX idx_categories_menu (MenuID)
|
||||
ADD COLUMN CategoryMenuID INT NULL DEFAULT NULL AFTER CategoryBusinessID,
|
||||
ADD INDEX idx_categories_menu (CategoryMenuID)
|
||||
", {}, { datasource: "payfrit" });
|
||||
response["CATEGORIES_UPDATED"] = true;
|
||||
response["CATEGORIES_MESSAGE"] = "Added MenuID column to Categories table";
|
||||
response["CATEGORIES_MESSAGE"] = "Added CategoryMenuID column to Categories table";
|
||||
} else {
|
||||
response["CATEGORIES_UPDATED"] = false;
|
||||
response["CATEGORIES_MESSAGE"] = "MenuID column already exists";
|
||||
response["CATEGORIES_MESSAGE"] = "CategoryMenuID column already exists";
|
||||
}
|
||||
|
||||
} catch (any e) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
*
|
||||
* POST body:
|
||||
* {
|
||||
* "Name": "Century Casino",
|
||||
* "BusinessName": "Century Casino",
|
||||
* "UserID": 1,
|
||||
* "ChildBusinessIDs": [47, 48] // Optional: link existing businesses as children
|
||||
* }
|
||||
|
|
@ -36,13 +36,13 @@ response = { "OK": false };
|
|||
try {
|
||||
data = readJsonBody();
|
||||
|
||||
Name = structKeyExists(data, "Name") ? trim(data.Name) : "";
|
||||
BusinessName = structKeyExists(data, "BusinessName") ? trim(data.BusinessName) : "";
|
||||
UserID = structKeyExists(data, "UserID") ? val(data.UserID) : 0;
|
||||
ChildBusinessIDs = structKeyExists(data, "ChildBusinessIDs") && isArray(data.ChildBusinessIDs) ? data.ChildBusinessIDs : [];
|
||||
|
||||
if (!len(Name)) {
|
||||
if (!len(BusinessName)) {
|
||||
response["ERROR"] = "missing_name";
|
||||
response["MESSAGE"] = "Name is required";
|
||||
response["MESSAGE"] = "BusinessName is required";
|
||||
writeOutput(serializeJSON(response));
|
||||
abort;
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ try {
|
|||
|
||||
// Create minimal address record (just a placeholder)
|
||||
queryExecute("
|
||||
INSERT INTO Addresses (Line1, UserID, AddressTypeID, AddedOn)
|
||||
INSERT INTO Addresses (AddressLine1, AddressUserID, AddressTypeID, AddressAddedOn)
|
||||
VALUES ('Parent Business - No Physical Location', :userID, 2, NOW())
|
||||
", {
|
||||
userID: UserID
|
||||
|
|
@ -67,10 +67,10 @@ try {
|
|||
|
||||
// Create parent business (no menu, no hours, just a shell)
|
||||
queryExecute("
|
||||
INSERT INTO Businesses (Name, UserID, AddressID, ParentBusinessID, BusinessDeliveryZipCodes, AddedOn)
|
||||
INSERT INTO Businesses (BusinessName, BusinessUserID, BusinessAddressID, BusinessParentBusinessID, BusinessDeliveryZipCodes, BusinessAddedOn)
|
||||
VALUES (:name, :userId, :addressId, NULL, '', NOW())
|
||||
", {
|
||||
name: Name,
|
||||
name: BusinessName,
|
||||
userId: UserID,
|
||||
addressId: addressId
|
||||
}, { datasource = "payfrit" });
|
||||
|
|
@ -80,7 +80,7 @@ try {
|
|||
|
||||
// Link address back to business
|
||||
queryExecute("
|
||||
UPDATE Addresses SET BusinessID = :bizId WHERE ID = :addrId
|
||||
UPDATE Addresses SET AddressBusinessID = :bizId WHERE AddressID = :addrId
|
||||
", {
|
||||
bizId: newBusinessID,
|
||||
addrId: addressId
|
||||
|
|
@ -92,7 +92,7 @@ try {
|
|||
childID = val(childID);
|
||||
if (childID > 0) {
|
||||
queryExecute("
|
||||
UPDATE Businesses SET ParentBusinessID = :parentId WHERE ID = :childId
|
||||
UPDATE Businesses SET BusinessParentBusinessID = :parentId WHERE BusinessID = :childId
|
||||
", {
|
||||
parentId: newBusinessID,
|
||||
childId: childID
|
||||
|
|
@ -103,7 +103,7 @@ try {
|
|||
|
||||
response["OK"] = true;
|
||||
response["BusinessID"] = newBusinessID;
|
||||
response["Name"] = Name;
|
||||
response["BusinessName"] = BusinessName;
|
||||
response["MESSAGE"] = "Parent business created";
|
||||
if (arrayLen(linkedChildren) > 0) {
|
||||
response["LinkedChildren"] = linkedChildren;
|
||||
|
|
|
|||
|
|
@ -9,22 +9,22 @@ bizId = 27;
|
|||
deactivatedIds = [11177, 11180, 11183, 11186, 11190, 11193, 11196, 11199, 11204, 11212, 11220, 11259];
|
||||
|
||||
qDeactivated = queryExecute("
|
||||
SELECT i.ID, i.Name, i.ParentItemID, i.IsActive, i.IsCollapsible,
|
||||
(SELECT COUNT(*) FROM Items c WHERE c.ParentItemID = i.ID) as ChildCount,
|
||||
(SELECT GROUP_CONCAT(c.Name) FROM Items c WHERE c.ParentItemID = i.ID) as Children
|
||||
SELECT i.ItemID, i.ItemName, i.ItemParentItemID, i.ItemIsActive, i.ItemIsCollapsible,
|
||||
(SELECT COUNT(*) FROM Items c WHERE c.ItemParentItemID = i.ItemID) as ChildCount,
|
||||
(SELECT GROUP_CONCAT(c.ItemName) FROM Items c WHERE c.ItemParentItemID = i.ItemID) as Children
|
||||
FROM Items i
|
||||
WHERE i.ID IN (:ids)
|
||||
ORDER BY i.ID
|
||||
WHERE i.ItemID IN (:ids)
|
||||
ORDER BY i.ItemID
|
||||
", { ids: { value: arrayToList(deactivatedIds), list: true } }, { datasource: "payfrit" });
|
||||
|
||||
items = [];
|
||||
for (row in qDeactivated) {
|
||||
arrayAppend(items, {
|
||||
"ItemID": row.ID,
|
||||
"Name": row.Name,
|
||||
"ParentID": row.ParentItemID,
|
||||
"IsActive": row.IsActive,
|
||||
"IsCollapsible": row.IsCollapsible,
|
||||
"ItemID": row.ItemID,
|
||||
"ItemName": row.ItemName,
|
||||
"ParentID": row.ItemParentItemID,
|
||||
"IsActive": row.ItemIsActive,
|
||||
"IsCollapsible": row.ItemIsCollapsible,
|
||||
"ChildCount": row.ChildCount,
|
||||
"Children": row.Children
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,24 +9,24 @@ bizId = 27;
|
|||
qLinks = queryExecute("
|
||||
SELECT
|
||||
tl.ItemID as MenuItemID,
|
||||
mi.Name as MenuName,
|
||||
mi.ParentItemID,
|
||||
mi.ItemName as MenuItemName,
|
||||
mi.ItemParentItemID,
|
||||
tl.TemplateItemID,
|
||||
t.Name as TemplateName,
|
||||
t.ItemName as TemplateName,
|
||||
tl.SortOrder
|
||||
FROM lt_ItemID_TemplateItemID tl
|
||||
JOIN Items mi ON mi.ID = tl.ItemID
|
||||
FROM ItemTemplateLinks tl
|
||||
JOIN Items mi ON mi.ItemID = tl.ItemID
|
||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||
WHERE mi.BusinessID = :bizId
|
||||
ORDER BY mi.ParentItemID, mi.Name, tl.SortOrder
|
||||
WHERE mi.ItemBusinessID = :bizId
|
||||
ORDER BY mi.ItemParentItemID, mi.ItemName, tl.SortOrder
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
links = [];
|
||||
for (row in qLinks) {
|
||||
arrayAppend(links, {
|
||||
"MenuItemID": row.MenuItemID,
|
||||
"MenuName": row.MenuName,
|
||||
"ParentItemID": row.ParentItemID,
|
||||
"MenuItemName": row.MenuItemName,
|
||||
"ParentItemID": row.ItemParentItemID,
|
||||
"TemplateItemID": row.TemplateItemID,
|
||||
"TemplateName": row.TemplateName
|
||||
});
|
||||
|
|
@ -34,20 +34,20 @@ for (row in qLinks) {
|
|||
|
||||
// Get burgers specifically (parent = 11271)
|
||||
qBurgers = queryExecute("
|
||||
SELECT ID, Name FROM Items
|
||||
WHERE BusinessID = :bizId AND ParentItemID = 11271 AND IsActive = 1
|
||||
ORDER BY SortOrder
|
||||
SELECT ItemID, ItemName FROM Items
|
||||
WHERE ItemBusinessID = :bizId AND ItemParentItemID = 11271 AND ItemIsActive = 1
|
||||
ORDER BY ItemSortOrder
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
burgers = [];
|
||||
for (row in qBurgers) {
|
||||
// Get templates for this burger
|
||||
qBurgerTemplates = queryExecute("
|
||||
SELECT tl.TemplateItemID, t.Name as TemplateName
|
||||
FROM lt_ItemID_TemplateItemID tl
|
||||
SELECT tl.TemplateItemID, t.ItemName as TemplateName
|
||||
FROM ItemTemplateLinks tl
|
||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||
WHERE tl.ItemID = :itemId
|
||||
", { itemId: row.ID }, { datasource: "payfrit" });
|
||||
", { itemId: row.ItemID }, { datasource: "payfrit" });
|
||||
|
||||
templates = [];
|
||||
for (t in qBurgerTemplates) {
|
||||
|
|
@ -55,8 +55,8 @@ for (row in qBurgers) {
|
|||
}
|
||||
|
||||
arrayAppend(burgers, {
|
||||
"ItemID": row.ID,
|
||||
"Name": row.Name,
|
||||
"ItemID": row.ItemID,
|
||||
"ItemName": row.ItemName,
|
||||
"Templates": templates
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,38 +9,38 @@ businessID = 27;
|
|||
qCategories = queryExecute("
|
||||
SELECT DISTINCT
|
||||
p.ItemID as CategoryID,
|
||||
p.Name as Name,
|
||||
p.SortOrder
|
||||
p.ItemName as CategoryName,
|
||||
p.ItemSortOrder
|
||||
FROM Items p
|
||||
INNER JOIN Items c ON c.ParentItemID = p.ItemID
|
||||
WHERE p.BusinessID = :businessID
|
||||
AND p.ParentItemID = 0
|
||||
AND p.IsActive = 1
|
||||
INNER JOIN Items c ON c.ItemParentItemID = p.ItemID
|
||||
WHERE p.ItemBusinessID = :businessID
|
||||
AND p.ItemParentItemID = 0
|
||||
AND p.ItemIsActive = 1
|
||||
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 });
|
||||
|
||||
cats = [];
|
||||
for (c in qCategories) {
|
||||
arrayAppend(cats, {
|
||||
"CategoryID": c.ID,
|
||||
"Name": c.Name
|
||||
"CategoryID": c.CategoryID,
|
||||
"CategoryName": c.CategoryName
|
||||
});
|
||||
}
|
||||
|
||||
// Also check raw counts
|
||||
rawCount = queryExecute("
|
||||
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 });
|
||||
|
||||
childrenCount = queryExecute("
|
||||
SELECT COUNT(DISTINCT c.ParentItemID) as cnt
|
||||
SELECT COUNT(DISTINCT c.ItemParentItemID) as cnt
|
||||
FROM Items c
|
||||
INNER JOIN Items p ON p.ItemID = c.ParentItemID
|
||||
WHERE p.BusinessID = :bizId AND p.ParentItemID = 0
|
||||
INNER JOIN Items p ON p.ItemID = c.ItemParentItemID
|
||||
WHERE p.ItemBusinessID = :bizId AND p.ItemParentItemID = 0
|
||||
", { bizId: businessID });
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
|
|
|
|||
|
|
@ -9,24 +9,24 @@ bizId = 27;
|
|||
qLinks = queryExecute("
|
||||
SELECT
|
||||
tl.ItemID as MenuItemID,
|
||||
mi.Name as MenuName,
|
||||
mi.ParentItemID as MenuItemParentID,
|
||||
mi.ItemName as MenuItemName,
|
||||
mi.ItemParentItemID as MenuItemParentID,
|
||||
tl.TemplateItemID,
|
||||
t.Name as TemplateName,
|
||||
t.IsActive as TemplateActive,
|
||||
t.ItemName as TemplateName,
|
||||
t.ItemIsActive as TemplateActive,
|
||||
tl.SortOrder
|
||||
FROM lt_ItemID_TemplateItemID tl
|
||||
JOIN Items mi ON mi.ID = tl.ItemID
|
||||
FROM ItemTemplateLinks tl
|
||||
JOIN Items mi ON mi.ItemID = tl.ItemID
|
||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||
WHERE mi.BusinessID = :bizId
|
||||
ORDER BY mi.Name, tl.SortOrder
|
||||
WHERE mi.ItemBusinessID = :bizId
|
||||
ORDER BY mi.ItemName, tl.SortOrder
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
links = [];
|
||||
for (row in qLinks) {
|
||||
arrayAppend(links, {
|
||||
"MenuItemID": row.MenuItemID,
|
||||
"MenuName": row.MenuName,
|
||||
"MenuItemName": row.MenuItemName,
|
||||
"MenuItemParentID": row.MenuItemParentID,
|
||||
"TemplateItemID": row.TemplateItemID,
|
||||
"TemplateName": row.TemplateName,
|
||||
|
|
@ -37,20 +37,20 @@ for (row in qLinks) {
|
|||
|
||||
// Get all templates that exist for this business
|
||||
qTemplates = queryExecute("
|
||||
SELECT ID, Name, IsActive, ParentItemID
|
||||
SELECT ItemID, ItemName, ItemIsActive, ItemParentItemID
|
||||
FROM Items
|
||||
WHERE BusinessID = :bizId
|
||||
AND IsCollapsible = 1
|
||||
ORDER BY Name
|
||||
WHERE ItemBusinessID = :bizId
|
||||
AND ItemIsCollapsible = 1
|
||||
ORDER BY ItemName
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
templates = [];
|
||||
for (row in qTemplates) {
|
||||
arrayAppend(templates, {
|
||||
"ItemID": row.ID,
|
||||
"Name": row.Name,
|
||||
"IsActive": row.IsActive,
|
||||
"ParentID": row.ParentItemID
|
||||
"ItemID": row.ItemID,
|
||||
"ItemName": row.ItemName,
|
||||
"IsActive": row.ItemIsActive,
|
||||
"ParentID": row.ItemParentItemID
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,67 +5,67 @@
|
|||
<cfscript>
|
||||
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";
|
||||
|
||||
qTemplates = queryExecute("
|
||||
SELECT ID, Name, IsCollapsible, IsActive, ParentItemID, BusinessID
|
||||
SELECT ItemID, ItemName, ItemIsCollapsible, ItemIsActive, ItemParentItemID, ItemBusinessID
|
||||
FROM Items
|
||||
WHERE ID IN (#templateIds#)
|
||||
ORDER BY Name
|
||||
WHERE ItemID IN (#templateIds#)
|
||||
ORDER BY ItemName
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
templates = [];
|
||||
for (row in qTemplates) {
|
||||
arrayAppend(templates, {
|
||||
"ItemID": row.ID,
|
||||
"Name": row.Name,
|
||||
"IsCollapsible": row.IsCollapsible,
|
||||
"IsActive": row.IsActive,
|
||||
"ParentID": row.ParentItemID,
|
||||
"BusinessID": row.BusinessID
|
||||
"ItemID": row.ItemID,
|
||||
"ItemName": row.ItemName,
|
||||
"IsCollapsible": row.ItemIsCollapsible,
|
||||
"IsActive": row.ItemIsActive,
|
||||
"ParentID": row.ItemParentItemID,
|
||||
"BusinessID": row.ItemBusinessID
|
||||
});
|
||||
}
|
||||
|
||||
// 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("
|
||||
SELECT DISTINCT t.ItemID, t.Name, t.IsCollapsible, t.IsActive
|
||||
SELECT DISTINCT t.ItemID, t.ItemName, t.ItemIsCollapsible, t.ItemIsActive
|
||||
FROM Items t
|
||||
WHERE t.BusinessID = :bizId
|
||||
AND t.ParentItemID = 0
|
||||
WHERE t.ItemBusinessID = :bizId
|
||||
AND t.ItemParentItemID = 0
|
||||
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)
|
||||
ORDER BY t.Name
|
||||
AND EXISTS (SELECT 1 FROM Items child WHERE child.ItemParentItemID = t.ItemID)
|
||||
ORDER BY t.ItemName
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
potentialTemplates = [];
|
||||
for (row in qMissingTemplates) {
|
||||
arrayAppend(potentialTemplates, {
|
||||
"ItemID": row.ID,
|
||||
"Name": row.Name,
|
||||
"IsCollapsible": row.IsCollapsible,
|
||||
"IsActive": row.IsActive
|
||||
"ItemID": row.ItemID,
|
||||
"ItemName": row.ItemName,
|
||||
"IsCollapsible": row.ItemIsCollapsible,
|
||||
"IsActive": row.ItemIsActive
|
||||
});
|
||||
}
|
||||
|
||||
// What templates SHOULD burgers have? Let's see all templates used by ANY item
|
||||
qAllTemplateUsage = queryExecute("
|
||||
SELECT t.ItemID, t.Name, COUNT(tl.ItemID) as UsageCount
|
||||
FROM lt_ItemID_TemplateItemID tl
|
||||
SELECT t.ItemID, t.ItemName, COUNT(tl.ItemID) as UsageCount
|
||||
FROM ItemTemplateLinks tl
|
||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||
JOIN Items mi ON mi.ID = tl.ItemID AND mi.BusinessID = :bizId
|
||||
GROUP BY t.ItemID, t.Name
|
||||
ORDER BY t.Name
|
||||
JOIN Items mi ON mi.ItemID = tl.ItemID AND mi.ItemBusinessID = :bizId
|
||||
GROUP BY t.ItemID, t.ItemName
|
||||
ORDER BY t.ItemName
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
allTemplates = [];
|
||||
for (row in qAllTemplateUsage) {
|
||||
arrayAppend(allTemplates, {
|
||||
"TemplateID": row.ID,
|
||||
"TemplateName": row.Name,
|
||||
"TemplateID": row.ItemID,
|
||||
"TemplateName": row.ItemName,
|
||||
"UsageCount": row.UsageCount
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,41 +7,41 @@ bizId = 27;
|
|||
|
||||
// Get the template items themselves
|
||||
qTemplates = queryExecute("
|
||||
SELECT ID, Name, IsCollapsible, IsActive, ParentItemID, BusinessID
|
||||
SELECT ItemID, ItemName, ItemIsCollapsible, ItemIsActive, ItemParentItemID, ItemBusinessID
|
||||
FROM Items
|
||||
WHERE ID IN (11267, 11251, 11246, 11224, 11233, 11230, 11240, 11243, 11237, 11227)
|
||||
ORDER BY Name
|
||||
WHERE ItemID IN (11267, 11251, 11246, 11224, 11233, 11230, 11240, 11243, 11237, 11227)
|
||||
ORDER BY ItemName
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
templates = [];
|
||||
for (row in qTemplates) {
|
||||
arrayAppend(templates, {
|
||||
"ItemID": row.ID,
|
||||
"Name": row.Name,
|
||||
"IsCollapsible": row.IsCollapsible,
|
||||
"IsActive": row.IsActive,
|
||||
"ParentID": row.ParentItemID,
|
||||
"BusinessID": row.BusinessID
|
||||
"ItemID": row.ItemID,
|
||||
"ItemName": row.ItemName,
|
||||
"IsCollapsible": row.ItemIsCollapsible,
|
||||
"IsActive": row.ItemIsActive,
|
||||
"ParentID": row.ItemParentItemID,
|
||||
"BusinessID": row.ItemBusinessID
|
||||
});
|
||||
}
|
||||
|
||||
// What templates are used by burgers vs all items?
|
||||
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
|
||||
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
|
||||
WHERE mi.BusinessID = :bizId
|
||||
AND mi.ParentItemID = 11271
|
||||
GROUP BY mi.ID, mi.Name
|
||||
ORDER BY mi.Name
|
||||
WHERE mi.ItemBusinessID = :bizId
|
||||
AND mi.ItemParentItemID = 11271
|
||||
GROUP BY mi.ItemID, mi.ItemName
|
||||
ORDER BY mi.ItemName
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
burgerLinks = [];
|
||||
for (row in qBurgerLinks) {
|
||||
arrayAppend(burgerLinks, {
|
||||
"ItemID": row.ID,
|
||||
"Name": row.Name,
|
||||
"ItemID": row.ItemID,
|
||||
"ItemName": row.ItemName,
|
||||
"Templates": row.Templates
|
||||
});
|
||||
}
|
||||
|
|
@ -49,20 +49,20 @@ for (row in qBurgerLinks) {
|
|||
// Also check: are there templates that SHOULD be linked to burgers?
|
||||
// (e.g., Add Cheese, etc.)
|
||||
qCheeseTemplate = queryExecute("
|
||||
SELECT ID, Name, ParentItemID, IsActive
|
||||
SELECT ItemID, ItemName, ItemParentItemID, ItemIsActive
|
||||
FROM Items
|
||||
WHERE BusinessID = :bizId
|
||||
AND Name LIKE '%Cheese%'
|
||||
ORDER BY Name
|
||||
WHERE ItemBusinessID = :bizId
|
||||
AND ItemName LIKE '%Cheese%'
|
||||
ORDER BY ItemName
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
cheeseItems = [];
|
||||
for (row in qCheeseTemplate) {
|
||||
arrayAppend(cheeseItems, {
|
||||
"ItemID": row.ID,
|
||||
"Name": row.Name,
|
||||
"ParentID": row.ParentItemID,
|
||||
"IsActive": row.IsActive
|
||||
"ItemID": row.ItemID,
|
||||
"ItemName": row.ItemName,
|
||||
"ParentID": row.ItemParentItemID,
|
||||
"IsActive": row.ItemIsActive
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,36 +26,36 @@
|
|||
<cftry>
|
||||
<!--- Get raw employee records --- >
|
||||
<cfset qEmployees = queryExecute("
|
||||
SELECT e.*, b.Name
|
||||
FROM Employees e
|
||||
INNER JOIN Businesses b ON b.ID = e.BusinessID
|
||||
SELECT e.*, b.BusinessName
|
||||
FROM lt_Users_Businesses_Employees e
|
||||
INNER JOIN Businesses b ON b.BusinessID = e.BusinessID
|
||||
WHERE e.UserID = ?
|
||||
ORDER BY b.Name ASC
|
||||
ORDER BY b.BusinessName ASC
|
||||
", [ { value = UserID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })>
|
||||
|
||||
<cfset employees = []>
|
||||
<cfloop query="qEmployees">
|
||||
<cfset arrayAppend(employees, {
|
||||
"EmployeeID": qEmployees.ID,
|
||||
"EmployeeID": qEmployees.EmployeeID,
|
||||
"UserID": qEmployees.UserID,
|
||||
"BusinessID": qEmployees.BusinessID,
|
||||
"Name": qEmployees.Name,
|
||||
"IsActive": qEmployees.IsActive
|
||||
"BusinessName": qEmployees.BusinessName,
|
||||
"EmployeeIsActive": qEmployees.EmployeeIsActive
|
||||
})>
|
||||
</cfloop>
|
||||
|
||||
<!--- Check for duplicate businesses --- >
|
||||
<cfset qDuplicates = queryExecute("
|
||||
SELECT Name, COUNT(*) AS cnt
|
||||
SELECT BusinessName, COUNT(*) AS cnt
|
||||
FROM Businesses
|
||||
GROUP BY Name
|
||||
GROUP BY BusinessName
|
||||
HAVING COUNT(*) > 1
|
||||
", [], { datasource = "payfrit" })>
|
||||
|
||||
<cfset duplicates = []>
|
||||
<cfloop query="qDuplicates">
|
||||
<cfset arrayAppend(duplicates, {
|
||||
"Name": qDuplicates.Name,
|
||||
"BusinessName": qDuplicates.BusinessName,
|
||||
"Count": qDuplicates.cnt
|
||||
})>
|
||||
</cfloop>
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ try {
|
|||
messages = [];
|
||||
for (row in qAll) {
|
||||
arrayAppend(messages, {
|
||||
"MessageID": row.ID,
|
||||
"MessageID": row.MessageID,
|
||||
"TaskID": row.TaskID,
|
||||
"SenderUserID": row.SenderUserID,
|
||||
"SenderType": row.SenderType,
|
||||
"MessageBody": left(row.MessageBody, 100),
|
||||
"MessageText": left(row.MessageText, 100),
|
||||
"CreatedOn": row.CreatedOn
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,54 +10,54 @@ response = { "OK": true };
|
|||
try {
|
||||
// Get Fountain Drinks item
|
||||
qFountain = queryExecute("
|
||||
SELECT ID, Name, ParentItemID, Price, IsCollapsible, RequiresChildSelection
|
||||
SELECT ItemID, ItemName, ItemParentItemID, ItemPrice, ItemIsCollapsible, ItemRequiresChildSelection
|
||||
FROM Items
|
||||
WHERE BusinessID = 17 AND Name LIKE '%Fountain%'
|
||||
WHERE ItemBusinessID = 17 AND ItemName LIKE '%Fountain%'
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
response["FountainDrinks"] = [];
|
||||
for (row in qFountain) {
|
||||
fountainItem = {
|
||||
"ItemID": row.ID,
|
||||
"Name": row.Name,
|
||||
"Price": row.Price,
|
||||
"IsCollapsible": row.IsCollapsible,
|
||||
"RequiresChildSelection": row.RequiresChildSelection,
|
||||
"ItemID": row.ItemID,
|
||||
"ItemName": row.ItemName,
|
||||
"ItemPrice": row.ItemPrice,
|
||||
"ItemIsCollapsible": row.ItemIsCollapsible,
|
||||
"ItemRequiresChildSelection": row.ItemRequiresChildSelection,
|
||||
"Children": []
|
||||
};
|
||||
|
||||
// Get children of this item
|
||||
qChildren = queryExecute("
|
||||
SELECT ID, Name, ParentItemID, Price, IsCollapsible, RequiresChildSelection, IsCheckedByDefault
|
||||
SELECT ItemID, ItemName, ItemParentItemID, ItemPrice, ItemIsCollapsible, ItemRequiresChildSelection, ItemIsCheckedByDefault
|
||||
FROM Items
|
||||
WHERE ParentItemID = :parentId
|
||||
ORDER BY SortOrder
|
||||
", { parentId: row.ID }, { datasource: "payfrit" });
|
||||
WHERE ItemParentItemID = :parentId
|
||||
ORDER BY ItemSortOrder
|
||||
", { parentId: row.ItemID }, { datasource: "payfrit" });
|
||||
|
||||
for (child in qChildren) {
|
||||
childItem = {
|
||||
"ItemID": child.ItemID,
|
||||
"Name": child.Name,
|
||||
"Price": child.Price,
|
||||
"IsCollapsible": child.IsCollapsible,
|
||||
"IsCheckedByDefault": child.IsCheckedByDefault,
|
||||
"ItemName": child.ItemName,
|
||||
"ItemPrice": child.ItemPrice,
|
||||
"ItemIsCollapsible": child.ItemIsCollapsible,
|
||||
"ItemIsCheckedByDefault": child.ItemIsCheckedByDefault,
|
||||
"Grandchildren": []
|
||||
};
|
||||
|
||||
// Get grandchildren
|
||||
qGrandchildren = queryExecute("
|
||||
SELECT ID, Name, Price, IsCheckedByDefault
|
||||
SELECT ItemID, ItemName, ItemPrice, ItemIsCheckedByDefault
|
||||
FROM Items
|
||||
WHERE ParentItemID = :parentId
|
||||
ORDER BY SortOrder
|
||||
WHERE ItemParentItemID = :parentId
|
||||
ORDER BY ItemSortOrder
|
||||
", { parentId: child.ItemID }, { datasource: "payfrit" });
|
||||
|
||||
for (gc in qGrandchildren) {
|
||||
arrayAppend(childItem.Grandchildren, {
|
||||
"ItemID": gc.ItemID,
|
||||
"Name": gc.Name,
|
||||
"Price": gc.Price,
|
||||
"IsCheckedByDefault": gc.IsCheckedByDefault
|
||||
"ItemName": gc.ItemName,
|
||||
"ItemPrice": gc.ItemPrice,
|
||||
"ItemIsCheckedByDefault": gc.ItemIsCheckedByDefault
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@ if (structKeyExists(data, "Phone") && len(data.Phone)) {
|
|||
phone = reReplace(data.Phone, "[^0-9]", "", "all");
|
||||
|
||||
qUser = queryExecute("
|
||||
SELECT ID, FirstName, LastName, EmailAddress, ContactNumber
|
||||
SELECT UserID, UserFirstName, UserLastName, UserEmailAddress, UserContactNumber
|
||||
FROM Users
|
||||
WHERE REPLACE(REPLACE(REPLACE(ContactNumber, '-', ''), '(', ''), ')', '') LIKE ?
|
||||
OR ContactNumber LIKE ?
|
||||
WHERE REPLACE(REPLACE(REPLACE(UserContactNumber, '-', ''), '(', ''), ')', '') LIKE ?
|
||||
OR UserContactNumber LIKE ?
|
||||
", [
|
||||
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" },
|
||||
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" }
|
||||
|
|
@ -28,35 +28,35 @@ if (structKeyExists(data, "Phone") && len(data.Phone)) {
|
|||
abort;
|
||||
}
|
||||
|
||||
userId = qUser.ID;
|
||||
userId = qUser.UserID;
|
||||
|
||||
qEmployees = queryExecute("
|
||||
SELECT e.ID, e.BusinessID, e.StatusID,
|
||||
CAST(e.IsActive AS UNSIGNED) AS IsActive,
|
||||
b.Name
|
||||
FROM Employees e
|
||||
JOIN Businesses b ON e.BusinessID = b.ID
|
||||
SELECT e.EmployeeID, e.BusinessID, e.EmployeeStatusID,
|
||||
CAST(e.EmployeeIsActive AS UNSIGNED) AS EmployeeIsActive,
|
||||
b.BusinessName
|
||||
FROM lt_Users_Businesses_Employees e
|
||||
JOIN Businesses b ON e.BusinessID = b.BusinessID
|
||||
WHERE e.UserID = ?
|
||||
", [{ value: userId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
||||
|
||||
employees = [];
|
||||
for (row in qEmployees) {
|
||||
arrayAppend(employees, {
|
||||
"EmployeeID": row.ID,
|
||||
"EmployeeID": row.EmployeeID,
|
||||
"BusinessID": row.BusinessID,
|
||||
"Name": row.Name,
|
||||
"StatusID": row.StatusID,
|
||||
"IsActive": row.IsActive
|
||||
"BusinessName": row.BusinessName,
|
||||
"StatusID": row.EmployeeStatusID,
|
||||
"IsActive": row.EmployeeIsActive
|
||||
});
|
||||
}
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
"OK": true,
|
||||
"USER": {
|
||||
"UserID": qUser.ID,
|
||||
"Name": trim(qUser.FirstName & " " & qUser.LastName),
|
||||
"Email": qUser.EmailAddress,
|
||||
"Phone": qUser.ContactNumber
|
||||
"UserID": qUser.UserID,
|
||||
"Name": trim(qUser.UserFirstName & " " & qUser.UserLastName),
|
||||
"Email": qUser.UserEmailAddress,
|
||||
"Phone": qUser.UserContactNumber
|
||||
},
|
||||
"EMPLOYEES": employees
|
||||
}));
|
||||
|
|
@ -67,23 +67,23 @@ if (structKeyExists(data, "Phone") && len(data.Phone)) {
|
|||
businessId = structKeyExists(data, "BusinessID") ? val(data.BusinessID) : 17;
|
||||
|
||||
q = queryExecute("
|
||||
SELECT ID, UserID, StatusID, IsActive,
|
||||
CAST(IsActive AS UNSIGNED) AS IsActiveInt
|
||||
FROM Employees
|
||||
SELECT EmployeeID, UserID, EmployeeStatusID, EmployeeIsActive,
|
||||
CAST(EmployeeIsActive AS UNSIGNED) AS IsActiveInt
|
||||
FROM lt_Users_Businesses_Employees
|
||||
WHERE BusinessID = ?
|
||||
", [{ value: businessId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
||||
|
||||
rows = [];
|
||||
for (r in q) {
|
||||
arrayAppend(rows, {
|
||||
"EmployeeID": r.ID,
|
||||
"EmployeeID": r.EmployeeID,
|
||||
"UserID": r.UserID,
|
||||
"StatusID": r.StatusID,
|
||||
"RawIsActive": r.IsActive,
|
||||
"StatusID": r.EmployeeStatusID,
|
||||
"RawIsActive": r.EmployeeIsActive,
|
||||
"CastIsActive": r.IsActiveInt,
|
||||
"ValRaw": val(r.IsActive),
|
||||
"ValRaw": val(r.EmployeeIsActive),
|
||||
"ValCast": val(r.IsActiveInt),
|
||||
"EqRaw1": r.IsActive == 1,
|
||||
"EqRaw1": r.EmployeeIsActive == 1,
|
||||
"EqCast1": r.IsActiveInt == 1
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ try {
|
|||
// Close all open chats action
|
||||
if (structKeyExists(data, "action") && data.action == "closeAllChats") {
|
||||
queryExecute("
|
||||
UPDATE Tasks SET CompletedOn = NOW()
|
||||
WHERE TaskTypeID = 2 AND CompletedOn IS NULL
|
||||
UPDATE Tasks SET TaskCompletedOn = NOW()
|
||||
WHERE TaskTypeID = 2 AND TaskCompletedOn IS NULL
|
||||
", {}, { datasource: "payfrit" });
|
||||
writeOutput(serializeJSON({ "OK": true, "MESSAGE": "All open chats closed" }));
|
||||
abort;
|
||||
|
|
@ -24,38 +24,38 @@ if (structKeyExists(data, "action") && data.action == "closeAllChats") {
|
|||
<cftry>
|
||||
<cfset qTasks = queryExecute("
|
||||
SELECT
|
||||
t.ID,
|
||||
t.BusinessID,
|
||||
t.OrderID,
|
||||
t.ClaimedByUserID,
|
||||
t.ClaimedOn,
|
||||
t.CompletedOn,
|
||||
o.StatusID
|
||||
t.TaskID,
|
||||
t.TaskBusinessID,
|
||||
t.TaskOrderID,
|
||||
t.TaskClaimedByUserID,
|
||||
t.TaskClaimedOn,
|
||||
t.TaskCompletedOn,
|
||||
o.OrderStatusID
|
||||
FROM Tasks t
|
||||
LEFT JOIN Orders o ON o.ID = t.OrderID
|
||||
ORDER BY t.ID DESC
|
||||
LEFT JOIN Orders o ON o.OrderID = t.TaskOrderID
|
||||
ORDER BY t.TaskID DESC
|
||||
LIMIT 20
|
||||
", [], { datasource = "payfrit" })>
|
||||
|
||||
<cfset tasks = []>
|
||||
<cfloop query="qTasks">
|
||||
<cfset arrayAppend(tasks, {
|
||||
"TaskID": qTasks.ID,
|
||||
"BusinessID": qTasks.BusinessID,
|
||||
"OrderID": qTasks.OrderID,
|
||||
"ClaimedByUserID": qTasks.ClaimedByUserID,
|
||||
"ClaimedOn": isNull(qTasks.ClaimedOn) ? "NULL" : dateTimeFormat(qTasks.ClaimedOn, "yyyy-mm-dd HH:nn:ss"),
|
||||
"CompletedOn": isNull(qTasks.CompletedOn) ? "NULL" : dateTimeFormat(qTasks.CompletedOn, "yyyy-mm-dd HH:nn:ss"),
|
||||
"StatusID": isNull(qTasks.StatusID) ? "NULL" : qTasks.StatusID
|
||||
"TaskID": qTasks.TaskID,
|
||||
"TaskBusinessID": qTasks.TaskBusinessID,
|
||||
"TaskOrderID": qTasks.TaskOrderID,
|
||||
"TaskClaimedByUserID": qTasks.TaskClaimedByUserID,
|
||||
"TaskClaimedOn": isNull(qTasks.TaskClaimedOn) ? "NULL" : dateTimeFormat(qTasks.TaskClaimedOn, "yyyy-mm-dd HH:nn:ss"),
|
||||
"TaskCompletedOn": isNull(qTasks.TaskCompletedOn) ? "NULL" : dateTimeFormat(qTasks.TaskCompletedOn, "yyyy-mm-dd HH:nn:ss"),
|
||||
"OrderStatusID": isNull(qTasks.OrderStatusID) ? "NULL" : qTasks.OrderStatusID
|
||||
})>
|
||||
</cfloop>
|
||||
|
||||
<cfset qStats = queryExecute("
|
||||
SELECT
|
||||
COUNT(*) as Total,
|
||||
SUM(CASE WHEN ClaimedByUserID > 0 AND CompletedOn 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 CompletedOn IS NOT NULL THEN 1 ELSE 0 END) as Completed
|
||||
SUM(CASE WHEN TaskClaimedByUserID > 0 AND TaskCompletedOn IS NULL THEN 1 ELSE 0 END) as ClaimedNotCompleted,
|
||||
SUM(CASE WHEN TaskClaimedByUserID = 0 OR TaskClaimedByUserID IS NULL THEN 1 ELSE 0 END) as Unclaimed,
|
||||
SUM(CASE WHEN TaskCompletedOn IS NOT NULL THEN 1 ELSE 0 END) as Completed
|
||||
FROM Tasks
|
||||
", [], { datasource = "payfrit" })>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,19 +4,19 @@
|
|||
|
||||
<cftry>
|
||||
<cfset qAll = queryExecute("
|
||||
SELECT ID, ClaimedByUserID, CompletedOn, OrderID,
|
||||
CASE WHEN CompletedOn IS NULL THEN 'YES_NULL' ELSE 'NOT_NULL' END AS IsNull
|
||||
SELECT TaskID, TaskClaimedByUserID, TaskCompletedOn, TaskOrderID,
|
||||
CASE WHEN TaskCompletedOn IS NULL THEN 'YES_NULL' ELSE 'NOT_NULL' END AS IsNull
|
||||
FROM Tasks
|
||||
ORDER BY ID DESC
|
||||
ORDER BY TaskID DESC
|
||||
", [], { datasource = "payfrit" })>
|
||||
|
||||
<cfset tasks = []>
|
||||
<cfloop query="qAll">
|
||||
<cfset arrayAppend(tasks, {
|
||||
"TaskID": qAll.ID,
|
||||
"ClaimedByUserID": qAll.ClaimedByUserID,
|
||||
"OrderID": qAll.OrderID,
|
||||
"CompletedOn": len(trim(qAll.CompletedOn)) ? toString(qAll.CompletedOn) : "",
|
||||
"TaskID": qAll.TaskID,
|
||||
"TaskClaimedByUserID": qAll.TaskClaimedByUserID,
|
||||
"TaskOrderID": qAll.TaskOrderID,
|
||||
"TaskCompletedOn": len(trim(qAll.TaskCompletedOn)) ? toString(qAll.TaskCompletedOn) : "",
|
||||
"IsNull": qAll.IsNull
|
||||
})>
|
||||
</cfloop>
|
||||
|
|
|
|||
|
|
@ -3,39 +3,39 @@
|
|||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
|
||||
<cfscript>
|
||||
// Check lt_ItemID_TemplateItemID for Big Dean's (BusinessID 27)
|
||||
// Check ItemTemplateLinks for Big Dean's (BusinessID 27)
|
||||
bizId = 27;
|
||||
|
||||
// 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
|
||||
qTemplates = queryExecute("
|
||||
SELECT DISTINCT tl.TemplateItemID, i.Name
|
||||
FROM lt_ItemID_TemplateItemID tl
|
||||
JOIN Items i ON i.ID = tl.TemplateItemID
|
||||
WHERE i.BusinessID = :bizId
|
||||
SELECT DISTINCT tl.TemplateItemID, i.ItemName
|
||||
FROM ItemTemplateLinks tl
|
||||
JOIN Items i ON i.ItemID = tl.TemplateItemID
|
||||
WHERE i.ItemBusinessID = :bizId
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
templates = [];
|
||||
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)
|
||||
qCategories = queryExecute("
|
||||
SELECT i.ID, i.Name, i.ParentItemID, i.IsCollapsible
|
||||
SELECT i.ItemID, i.ItemName, i.ItemParentItemID, i.ItemIsCollapsible
|
||||
FROM Items i
|
||||
WHERE i.BusinessID = :bizId
|
||||
AND i.ParentItemID = 0
|
||||
AND i.IsCollapsible = 0
|
||||
AND NOT EXISTS (SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = i.ID)
|
||||
ORDER BY i.SortOrder
|
||||
WHERE i.ItemBusinessID = :bizId
|
||||
AND i.ItemParentItemID = 0
|
||||
AND i.ItemIsCollapsible = 0
|
||||
AND NOT EXISTS (SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = i.ItemID)
|
||||
ORDER BY i.ItemSortOrder
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
categories = [];
|
||||
for (row in qCategories) {
|
||||
arrayAppend(categories, { "ItemID": row.ID, "Name": row.Name });
|
||||
arrayAppend(categories, { "ItemID": row.ItemID, "ItemName": row.ItemName });
|
||||
}
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ if (len(phone) == 0) {
|
|||
|
||||
// Find user by phone
|
||||
qUser = queryExecute("
|
||||
SELECT ID, FirstName, LastName, EmailAddress, ContactNumber
|
||||
SELECT UserID, UserFirstName, UserLastName, UserEmailAddress, UserContactNumber
|
||||
FROM Users
|
||||
WHERE REPLACE(REPLACE(REPLACE(ContactNumber, '-', ''), '(', ''), ')', '') LIKE ?
|
||||
OR ContactNumber LIKE ?
|
||||
WHERE REPLACE(REPLACE(REPLACE(UserContactNumber, '-', ''), '(', ''), ')', '') LIKE ?
|
||||
OR UserContactNumber LIKE ?
|
||||
", [
|
||||
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" },
|
||||
{ value: "%" & phone & "%", cfsqltype: "cf_sql_varchar" }
|
||||
|
|
@ -34,36 +34,36 @@ if (qUser.recordCount == 0) {
|
|||
abort;
|
||||
}
|
||||
|
||||
userId = qUser.ID;
|
||||
userId = qUser.UserID;
|
||||
|
||||
// Get all employee records for this user
|
||||
qEmployees = queryExecute("
|
||||
SELECT e.ID, e.BusinessID, e.StatusID,
|
||||
CAST(e.IsActive AS UNSIGNED) AS IsActive,
|
||||
b.Name
|
||||
FROM Employees e
|
||||
JOIN Businesses b ON e.BusinessID = b.ID
|
||||
SELECT e.EmployeeID, e.BusinessID, e.EmployeeStatusID,
|
||||
CAST(e.EmployeeIsActive AS UNSIGNED) AS EmployeeIsActive,
|
||||
b.BusinessName
|
||||
FROM lt_Users_Businesses_Employees e
|
||||
JOIN Businesses b ON e.BusinessID = b.BusinessID
|
||||
WHERE e.UserID = ?
|
||||
", [{ value: userId, cfsqltype: "cf_sql_integer" }], { datasource: "payfrit" });
|
||||
|
||||
employees = [];
|
||||
for (row in qEmployees) {
|
||||
arrayAppend(employees, {
|
||||
"EmployeeID": row.ID,
|
||||
"EmployeeID": row.EmployeeID,
|
||||
"BusinessID": row.BusinessID,
|
||||
"Name": row.Name,
|
||||
"StatusID": row.StatusID,
|
||||
"IsActive": row.IsActive
|
||||
"BusinessName": row.BusinessName,
|
||||
"StatusID": row.EmployeeStatusID,
|
||||
"IsActive": row.EmployeeIsActive
|
||||
});
|
||||
}
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
"OK": true,
|
||||
"USER": {
|
||||
"UserID": qUser.ID,
|
||||
"Name": trim(qUser.FirstName & " " & qUser.LastName),
|
||||
"Email": qUser.EmailAddress,
|
||||
"Phone": qUser.ContactNumber
|
||||
"UserID": qUser.UserID,
|
||||
"Name": trim(qUser.UserFirstName & " " & qUser.UserLastName),
|
||||
"Email": qUser.UserEmailAddress,
|
||||
"Phone": qUser.UserContactNumber
|
||||
},
|
||||
"EMPLOYEES": employees
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -28,19 +28,19 @@ try {
|
|||
response["ERROR"] = "BusinessID required";
|
||||
} else {
|
||||
// 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) {
|
||||
response["ERROR"] = "Business not found";
|
||||
} else {
|
||||
addrID = qBiz.AddressID;
|
||||
addrID = qBiz.BusinessAddressID;
|
||||
|
||||
// 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
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
* Delete Orphan Modifiers for In and Out Burger (BusinessID=17)
|
||||
*
|
||||
* 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)
|
||||
* that have been replaced by template links.
|
||||
|
|
@ -29,18 +29,18 @@ try {
|
|||
qOrphans = queryExecute("
|
||||
SELECT
|
||||
m.ItemID,
|
||||
m.Name,
|
||||
m.ParentItemID,
|
||||
p.Name as ParentName
|
||||
m.ItemName,
|
||||
m.ItemParentItemID,
|
||||
p.ItemName as ParentName
|
||||
FROM Items m
|
||||
INNER JOIN Items p ON p.ItemID = m.ParentItemID
|
||||
INNER JOIN Categories c ON c.ID = p.CategoryID
|
||||
WHERE c.BusinessID = :businessID
|
||||
AND m.ParentItemID > 0
|
||||
AND p.ParentItemID = 0
|
||||
AND (m.IsModifierTemplate IS NULL OR m.IsModifierTemplate = 0)
|
||||
AND m.IsActive = 1
|
||||
ORDER BY m.Name
|
||||
INNER JOIN Items p ON p.ItemID = m.ItemParentItemID
|
||||
INNER JOIN Categories c ON c.CategoryID = p.ItemCategoryID
|
||||
WHERE c.CategoryBusinessID = :businessID
|
||||
AND m.ItemParentItemID > 0
|
||||
AND p.ItemParentItemID = 0
|
||||
AND (m.ItemIsModifierTemplate IS NULL OR m.ItemIsModifierTemplate = 0)
|
||||
AND m.ItemIsActive = 1
|
||||
ORDER BY m.ItemName
|
||||
", { businessID: businessID }, { datasource: "payfrit" });
|
||||
|
||||
arrayAppend(response.deleted, "Found " & qOrphans.recordCount & " orphan modifiers to delete");
|
||||
|
|
@ -50,23 +50,23 @@ try {
|
|||
try {
|
||||
// Delete children of this orphan (options within the modifier group)
|
||||
qDeleteChildren = queryExecute("
|
||||
DELETE FROM Items WHERE ParentItemID = :orphanID
|
||||
DELETE FROM Items WHERE ItemParentItemID = :orphanID
|
||||
", { orphanID: orphan.ItemID }, { datasource: "payfrit" });
|
||||
|
||||
// Delete the orphan itself
|
||||
qDeleteOrphan = queryExecute("
|
||||
DELETE FROM Items WHERE ID = :orphanID
|
||||
DELETE FROM Items WHERE ItemID = :orphanID
|
||||
", { orphanID: orphan.ItemID }, { datasource: "payfrit" });
|
||||
|
||||
arrayAppend(response.deleted, {
|
||||
"ItemID": orphan.ItemID,
|
||||
"Name": orphan.Name,
|
||||
"ItemName": orphan.ItemName,
|
||||
"WasUnder": orphan.ParentName
|
||||
});
|
||||
} catch (any deleteErr) {
|
||||
arrayAppend(response.errors, {
|
||||
"ItemID": orphan.ItemID,
|
||||
"Name": orphan.Name,
|
||||
"ItemName": orphan.ItemName,
|
||||
"Error": deleteErr.message
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<cfscript>
|
||||
/**
|
||||
* 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": [] };
|
||||
|
|
@ -19,24 +19,24 @@ response = { "OK": false, "deleted": 0, "orphans": [] };
|
|||
try {
|
||||
// Find orphans
|
||||
qOrphans = queryExecute("
|
||||
SELECT i.ID, i.Name, i.BusinessID
|
||||
SELECT i.ItemID, i.ItemName, i.ItemBusinessID
|
||||
FROM Items i
|
||||
WHERE i.ParentItemID = 0
|
||||
WHERE i.ItemParentItemID = 0
|
||||
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 (
|
||||
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" });
|
||||
|
||||
orphanIDs = [];
|
||||
for (orphan in qOrphans) {
|
||||
arrayAppend(response.orphans, {
|
||||
"ItemID": orphan.ItemID,
|
||||
"Name": orphan.Name,
|
||||
"BusinessID": orphan.BusinessID
|
||||
"ItemName": orphan.ItemName,
|
||||
"BusinessID": orphan.ItemBusinessID
|
||||
});
|
||||
arrayAppend(orphanIDs, orphan.ItemID);
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ try {
|
|||
// Delete them by ID list
|
||||
if (arrayLen(orphanIDs) > 0) {
|
||||
queryExecute("
|
||||
DELETE FROM Items WHERE ID IN (#arrayToList(orphanIDs)#)
|
||||
DELETE FROM Items WHERE ItemID IN (#arrayToList(orphanIDs)#)
|
||||
", {}, { datasource: "payfrit" });
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,16 +14,16 @@
|
|||
* Eliminate Categories Table - Schema Migration
|
||||
*
|
||||
* 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)
|
||||
* - 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)
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
|
|
@ -34,30 +34,30 @@ try {
|
|||
dryRun = structKeyExists(url, "dryRun") && url.dryRun == 1;
|
||||
response["dryRun"] = dryRun;
|
||||
|
||||
// Step 1: Add BusinessID column if it doesn't exist
|
||||
// Step 1: Add ItemBusinessID column if it doesn't exist
|
||||
try {
|
||||
if (!dryRun) {
|
||||
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" });
|
||||
}
|
||||
arrayAppend(response.steps, "Added BusinessID column to Items table");
|
||||
arrayAppend(response.steps, "Added ItemBusinessID column to Items table");
|
||||
} catch (any e) {
|
||||
if (findNoCase("Duplicate column", e.message)) {
|
||||
arrayAppend(response.steps, "BusinessID column already exists");
|
||||
arrayAppend(response.steps, "ItemBusinessID column already exists");
|
||||
} else {
|
||||
throw(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Add index on BusinessID
|
||||
// Step 2: Add index on ItemBusinessID
|
||||
try {
|
||||
if (!dryRun) {
|
||||
queryExecute("
|
||||
CREATE INDEX idx_item_business ON Items (BusinessID)
|
||||
CREATE INDEX idx_item_business ON Items (ItemBusinessID)
|
||||
", {}, { datasource: "payfrit" });
|
||||
}
|
||||
arrayAppend(response.steps, "Added index on BusinessID");
|
||||
arrayAppend(response.steps, "Added index on ItemBusinessID");
|
||||
} catch (any e) {
|
||||
if (findNoCase("Duplicate key name", e.message)) {
|
||||
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 {
|
||||
if (!dryRun) {
|
||||
queryExecute("
|
||||
|
|
@ -84,9 +84,9 @@ try {
|
|||
|
||||
// Step 4: Get all Categories
|
||||
qCategories = queryExecute("
|
||||
SELECT ID, BusinessID, Name
|
||||
SELECT CategoryID, CategoryBusinessID, CategoryName
|
||||
FROM Categories
|
||||
ORDER BY BusinessID, Name
|
||||
ORDER BY CategoryBusinessID, CategoryName
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
arrayAppend(response.steps, "Found " & qCategories.recordCount & " categories to migrate");
|
||||
|
|
@ -94,29 +94,29 @@ try {
|
|||
// Step 4: Migrate each category
|
||||
for (cat in qCategories) {
|
||||
migration = {
|
||||
"oldCategoryID": cat.ID,
|
||||
"categoryName": cat.Name,
|
||||
"businessID": cat.BusinessID,
|
||||
"oldCategoryID": cat.CategoryID,
|
||||
"categoryName": cat.CategoryName,
|
||||
"businessID": cat.CategoryBusinessID,
|
||||
"newItemID": 0,
|
||||
"itemsUpdated": 0
|
||||
};
|
||||
|
||||
if (!dryRun) {
|
||||
// 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("
|
||||
INSERT INTO Items (
|
||||
BusinessID,
|
||||
CategoryID,
|
||||
Name,
|
||||
Description,
|
||||
ParentItemID,
|
||||
Price,
|
||||
IsActive,
|
||||
IsCheckedByDefault,
|
||||
RequiresChildSelection,
|
||||
SortOrder,
|
||||
AddedOn
|
||||
ItemBusinessID,
|
||||
ItemCategoryID,
|
||||
ItemName,
|
||||
ItemDescription,
|
||||
ItemParentItemID,
|
||||
ItemPrice,
|
||||
ItemIsActive,
|
||||
ItemIsCheckedByDefault,
|
||||
ItemRequiresChildSelection,
|
||||
ItemSortOrder,
|
||||
ItemAddedOn
|
||||
) VALUES (
|
||||
:businessID,
|
||||
0,
|
||||
|
|
@ -131,56 +131,56 @@ try {
|
|||
NOW()
|
||||
)
|
||||
", {
|
||||
businessID: cat.BusinessID,
|
||||
categoryName: cat.Name
|
||||
businessID: cat.CategoryBusinessID,
|
||||
categoryName: cat.CategoryName
|
||||
}, { datasource: "payfrit" });
|
||||
|
||||
// Get the new Item ID
|
||||
qNewItem = queryExecute("
|
||||
SELECT ID FROM Items
|
||||
WHERE BusinessID = :businessID
|
||||
AND Name = :categoryName
|
||||
AND ParentItemID = 0
|
||||
ORDER BY ID DESC
|
||||
SELECT ItemID FROM Items
|
||||
WHERE ItemBusinessID = :businessID
|
||||
AND ItemName = :categoryName
|
||||
AND ItemParentItemID = 0
|
||||
ORDER BY ItemID DESC
|
||||
LIMIT 1
|
||||
", {
|
||||
businessID: cat.BusinessID,
|
||||
categoryName: cat.Name
|
||||
businessID: cat.CategoryBusinessID,
|
||||
categoryName: cat.CategoryName
|
||||
}, { datasource: "payfrit" });
|
||||
|
||||
newItemID = qNewItem.ID;
|
||||
newItemID = qNewItem.ItemID;
|
||||
migration["newItemID"] = newItemID;
|
||||
|
||||
// Update menu items in this category:
|
||||
// - Set ParentItemID = newItemID (for top-level items only)
|
||||
// - Set BusinessID = businessID (for all items)
|
||||
// - Set ItemParentItemID = newItemID (for top-level items only)
|
||||
// - Set ItemBusinessID = businessID (for all items)
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET BusinessID = :businessID,
|
||||
ParentItemID = :newItemID
|
||||
WHERE CategoryID = :categoryID
|
||||
AND ParentItemID = 0
|
||||
SET ItemBusinessID = :businessID,
|
||||
ItemParentItemID = :newItemID
|
||||
WHERE ItemCategoryID = :categoryID
|
||||
AND ItemParentItemID = 0
|
||||
", {
|
||||
businessID: cat.BusinessID,
|
||||
businessID: cat.CategoryBusinessID,
|
||||
newItemID: newItemID,
|
||||
categoryID: cat.ID
|
||||
categoryID: cat.CategoryID
|
||||
}, { datasource: "payfrit" });
|
||||
|
||||
// Set BusinessID on ALL items in this category (including nested)
|
||||
// Set ItemBusinessID on ALL items in this category (including nested)
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET BusinessID = :businessID
|
||||
WHERE CategoryID = :categoryID
|
||||
AND (BusinessID IS NULL OR BusinessID = 0)
|
||||
SET ItemBusinessID = :businessID
|
||||
WHERE ItemCategoryID = :categoryID
|
||||
AND (ItemBusinessID IS NULL OR ItemBusinessID = 0)
|
||||
", {
|
||||
businessID: cat.BusinessID,
|
||||
categoryID: cat.ID
|
||||
businessID: cat.CategoryBusinessID,
|
||||
categoryID: cat.CategoryID
|
||||
}, { datasource: "payfrit" });
|
||||
|
||||
// Count how many were updated
|
||||
qCount = queryExecute("
|
||||
SELECT COUNT(*) as cnt FROM Items
|
||||
WHERE ParentItemID = :newItemID
|
||||
WHERE ItemParentItemID = :newItemID
|
||||
", { newItemID: newItemID }, { datasource: "payfrit" });
|
||||
|
||||
migration["itemsUpdated"] = qCount.cnt;
|
||||
|
|
@ -188,9 +188,9 @@ try {
|
|||
// Dry run - count what would be updated
|
||||
qCount = queryExecute("
|
||||
SELECT COUNT(*) as cnt FROM Items
|
||||
WHERE CategoryID = :categoryID
|
||||
AND ParentItemID = 0
|
||||
", { categoryID: cat.ID }, { datasource: "payfrit" });
|
||||
WHERE ItemCategoryID = :categoryID
|
||||
AND ItemParentItemID = 0
|
||||
", { categoryID: cat.CategoryID }, { datasource: "payfrit" });
|
||||
|
||||
migration["itemsToUpdate"] = qCount.cnt;
|
||||
}
|
||||
|
|
@ -198,37 +198,37 @@ try {
|
|||
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
|
||||
if (!dryRun) {
|
||||
queryExecute("
|
||||
UPDATE Items t
|
||||
INNER JOIN lt_ItemID_TemplateItemID tl ON tl.TemplateItemID = t.ItemID
|
||||
INNER JOIN Items i ON i.ID = tl.ItemID
|
||||
SET t.BusinessID = i.BusinessID
|
||||
WHERE (t.BusinessID IS NULL OR t.BusinessID = 0)
|
||||
AND i.BusinessID > 0
|
||||
INNER JOIN ItemTemplateLinks tl ON tl.TemplateItemID = t.ItemID
|
||||
INNER JOIN Items i ON i.ItemID = tl.ItemID
|
||||
SET t.ItemBusinessID = i.ItemBusinessID
|
||||
WHERE (t.ItemBusinessID IS NULL OR t.ItemBusinessID = 0)
|
||||
AND i.ItemBusinessID > 0
|
||||
", {}, { 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("
|
||||
UPDATE Items c
|
||||
INNER JOIN Items t ON t.ItemID = c.ParentItemID
|
||||
SET c.BusinessID = t.BusinessID
|
||||
WHERE t.BusinessID > 0
|
||||
AND (c.BusinessID IS NULL OR c.BusinessID = 0)
|
||||
INNER JOIN Items t ON t.ItemID = c.ItemParentItemID
|
||||
SET c.ItemBusinessID = t.ItemBusinessID
|
||||
WHERE t.ItemBusinessID > 0
|
||||
AND (c.ItemBusinessID IS NULL OR c.ItemBusinessID = 0)
|
||||
", {}, { 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)
|
||||
queryExecute("
|
||||
UPDATE Items t
|
||||
INNER JOIN lt_ItemID_TemplateItemID tl ON tl.TemplateItemID = t.ItemID
|
||||
SET t.ParentItemID = 0
|
||||
WHERE t.ParentItemID != 0
|
||||
INNER JOIN ItemTemplateLinks tl ON tl.TemplateItemID = t.ItemID
|
||||
SET t.ItemParentItemID = 0
|
||||
WHERE t.ItemParentItemID != 0
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
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)
|
||||
for (itemId in fakeCategories) {
|
||||
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" });
|
||||
}
|
||||
|
||||
// Also deactivate their children (modifier options that belong to these fake parents)
|
||||
for (itemId in fakeCategories) {
|
||||
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" });
|
||||
}
|
||||
|
||||
// Now verify what categories remain
|
||||
qCategories = queryExecute("
|
||||
SELECT i.ID, i.Name
|
||||
SELECT i.ItemID, i.ItemName
|
||||
FROM Items i
|
||||
WHERE i.BusinessID = :bizId
|
||||
AND i.ParentItemID = 0
|
||||
AND i.IsActive = 1
|
||||
AND i.IsCollapsible = 0
|
||||
AND NOT EXISTS (SELECT 1 FROM lt_ItemID_TemplateItemID tl WHERE tl.TemplateItemID = i.ID)
|
||||
ORDER BY i.SortOrder
|
||||
WHERE i.ItemBusinessID = :bizId
|
||||
AND i.ItemParentItemID = 0
|
||||
AND i.ItemIsActive = 1
|
||||
AND i.ItemIsCollapsible = 0
|
||||
AND NOT EXISTS (SELECT 1 FROM ItemTemplateLinks tl WHERE tl.TemplateItemID = i.ItemID)
|
||||
ORDER BY i.ItemSortOrder
|
||||
", { bizId: bizId }, { datasource: "payfrit" });
|
||||
|
||||
categories = [];
|
||||
for (row in qCategories) {
|
||||
arrayAppend(categories, { "ItemID": row.ID, "Name": row.Name });
|
||||
arrayAppend(categories, { "ItemID": row.ItemID, "ItemName": row.ItemName });
|
||||
}
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ actions = [];
|
|||
|
||||
// First, let's see what templates already exist and are active for burgers
|
||||
qExistingLinks = queryExecute("
|
||||
SELECT tl.ItemID as MenuItemID, tl.TemplateItemID, t.Name as TemplateName
|
||||
FROM lt_ItemID_TemplateItemID tl
|
||||
SELECT tl.ItemID as MenuItemID, tl.TemplateItemID, t.ItemName as TemplateName
|
||||
FROM ItemTemplateLinks tl
|
||||
JOIN Items t ON t.ItemID = tl.TemplateItemID
|
||||
WHERE tl.ItemID IN (:burgerIds)
|
||||
", { burgerIds: { value: arrayToList(burgerIds), list: true } }, { datasource: "payfrit" });
|
||||
|
|
@ -33,8 +33,8 @@ for (row in qExistingLinks) {
|
|||
|
||||
// Reactivate template 11196 (Extras with Add Cheese)
|
||||
if (!dryRun) {
|
||||
queryExecute("UPDATE Items SET IsActive = 1 WHERE ItemID = 11196", {}, { datasource: "payfrit" });
|
||||
queryExecute("UPDATE Items SET IsActive = 1 WHERE ParentItemID = 11196", {}, { datasource: "payfrit" });
|
||||
queryExecute("UPDATE Items SET ItemIsActive = 1 WHERE ItemID = 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)" });
|
||||
|
||||
|
|
@ -42,13 +42,13 @@ arrayAppend(actions, { action: dryRun ? "WOULD_REACTIVATE" : "REACTIVATED", item
|
|||
for (burgerId in burgerIds) {
|
||||
// Check if link already exists
|
||||
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" });
|
||||
|
||||
if (qCheck.cnt EQ 0) {
|
||||
if (!dryRun) {
|
||||
queryExecute("
|
||||
INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder)
|
||||
INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder)
|
||||
VALUES (:burgerId, 11196, 2)
|
||||
", { burgerId: burgerId }, { datasource: "payfrit" });
|
||||
}
|
||||
|
|
@ -59,17 +59,17 @@ for (burgerId in burgerIds) {
|
|||
// Verify the result
|
||||
if (!dryRun) {
|
||||
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
|
||||
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
|
||||
WHERE mi.ID IN (:burgerIds)
|
||||
GROUP BY mi.ID, mi.Name
|
||||
WHERE mi.ItemID IN (:burgerIds)
|
||||
GROUP BY mi.ItemID, mi.ItemName
|
||||
", { burgerIds: { value: arrayToList(burgerIds), list: true } }, { datasource: "payfrit" });
|
||||
|
||||
result = [];
|
||||
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 {
|
||||
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
|
||||
* 3. Remove template flag from flavors
|
||||
* 4. Mark "Choose Flavor" as the template
|
||||
* 5. Create lt_ItemID_TemplateItemID entry for Shake -> Choose Flavor
|
||||
* 6. Set RequiresChildSelection=1 on the shake item
|
||||
* 5. Create ItemTemplateLinks entry for Shake -> Choose Flavor
|
||||
* 6. Set ItemRequiresChildSelection=1 on the shake item
|
||||
*/
|
||||
|
||||
response = { "OK": false, "steps": [] };
|
||||
|
|
@ -46,19 +46,19 @@ try {
|
|||
// Step 1: Create "Choose Flavor" modifier group under Shake
|
||||
queryExecute("
|
||||
INSERT INTO Items (
|
||||
CategoryID,
|
||||
Name,
|
||||
Description,
|
||||
ParentItemID,
|
||||
Price,
|
||||
IsActive,
|
||||
IsCheckedByDefault,
|
||||
RequiresChildSelection,
|
||||
MaxNumSelectionReq,
|
||||
IsCollapsible,
|
||||
SortOrder,
|
||||
IsModifierTemplate,
|
||||
AddedOn
|
||||
ItemCategoryID,
|
||||
ItemName,
|
||||
ItemDescription,
|
||||
ItemParentItemID,
|
||||
ItemPrice,
|
||||
ItemIsActive,
|
||||
ItemIsCheckedByDefault,
|
||||
ItemRequiresChildSelection,
|
||||
ItemMaxNumSelectionReq,
|
||||
ItemIsCollapsible,
|
||||
ItemSortOrder,
|
||||
ItemIsModifierTemplate,
|
||||
ItemAddedOn
|
||||
) VALUES (
|
||||
:categoryID,
|
||||
'Choose Flavor',
|
||||
|
|
@ -81,22 +81,22 @@ try {
|
|||
|
||||
// Get the new Choose Flavor ID
|
||||
qNewGroup = queryExecute("
|
||||
SELECT ID FROM Items
|
||||
WHERE Name = 'Choose Flavor'
|
||||
AND ParentItemID = :shakeItemID
|
||||
ORDER BY ID DESC
|
||||
SELECT ItemID FROM Items
|
||||
WHERE ItemName = 'Choose Flavor'
|
||||
AND ItemParentItemID = :shakeItemID
|
||||
ORDER BY ItemID DESC
|
||||
LIMIT 1
|
||||
", { shakeItemID: shakeItemID }, { datasource: "payfrit" });
|
||||
|
||||
chooseFlavorID = qNewGroup.ID;
|
||||
chooseFlavorID = qNewGroup.ItemID;
|
||||
arrayAppend(response.steps, "Created 'Choose Flavor' group with ID: " & chooseFlavorID);
|
||||
|
||||
// Step 2: Re-parent the three flavors under Choose Flavor
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET ParentItemID = :chooseFlavorID,
|
||||
IsModifierTemplate = 0,
|
||||
IsCheckedByDefault = 0
|
||||
SET ItemParentItemID = :chooseFlavorID,
|
||||
ItemIsModifierTemplate = 0,
|
||||
ItemIsCheckedByDefault = 0
|
||||
WHERE ItemID IN (:chocolateID, :strawberryID, :vanillaID)
|
||||
", {
|
||||
chooseFlavorID: chooseFlavorID,
|
||||
|
|
@ -109,14 +109,14 @@ try {
|
|||
|
||||
// Step 3: Set Vanilla as default (common choice)
|
||||
queryExecute("
|
||||
UPDATE Items SET IsCheckedByDefault = 1 WHERE ItemID = :vanillaID
|
||||
UPDATE Items SET ItemIsCheckedByDefault = 1 WHERE ItemID = :vanillaID
|
||||
", { vanillaID: vanillaID }, { datasource: "payfrit" });
|
||||
|
||||
arrayAppend(response.steps, "Set Vanilla as default flavor");
|
||||
|
||||
// Step 4: Remove old template links for the flavors
|
||||
queryExecute("
|
||||
DELETE FROM lt_ItemID_TemplateItemID
|
||||
DELETE FROM ItemTemplateLinks
|
||||
WHERE TemplateItemID IN (:chocolateID, :strawberryID, :vanillaID)
|
||||
", {
|
||||
chocolateID: chocolateID,
|
||||
|
|
@ -126,9 +126,9 @@ try {
|
|||
|
||||
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("
|
||||
INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder)
|
||||
INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder)
|
||||
VALUES (:shakeItemID, :chooseFlavorID, 0)
|
||||
ON DUPLICATE KEY UPDATE SortOrder = 0
|
||||
", {
|
||||
|
|
@ -138,14 +138,14 @@ try {
|
|||
|
||||
arrayAppend(response.steps, "Created template link: Shake -> Choose Flavor");
|
||||
|
||||
// Step 6: Set RequiresChildSelection on shake
|
||||
// Step 6: Set ItemRequiresChildSelection on shake
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET RequiresChildSelection = 1
|
||||
SET ItemRequiresChildSelection = 1
|
||||
WHERE ItemID = :shakeItemID
|
||||
", { 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["chooseFlavorID"] = chooseFlavorID;
|
||||
|
|
|
|||
|
|
@ -75,17 +75,17 @@ function buildAddressString(line1, line2, city, zipCode) {
|
|||
<cfif structKeyExists(url, "geocode") AND structKeyExists(url, "addressId")>
|
||||
<cfset addressId = val(url.addressId)>
|
||||
<cfquery name="addr" datasource="payfrit">
|
||||
SELECT Line1, Line2, City, ZIPCode
|
||||
FROM Addresses WHERE ID = <cfqueryparam value="#addressId#" cfsqltype="cf_sql_integer">
|
||||
SELECT AddressLine1, AddressLine2, AddressCity, AddressZIPCode
|
||||
FROM Addresses WHERE AddressID = <cfqueryparam value="#addressId#" cfsqltype="cf_sql_integer">
|
||||
</cfquery>
|
||||
<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)>
|
||||
<cfif geo.success>
|
||||
<cfquery datasource="payfrit">
|
||||
UPDATE Addresses SET Latitude = <cfqueryparam value="#geo.lat#" cfsqltype="cf_sql_decimal">,
|
||||
Longitude = <cfqueryparam value="#geo.lng#" cfsqltype="cf_sql_decimal">
|
||||
WHERE ID = <cfqueryparam value="#addressId#" cfsqltype="cf_sql_integer">
|
||||
UPDATE Addresses SET AddressLat = <cfqueryparam value="#geo.lat#" cfsqltype="cf_sql_decimal">,
|
||||
AddressLng = <cfqueryparam value="#geo.lng#" cfsqltype="cf_sql_decimal">
|
||||
WHERE AddressID = <cfqueryparam value="#addressId#" cfsqltype="cf_sql_integer">
|
||||
</cfquery>
|
||||
<cfoutput><div class="success">Geocoded Address ID #addressId#: #geo.lat#, #geo.lng#</div></cfoutput>
|
||||
<cfelse>
|
||||
|
|
@ -96,21 +96,21 @@ function buildAddressString(line1, line2, city, zipCode) {
|
|||
|
||||
<cfif structKeyExists(url, "geocodeAll")>
|
||||
<cfquery name="missing" datasource="payfrit">
|
||||
SELECT ID, Line1, Line2, City, ZIPCode
|
||||
SELECT AddressID, AddressLine1, AddressLine2, AddressCity, AddressZIPCode
|
||||
FROM Addresses
|
||||
WHERE (Latitude IS NULL OR Latitude = 0)
|
||||
AND Line1 IS NOT NULL AND Line1 != ''
|
||||
WHERE (AddressLat IS NULL OR AddressLat = 0)
|
||||
AND AddressLine1 IS NOT NULL AND AddressLine1 != ''
|
||||
</cfquery>
|
||||
<cfset successCount = 0>
|
||||
<cfset failCount = 0>
|
||||
<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)>
|
||||
<cfif geo.success>
|
||||
<cfquery datasource="payfrit">
|
||||
UPDATE Addresses SET Latitude = <cfqueryparam value="#geo.lat#" cfsqltype="cf_sql_decimal">,
|
||||
Longitude = <cfqueryparam value="#geo.lng#" cfsqltype="cf_sql_decimal">
|
||||
WHERE ID = <cfqueryparam value="#missing.ID#" cfsqltype="cf_sql_integer">
|
||||
UPDATE Addresses SET AddressLat = <cfqueryparam value="#geo.lat#" cfsqltype="cf_sql_decimal">,
|
||||
AddressLng = <cfqueryparam value="#geo.lng#" cfsqltype="cf_sql_decimal">
|
||||
WHERE AddressID = <cfqueryparam value="#missing.AddressID#" cfsqltype="cf_sql_integer">
|
||||
</cfquery>
|
||||
<cfset successCount = successCount + 1>
|
||||
<cfelse>
|
||||
|
|
@ -123,23 +123,23 @@ function buildAddressString(line1, line2, city, zipCode) {
|
|||
|
||||
<cfquery name="addresses" datasource="payfrit">
|
||||
SELECT
|
||||
b.ID,
|
||||
b.Name,
|
||||
a.ID,
|
||||
a.Line1,
|
||||
a.Line2,
|
||||
a.City,
|
||||
a.ZIPCode,
|
||||
a.Latitude,
|
||||
a.Longitude
|
||||
b.BusinessID,
|
||||
b.BusinessName,
|
||||
a.AddressID,
|
||||
a.AddressLine1,
|
||||
a.AddressLine2,
|
||||
a.AddressCity,
|
||||
a.AddressZIPCode,
|
||||
a.AddressLat,
|
||||
a.AddressLng
|
||||
FROM Businesses b
|
||||
LEFT JOIN Addresses a ON b.AddressID = a.ID
|
||||
ORDER BY b.Name
|
||||
LEFT JOIN Addresses a ON b.BusinessAddressID = a.AddressID
|
||||
ORDER BY b.BusinessName
|
||||
</cfquery>
|
||||
|
||||
<cfset missingCount = 0>
|
||||
<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>
|
||||
</cfif>
|
||||
</cfloop>
|
||||
|
|
@ -166,31 +166,31 @@ function buildAddressString(line1, line2, city, zipCode) {
|
|||
<cfloop query="addresses">
|
||||
<tr>
|
||||
<td>
|
||||
#addresses.Name#
|
||||
<cfif len(addresses.Latitude) AND val(addresses.Latitude) NEQ 0>
|
||||
#addresses.BusinessName#
|
||||
<cfif len(addresses.AddressLat) AND val(addresses.AddressLat) NEQ 0>
|
||||
<span class="has-coords">#chr(10003)#</span>
|
||||
<cfelseif len(addresses.Line1)>
|
||||
<cfelseif len(addresses.AddressLine1)>
|
||||
<span class="no-coords">#chr(9679)#</span>
|
||||
</cfif>
|
||||
</td>
|
||||
<td class="address">
|
||||
<cfif len(addresses.Line1)>
|
||||
#addresses.Line1#<cfif len(addresses.Line2)>, #addresses.Line2#</cfif><br>
|
||||
#addresses.City# #addresses.ZIPCode#
|
||||
<cfif len(addresses.AddressLine1)>
|
||||
#addresses.AddressLine1#<cfif len(addresses.AddressLine2)>, #addresses.AddressLine2#</cfif><br>
|
||||
#addresses.AddressCity# #addresses.AddressZIPCode#
|
||||
<cfelse>
|
||||
<em style="color:##666;">No address</em>
|
||||
</cfif>
|
||||
</td>
|
||||
<td class="coords">
|
||||
<cfif len(addresses.Latitude) AND val(addresses.Latitude) NEQ 0>
|
||||
#numberFormat(addresses.Latitude, "_.______")#<br>
|
||||
#numberFormat(addresses.Longitude, "_.______")#
|
||||
<cfif len(addresses.AddressLat) AND val(addresses.AddressLat) NEQ 0>
|
||||
#numberFormat(addresses.AddressLat, "_.______")#<br>
|
||||
#numberFormat(addresses.AddressLng, "_.______")#
|
||||
<cfelse>
|
||||
-
|
||||
</cfif>
|
||||
</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>
|
||||
</cfif>
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ try {
|
|||
response["ERROR"] = "ChildBusinessID required";
|
||||
} else {
|
||||
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 },
|
||||
childId: childID
|
||||
|
|
|
|||
|
|
@ -26,13 +26,13 @@ try {
|
|||
|
||||
// Step 1: Get all parent items (burgers, combos, etc.)
|
||||
qParentItems = queryExecute("
|
||||
SELECT i.ID, i.Name
|
||||
SELECT i.ItemID, i.ItemName
|
||||
FROM Items i
|
||||
INNER JOIN Categories c ON c.ID = i.CategoryID
|
||||
WHERE c.BusinessID = :businessID
|
||||
AND i.ParentItemID = 0
|
||||
AND i.IsActive = 1
|
||||
ORDER BY i.Name
|
||||
INNER JOIN Categories c ON c.CategoryID = i.ItemCategoryID
|
||||
WHERE c.CategoryBusinessID = :businessID
|
||||
AND i.ItemParentItemID = 0
|
||||
AND i.ItemIsActive = 1
|
||||
ORDER BY i.ItemName
|
||||
", { businessID: businessID }, { datasource: "payfrit" });
|
||||
|
||||
arrayAppend(response.steps, "Found " & qParentItems.recordCount & " parent items");
|
||||
|
|
@ -41,20 +41,20 @@ try {
|
|||
qModifiers = queryExecute("
|
||||
SELECT
|
||||
m.ItemID,
|
||||
m.Name,
|
||||
m.ParentItemID,
|
||||
m.Price,
|
||||
m.IsCheckedByDefault,
|
||||
m.SortOrder,
|
||||
p.Name as ParentName
|
||||
m.ItemName,
|
||||
m.ItemParentItemID,
|
||||
m.ItemPrice,
|
||||
m.ItemIsCheckedByDefault,
|
||||
m.ItemSortOrder,
|
||||
p.ItemName as ParentName
|
||||
FROM Items m
|
||||
INNER JOIN Items p ON p.ItemID = m.ParentItemID
|
||||
INNER JOIN Categories c ON c.ID = p.CategoryID
|
||||
WHERE c.BusinessID = :businessID
|
||||
AND m.ParentItemID > 0
|
||||
AND m.IsActive = 1
|
||||
AND p.ParentItemID = 0
|
||||
ORDER BY m.Name, m.ItemID
|
||||
INNER JOIN Items p ON p.ItemID = m.ItemParentItemID
|
||||
INNER JOIN Categories c ON c.CategoryID = p.ItemCategoryID
|
||||
WHERE c.CategoryBusinessID = :businessID
|
||||
AND m.ItemParentItemID > 0
|
||||
AND m.ItemIsActive = 1
|
||||
AND p.ItemParentItemID = 0
|
||||
ORDER BY m.ItemName, m.ItemID
|
||||
", { businessID: businessID }, { datasource: "payfrit" });
|
||||
|
||||
arrayAppend(response.steps, "Found " & qModifiers.recordCount & " level-1 modifiers");
|
||||
|
|
@ -62,17 +62,17 @@ try {
|
|||
// Step 3: Group modifiers by name to find duplicates
|
||||
modifiersByName = {};
|
||||
for (mod in qModifiers) {
|
||||
modName = mod.Name;
|
||||
modName = mod.ItemName;
|
||||
if (!structKeyExists(modifiersByName, modName)) {
|
||||
modifiersByName[modName] = [];
|
||||
}
|
||||
arrayAppend(modifiersByName[modName], {
|
||||
"ItemID": mod.ItemID,
|
||||
"ParentItemID": mod.ParentItemID,
|
||||
"ParentItemID": mod.ItemParentItemID,
|
||||
"ParentName": mod.ParentName,
|
||||
"Price": mod.Price,
|
||||
"IsDefault": mod.IsCheckedByDefault,
|
||||
"SortOrder": mod.SortOrder
|
||||
"Price": mod.ItemPrice,
|
||||
"IsDefault": mod.ItemIsCheckedByDefault,
|
||||
"SortOrder": mod.ItemSortOrder
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ try {
|
|||
|
||||
// Mark as template
|
||||
queryExecute("
|
||||
UPDATE Items SET IsModifierTemplate = 1 WHERE ItemID = :itemID
|
||||
UPDATE Items SET ItemIsModifierTemplate = 1 WHERE ItemID = :itemID
|
||||
", { itemID: templateItemID }, { datasource: "payfrit" });
|
||||
|
||||
templateMap[modName] = templateItemID;
|
||||
|
|
@ -111,7 +111,7 @@ try {
|
|||
// Insert link (ignore duplicates)
|
||||
try {
|
||||
queryExecute("
|
||||
INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder)
|
||||
INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder)
|
||||
VALUES (:itemID, :templateID, :sortOrder)
|
||||
ON DUPLICATE KEY UPDATE SortOrder = :sortOrder
|
||||
", {
|
||||
|
|
@ -134,7 +134,7 @@ try {
|
|||
if (i > 1) {
|
||||
arrayAppend(orphanItems, {
|
||||
"ItemID": inst.ItemID,
|
||||
"Name": modName,
|
||||
"ItemName": modName,
|
||||
"WasUnder": inst.ParentName
|
||||
});
|
||||
}
|
||||
|
|
@ -143,12 +143,12 @@ try {
|
|||
// Single instance - still mark as template for consistency
|
||||
singleItem = instances[1];
|
||||
queryExecute("
|
||||
UPDATE Items SET IsModifierTemplate = 1 WHERE ItemID = :itemID
|
||||
UPDATE Items SET ItemIsModifierTemplate = 1 WHERE ItemID = :itemID
|
||||
", { itemID: singleItem.ItemID }, { datasource: "payfrit" });
|
||||
|
||||
// Create link
|
||||
queryExecute("
|
||||
INSERT INTO lt_ItemID_TemplateItemID (ItemID, TemplateItemID, SortOrder)
|
||||
INSERT INTO ItemTemplateLinks (ItemID, TemplateItemID, SortOrder)
|
||||
VALUES (:itemID, :templateID, :sortOrder)
|
||||
ON DUPLICATE KEY UPDATE SortOrder = :sortOrder
|
||||
", {
|
||||
|
|
|
|||
|
|
@ -27,20 +27,20 @@ try {
|
|||
// Find all businesses with items in unified schema
|
||||
if (len(businessFilter)) {
|
||||
qBusinesses = queryExecute("
|
||||
SELECT DISTINCT BusinessID as BusinessID
|
||||
SELECT DISTINCT ItemBusinessID as BusinessID
|
||||
FROM Items
|
||||
WHERE BusinessID = :bid AND BusinessID > 0
|
||||
WHERE ItemBusinessID = :bid AND ItemBusinessID > 0
|
||||
", { bid: businessFilter }, { datasource: "payfrit" });
|
||||
} else {
|
||||
qBusinesses = queryExecute("
|
||||
SELECT DISTINCT BusinessID as BusinessID
|
||||
SELECT DISTINCT ItemBusinessID as BusinessID
|
||||
FROM Items
|
||||
WHERE BusinessID > 0
|
||||
WHERE ItemBusinessID > 0
|
||||
", {}, { datasource: "payfrit" });
|
||||
}
|
||||
|
||||
for (biz in qBusinesses) {
|
||||
bizId = biz.ID;
|
||||
bizId = biz.BusinessID;
|
||||
bizResult = { "BusinessID": bizId, "CategoriesCreated": 0, "ItemsUpdated": 0 };
|
||||
|
||||
try {
|
||||
|
|
@ -48,26 +48,26 @@ try {
|
|||
qCategoryItems = queryExecute("
|
||||
SELECT DISTINCT
|
||||
p.ItemID,
|
||||
p.Name,
|
||||
p.SortOrder
|
||||
p.ItemName,
|
||||
p.ItemSortOrder
|
||||
FROM Items p
|
||||
INNER JOIN Items c ON c.ParentItemID = p.ItemID
|
||||
WHERE p.BusinessID = :bizId
|
||||
AND p.ParentItemID = 0
|
||||
AND (p.IsCollapsible = 0 OR p.IsCollapsible IS NULL)
|
||||
INNER JOIN Items c ON c.ItemParentItemID = p.ItemID
|
||||
WHERE p.ItemBusinessID = :bizId
|
||||
AND p.ItemParentItemID = 0
|
||||
AND (p.ItemIsCollapsible = 0 OR p.ItemIsCollapsible IS NULL)
|
||||
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" });
|
||||
|
||||
sortOrder = 0;
|
||||
for (catItem in qCategoryItems) {
|
||||
// Check if category already exists for this business with same name
|
||||
qExisting = queryExecute("
|
||||
SELECT ID FROM Categories
|
||||
WHERE BusinessID = :bizId AND Name = :name
|
||||
", { bizId: bizId, name: left(catItem.Name, 30) }, { datasource: "payfrit" });
|
||||
SELECT CategoryID FROM Categories
|
||||
WHERE CategoryBusinessID = :bizId AND CategoryName = :name
|
||||
", { bizId: bizId, name: left(catItem.ItemName, 30) }, { datasource: "payfrit" });
|
||||
|
||||
if (qExisting.recordCount == 0) {
|
||||
// Get next CategoryID
|
||||
|
|
@ -79,12 +79,12 @@ try {
|
|||
// Create new category with explicit ID
|
||||
queryExecute("
|
||||
INSERT INTO Categories
|
||||
(CategoryID, BusinessID, ParentCategoryID, Name, SortOrder, AddedOn)
|
||||
(CategoryID, CategoryBusinessID, CategoryParentCategoryID, CategoryName, CategorySortOrder, CategoryAddedOn)
|
||||
VALUES (:catId, :bizId, 0, :name, :sortOrder, NOW())
|
||||
", {
|
||||
catId: newCatId,
|
||||
bizId: bizId,
|
||||
name: left(catItem.Name, 30),
|
||||
name: left(catItem.ItemName, 30),
|
||||
sortOrder: sortOrder
|
||||
}, { datasource: "payfrit" });
|
||||
|
||||
|
|
@ -96,9 +96,9 @@ try {
|
|||
// Update all children of this category Item to have the new CategoryID
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET CategoryID = :catId
|
||||
WHERE ParentItemID = :parentId
|
||||
AND BusinessID = :bizId
|
||||
SET ItemCategoryID = :catId
|
||||
WHERE ItemParentItemID = :parentId
|
||||
AND ItemBusinessID = :bizId
|
||||
", {
|
||||
catId: newCatId,
|
||||
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
|
||||
qTemplate = queryExecute("
|
||||
SELECT
|
||||
Title as Title,
|
||||
Details as Details,
|
||||
TaskCategoryID as CategoryID
|
||||
QuickTaskTemplateTitle as Title,
|
||||
QuickTaskTemplateDetails as Details,
|
||||
QuickTaskTemplateCategoryID as CategoryID,
|
||||
QuickTaskTemplateTypeID as TypeID
|
||||
FROM QuickTaskTemplates
|
||||
WHERE ID = :id
|
||||
AND BusinessID = :businessID
|
||||
AND IsActive = 1
|
||||
WHERE QuickTaskTemplateID = :id
|
||||
AND QuickTaskTemplateBusinessID = :businessID
|
||||
AND QuickTaskTemplateIsActive = 1
|
||||
", {
|
||||
id: { value: templateID, 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" });
|
||||
}
|
||||
|
||||
// Create the task (ClaimedByUserID=0 means unclaimed/pending)
|
||||
// Create the task
|
||||
queryExecute("
|
||||
INSERT INTO Tasks (
|
||||
BusinessID, CategoryID, TaskTypeID,
|
||||
Title, Details, CreatedOn, ClaimedByUserID
|
||||
TaskBusinessID, TaskCategoryID, TaskTypeID,
|
||||
TaskTitle, TaskDetails, TaskStatusID, TaskAddedOn,
|
||||
TaskSourceType, TaskSourceID
|
||||
) VALUES (
|
||||
:businessID, :categoryID, :typeID,
|
||||
:title, :details, NOW(), 0
|
||||
:title, :details, 0, NOW(),
|
||||
'quicktask', :templateID
|
||||
)
|
||||
", {
|
||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
||||
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" },
|
||||
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" });
|
||||
|
||||
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
|
||||
qCheck = queryExecute("
|
||||
SELECT QuickTaskTemplateID FROM QuickTaskTemplates
|
||||
WHERE ID = :id AND BusinessID = :businessID
|
||||
WHERE QuickTaskTemplateID = :id AND QuickTaskTemplateBusinessID = :businessID
|
||||
", {
|
||||
id: { value: templateID, cfsqltype: "cf_sql_integer" },
|
||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||
|
|
@ -62,8 +62,8 @@ try {
|
|||
|
||||
// Soft delete by setting IsActive to 0
|
||||
queryExecute("
|
||||
UPDATE QuickTaskTemplates SET IsActive = 0
|
||||
WHERE ID = :id
|
||||
UPDATE QuickTaskTemplates SET QuickTaskTemplateIsActive = 0
|
||||
WHERE QuickTaskTemplateID = :id
|
||||
", {
|
||||
id: { value: templateID, cfsqltype: "cf_sql_integer" }
|
||||
}, { datasource: "payfrit" });
|
||||
|
|
|
|||
|
|
@ -45,22 +45,23 @@ try {
|
|||
// Get quick task templates for this business
|
||||
q = queryExecute("
|
||||
SELECT
|
||||
qt.ID,
|
||||
qt.Name as Name,
|
||||
qt.TaskCategoryID as CategoryID,
|
||||
qt.Title as Title,
|
||||
qt.Details as Details,
|
||||
qt.Icon as Icon,
|
||||
qt.Color as Color,
|
||||
qt.SortOrder as SortOrder,
|
||||
qt.IsActive as IsActive,
|
||||
tc.Name as Name,
|
||||
tc.Color as CategoryColor
|
||||
qt.QuickTaskTemplateID,
|
||||
qt.QuickTaskTemplateName as Name,
|
||||
qt.QuickTaskTemplateCategoryID as CategoryID,
|
||||
qt.QuickTaskTemplateTypeID as TypeID,
|
||||
qt.QuickTaskTemplateTitle as Title,
|
||||
qt.QuickTaskTemplateDetails as Details,
|
||||
qt.QuickTaskTemplateIcon as Icon,
|
||||
qt.QuickTaskTemplateColor as Color,
|
||||
qt.QuickTaskTemplateSortOrder as SortOrder,
|
||||
qt.QuickTaskTemplateIsActive as IsActive,
|
||||
tc.TaskCategoryName as CategoryName,
|
||||
tc.TaskCategoryColor as CategoryColor
|
||||
FROM QuickTaskTemplates qt
|
||||
LEFT JOIN TaskCategories tc ON qt.TaskCategoryID = tc.ID
|
||||
WHERE qt.BusinessID = :businessID
|
||||
AND qt.IsActive = 1
|
||||
ORDER BY qt.SortOrder, qt.ID
|
||||
LEFT JOIN TaskCategories tc ON qt.QuickTaskTemplateCategoryID = tc.TaskCategoryID
|
||||
WHERE qt.QuickTaskTemplateBusinessID = :businessID
|
||||
AND qt.QuickTaskTemplateIsActive = 1
|
||||
ORDER BY qt.QuickTaskTemplateSortOrder, qt.QuickTaskTemplateID
|
||||
", {
|
||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||
}, { datasource: "payfrit" });
|
||||
|
|
@ -68,16 +69,17 @@ try {
|
|||
templates = [];
|
||||
for (row in q) {
|
||||
arrayAppend(templates, {
|
||||
"QuickTaskTemplateID": row.ID,
|
||||
"QuickTaskTemplateID": row.QuickTaskTemplateID,
|
||||
"Name": row.Name,
|
||||
"CategoryID": isNull(row.CategoryID) ? "" : row.CategoryID,
|
||||
"TypeID": isNull(row.TypeID) ? "" : row.TypeID,
|
||||
"Title": row.Title,
|
||||
"Details": isNull(row.Details) ? "" : row.Details,
|
||||
"Icon": isNull(row.Icon) ? "add_box" : row.Icon,
|
||||
"Color": isNull(row.Color) ? "##6366f1" : row.Color,
|
||||
"SortOrder": row.SortOrder,
|
||||
"IsActive": row.IsActive,
|
||||
"Name": isNull(row.Name) ? "" : row.Name,
|
||||
"CategoryName": isNull(row.CategoryName) ? "" : row.CategoryName,
|
||||
"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>
|
||||
// Create or update a quick task template
|
||||
// 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 }
|
||||
|
||||
function apiAbort(required struct payload) {
|
||||
|
|
@ -46,12 +46,8 @@ try {
|
|||
templateName = structKeyExists(data, "Name") ? trim(toString(data.Name)) : "";
|
||||
templateTitle = structKeyExists(data, "Title") ? trim(toString(data.Title)) : "";
|
||||
templateDetails = structKeyExists(data, "Details") ? trim(toString(data.Details)) : "";
|
||||
hasCategory = false;
|
||||
catID = 0;
|
||||
if (structKeyExists(data, "CategoryID") && isNumeric(data.CategoryID) && data.CategoryID > 0) {
|
||||
catID = int(data.CategoryID);
|
||||
hasCategory = true;
|
||||
}
|
||||
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", "");
|
||||
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";
|
||||
|
||||
|
|
@ -62,15 +58,12 @@ try {
|
|||
if (!len(templateTitle)) {
|
||||
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) {
|
||||
// UPDATE existing template
|
||||
qCheck = queryExecute("
|
||||
SELECT QuickTaskTemplateID FROM QuickTaskTemplates
|
||||
WHERE ID = :id AND BusinessID = :businessID
|
||||
WHERE QuickTaskTemplateID = :id AND QuickTaskTemplateBusinessID = :businessID
|
||||
", {
|
||||
id: { value: templateID, cfsqltype: "cf_sql_integer" },
|
||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||
|
|
@ -82,18 +75,20 @@ try {
|
|||
|
||||
queryExecute("
|
||||
UPDATE QuickTaskTemplates SET
|
||||
Name = :name,
|
||||
Title = :title,
|
||||
Details = :details,
|
||||
TaskCategoryID = :categoryID,
|
||||
Icon = :icon,
|
||||
Color = :color
|
||||
WHERE ID = :id
|
||||
QuickTaskTemplateName = :name,
|
||||
QuickTaskTemplateTitle = :title,
|
||||
QuickTaskTemplateDetails = :details,
|
||||
QuickTaskTemplateCategoryID = :categoryID,
|
||||
QuickTaskTemplateTypeID = :typeID,
|
||||
QuickTaskTemplateIcon = :icon,
|
||||
QuickTaskTemplateColor = :color
|
||||
WHERE QuickTaskTemplateID = :id
|
||||
", {
|
||||
name: { value: templateName, cfsqltype: "cf_sql_varchar" },
|
||||
title: { value: templateTitle, cfsqltype: "cf_sql_varchar" },
|
||||
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" },
|
||||
color: { value: templateColor, cfsqltype: "cf_sql_varchar" },
|
||||
id: { value: templateID, cfsqltype: "cf_sql_integer" }
|
||||
|
|
@ -109,8 +104,8 @@ try {
|
|||
// INSERT new template
|
||||
// Get next sort order
|
||||
qSort = queryExecute("
|
||||
SELECT COALESCE(MAX(SortOrder), 0) + 1 as nextSort
|
||||
FROM QuickTaskTemplates WHERE BusinessID = :businessID
|
||||
SELECT COALESCE(MAX(QuickTaskTemplateSortOrder), 0) + 1 as nextSort
|
||||
FROM QuickTaskTemplates WHERE QuickTaskTemplateBusinessID = :businessID
|
||||
", {
|
||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||
}, { datasource: "payfrit" });
|
||||
|
|
@ -119,18 +114,19 @@ try {
|
|||
|
||||
queryExecute("
|
||||
INSERT INTO QuickTaskTemplates (
|
||||
BusinessID, Name, Title,
|
||||
Details, TaskCategoryID,
|
||||
Icon, Color, SortOrder
|
||||
QuickTaskTemplateBusinessID, QuickTaskTemplateName, QuickTaskTemplateTitle,
|
||||
QuickTaskTemplateDetails, QuickTaskTemplateCategoryID, QuickTaskTemplateTypeID,
|
||||
QuickTaskTemplateIcon, QuickTaskTemplateColor, QuickTaskTemplateSortOrder
|
||||
) 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" },
|
||||
name: { value: templateName, cfsqltype: "cf_sql_varchar" },
|
||||
title: { value: templateTitle, cfsqltype: "cf_sql_varchar" },
|
||||
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" },
|
||||
color: { value: templateColor, cfsqltype: "cf_sql_varchar" },
|
||||
sortOrder: { value: nextSort, cfsqltype: "cf_sql_integer" }
|
||||
|
|
@ -149,10 +145,7 @@ try {
|
|||
apiAbort({
|
||||
"OK": false,
|
||||
"ERROR": "server_error",
|
||||
"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"
|
||||
"MESSAGE": e.message
|
||||
});
|
||||
}
|
||||
</cfscript>
|
||||
|
|
|
|||
|
|
@ -15,20 +15,20 @@ try {
|
|||
// Create QuickTaskTemplates table
|
||||
queryExecute("
|
||||
CREATE TABLE IF NOT EXISTS QuickTaskTemplates (
|
||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
BusinessID INT NOT NULL,
|
||||
Name VARCHAR(100) NOT NULL,
|
||||
TaskCategoryID INT NULL,
|
||||
TaskTypeID INT NULL,
|
||||
Title VARCHAR(255) NOT NULL,
|
||||
Details TEXT NULL,
|
||||
Icon VARCHAR(30) DEFAULT 'add_box',
|
||||
Color VARCHAR(20) DEFAULT '##6366f1',
|
||||
SortOrder INT DEFAULT 0,
|
||||
IsActive BIT(1) DEFAULT b'1',
|
||||
CreatedOn DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_business_active (BusinessID, IsActive),
|
||||
INDEX idx_sort (BusinessID, SortOrder)
|
||||
QuickTaskTemplateID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
QuickTaskTemplateBusinessID INT NOT NULL,
|
||||
QuickTaskTemplateName VARCHAR(100) NOT NULL,
|
||||
QuickTaskTemplateCategoryID INT NULL,
|
||||
QuickTaskTemplateTypeID INT NULL,
|
||||
QuickTaskTemplateTitle VARCHAR(255) NOT NULL,
|
||||
QuickTaskTemplateDetails TEXT NULL,
|
||||
QuickTaskTemplateIcon VARCHAR(30) DEFAULT 'add_box',
|
||||
QuickTaskTemplateColor VARCHAR(20) DEFAULT '##6366f1',
|
||||
QuickTaskTemplateSortOrder INT DEFAULT 0,
|
||||
QuickTaskTemplateIsActive BIT(1) DEFAULT b'1',
|
||||
QuickTaskTemplateCreatedOn DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_business_active (QuickTaskTemplateBusinessID, QuickTaskTemplateIsActive),
|
||||
INDEX idx_sort (QuickTaskTemplateBusinessID, QuickTaskTemplateSortOrder)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
", [], { datasource: "payfrit" });
|
||||
|
||||
|
|
|
|||
|
|
@ -5,42 +5,42 @@
|
|||
<cfscript>
|
||||
businessId = 27; // Big Dean's
|
||||
|
||||
// Categories are items with ParentItemID=0 AND IsCollapsible=0
|
||||
// Modifier templates are items with ParentItemID=0 AND IsCollapsible=1
|
||||
// Categories are items with ItemParentItemID=0 AND ItemIsCollapsible=0
|
||||
// Modifier templates are items with ItemParentItemID=0 AND ItemIsCollapsible=1
|
||||
// Menu items are children of categories
|
||||
// Modifiers are children of menu items or modifier templates
|
||||
|
||||
// Get category IDs (NOT modifier templates)
|
||||
categoryIds = queryExecute("
|
||||
SELECT ID
|
||||
SELECT ItemID
|
||||
FROM Items
|
||||
WHERE BusinessID = :bizId
|
||||
AND ParentItemID = 0
|
||||
AND IsCollapsible = 0
|
||||
WHERE ItemBusinessID = :bizId
|
||||
AND ItemParentItemID = 0
|
||||
AND ItemIsCollapsible = 0
|
||||
", { bizId: businessId }, { datasource: "payfrit" });
|
||||
|
||||
catIdList = "";
|
||||
for (cat in categoryIds) {
|
||||
catIdList = listAppend(catIdList, cat.ID);
|
||||
catIdList = listAppend(catIdList, cat.ItemID);
|
||||
}
|
||||
|
||||
// Now get actual menu items (direct children of categories)
|
||||
// Exclude items that are template options (their parent is a collapsible modifier group)
|
||||
items = queryExecute("
|
||||
SELECT i.ID, i.Name
|
||||
SELECT i.ItemID, i.ItemName
|
||||
FROM Items i
|
||||
WHERE i.BusinessID = :bizId
|
||||
AND i.ParentItemID IN (#catIdList#)
|
||||
AND i.IsCollapsible = 0
|
||||
WHERE i.ItemBusinessID = :bizId
|
||||
AND i.ItemParentItemID IN (#catIdList#)
|
||||
AND i.ItemIsCollapsible = 0
|
||||
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" });
|
||||
|
||||
updated = [];
|
||||
|
||||
for (item in items) {
|
||||
itemName = lcase(item.Name);
|
||||
itemName = lcase(item.ItemName);
|
||||
newPrice = 0;
|
||||
|
||||
// Drinks - $3-6
|
||||
|
|
@ -99,13 +99,13 @@ for (item in items) {
|
|||
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET Price = :price
|
||||
SET ItemPrice = :price
|
||||
WHERE ItemID = :itemId
|
||||
", { price: newPrice, itemId: item.ID }, { datasource: "payfrit" });
|
||||
", { price: newPrice, itemId: item.ItemID }, { datasource: "payfrit" });
|
||||
|
||||
arrayAppend(updated, {
|
||||
"ItemID": item.ID,
|
||||
"Name": item.Name,
|
||||
"ItemID": item.ItemID,
|
||||
"ItemName": item.ItemName,
|
||||
"NewPrice": newPrice
|
||||
});
|
||||
}
|
||||
|
|
@ -113,15 +113,15 @@ for (item in items) {
|
|||
// 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 = queryExecute("
|
||||
SELECT ID, Name
|
||||
SELECT ItemID, ItemName
|
||||
FROM Items
|
||||
WHERE BusinessID = :bizId
|
||||
AND ParentItemID > 0
|
||||
AND ParentItemID NOT IN (#catIdList#)
|
||||
WHERE ItemBusinessID = :bizId
|
||||
AND ItemParentItemID > 0
|
||||
AND ItemParentItemID NOT IN (#catIdList#)
|
||||
", { bizId: businessId }, { datasource: "payfrit" });
|
||||
|
||||
for (mod in modifiers) {
|
||||
modName = lcase(mod.Name);
|
||||
modName = lcase(mod.ItemName);
|
||||
modPrice = 0;
|
||||
|
||||
// Proteins are expensive add-ons
|
||||
|
|
@ -150,7 +150,7 @@ for (mod in modifiers) {
|
|||
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET Price = :price
|
||||
SET ItemPrice = :price
|
||||
WHERE ItemID = :itemId
|
||||
", { 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)
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET Price = 0
|
||||
WHERE BusinessID = :bizId
|
||||
AND ParentItemID = 0
|
||||
SET ItemPrice = 0
|
||||
WHERE ItemBusinessID = :bizId
|
||||
AND ItemParentItemID = 0
|
||||
", { bizId: businessId }, { datasource: "payfrit" });
|
||||
|
||||
// Reset modifier group prices to $0 (only options have prices)
|
||||
queryExecute("
|
||||
UPDATE Items
|
||||
SET Price = 0
|
||||
WHERE BusinessID = :bizId
|
||||
AND IsCollapsible = 1
|
||||
SET ItemPrice = 0
|
||||
WHERE ItemBusinessID = :bizId
|
||||
AND ItemIsCollapsible = 1
|
||||
", { bizId: businessId }, { datasource: "payfrit" });
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ try {
|
|||
// Verify exists and belongs to business
|
||||
qCheck = queryExecute("
|
||||
SELECT ScheduledTaskID FROM ScheduledTaskDefinitions
|
||||
WHERE ID = :id AND BusinessID = :businessID
|
||||
WHERE ScheduledTaskID = :id AND ScheduledTaskBusinessID = :businessID
|
||||
", {
|
||||
id: { value: taskID, cfsqltype: "cf_sql_integer" },
|
||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||
|
|
@ -62,7 +62,7 @@ try {
|
|||
|
||||
// Hard delete the definition
|
||||
queryExecute("
|
||||
DELETE FROM ScheduledTaskDefinitions WHERE ID = :id
|
||||
DELETE FROM ScheduledTaskDefinitions WHERE ScheduledTaskID = :id
|
||||
", {
|
||||
id: { value: taskID, cfsqltype: "cf_sql_integer" }
|
||||
}, { datasource: "payfrit" });
|
||||
|
|
|
|||
|
|
@ -45,24 +45,23 @@ try {
|
|||
// Get scheduled task definitions for this business
|
||||
q = queryExecute("
|
||||
SELECT
|
||||
st.ID,
|
||||
st.Name as Name,
|
||||
st.TaskCategoryID as CategoryID,
|
||||
st.Title as Title,
|
||||
st.Details as Details,
|
||||
st.CronExpression as CronExpression,
|
||||
COALESCE(st.ScheduleType, 'cron') as ScheduleType,
|
||||
st.IntervalMinutes as IntervalMinutes,
|
||||
st.IsActive as IsActive,
|
||||
st.LastRunOn as LastRunOn,
|
||||
st.NextRunOn as NextRunOn,
|
||||
st.CreatedOn as CreatedOn,
|
||||
tc.Name as Name,
|
||||
tc.Color as CategoryColor
|
||||
st.ScheduledTaskID,
|
||||
st.ScheduledTaskName as Name,
|
||||
st.ScheduledTaskCategoryID as CategoryID,
|
||||
st.ScheduledTaskTypeID as TypeID,
|
||||
st.ScheduledTaskTitle as Title,
|
||||
st.ScheduledTaskDetails as Details,
|
||||
st.ScheduledTaskCronExpression as CronExpression,
|
||||
st.ScheduledTaskIsActive as IsActive,
|
||||
st.ScheduledTaskLastRunOn as LastRunOn,
|
||||
st.ScheduledTaskNextRunOn as NextRunOn,
|
||||
st.ScheduledTaskCreatedOn as CreatedOn,
|
||||
tc.TaskCategoryName as CategoryName,
|
||||
tc.TaskCategoryColor as CategoryColor
|
||||
FROM ScheduledTaskDefinitions st
|
||||
LEFT JOIN TaskCategories tc ON st.TaskCategoryID = tc.ID
|
||||
WHERE st.BusinessID = :businessID
|
||||
ORDER BY st.IsActive DESC, st.Name
|
||||
LEFT JOIN TaskCategories tc ON st.ScheduledTaskCategoryID = tc.TaskCategoryID
|
||||
WHERE st.ScheduledTaskBusinessID = :businessID
|
||||
ORDER BY st.ScheduledTaskIsActive DESC, st.ScheduledTaskName
|
||||
", {
|
||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||
}, { datasource: "payfrit" });
|
||||
|
|
@ -70,19 +69,18 @@ try {
|
|||
scheduledTasks = [];
|
||||
for (row in q) {
|
||||
arrayAppend(scheduledTasks, {
|
||||
"ScheduledTaskID": row.ID,
|
||||
"ScheduledTaskID": row.ScheduledTaskID,
|
||||
"Name": row.Name,
|
||||
"CategoryID": isNull(row.CategoryID) ? "" : row.CategoryID,
|
||||
"TypeID": isNull(row.TypeID) ? "" : row.TypeID,
|
||||
"Title": row.Title,
|
||||
"Details": isNull(row.Details) ? "" : row.Details,
|
||||
"CronExpression": row.CronExpression,
|
||||
"ScheduleType": row.ScheduleType,
|
||||
"IntervalMinutes": isNull(row.IntervalMinutes) ? "" : row.IntervalMinutes,
|
||||
"IsActive": row.IsActive ? true : false,
|
||||
"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"),
|
||||
"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
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,11 +51,12 @@ try {
|
|||
// Get scheduled task definition
|
||||
qDef = queryExecute("
|
||||
SELECT
|
||||
Title as Title,
|
||||
Details as Details,
|
||||
TaskCategoryID as CategoryID
|
||||
ScheduledTaskTitle as Title,
|
||||
ScheduledTaskDetails as Details,
|
||||
ScheduledTaskCategoryID as CategoryID,
|
||||
ScheduledTaskTypeID as TypeID
|
||||
FROM ScheduledTaskDefinitions
|
||||
WHERE ID = :id AND BusinessID = :businessID
|
||||
WHERE ScheduledTaskID = :id AND ScheduledTaskBusinessID = :businessID
|
||||
", {
|
||||
id: { value: scheduledTaskID, 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" });
|
||||
}
|
||||
|
||||
// Create the task (ClaimedByUserID=0 means unclaimed/pending)
|
||||
// Create the task
|
||||
queryExecute("
|
||||
INSERT INTO Tasks (
|
||||
BusinessID, CategoryID, TaskTypeID,
|
||||
Title, Details, CreatedOn, ClaimedByUserID
|
||||
TaskBusinessID, TaskCategoryID, TaskTypeID,
|
||||
TaskTitle, TaskDetails, TaskStatusID, TaskAddedOn,
|
||||
TaskSourceType, TaskSourceID
|
||||
) VALUES (
|
||||
:businessID, :categoryID, :typeID,
|
||||
:title, :details, NOW(), 0
|
||||
:title, :details, 0, NOW(),
|
||||
'scheduled_manual', :scheduledTaskID
|
||||
)
|
||||
", {
|
||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" },
|
||||
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" },
|
||||
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" });
|
||||
|
||||
qNew = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" });
|
||||
|
|
|
|||
|
|
@ -68,65 +68,57 @@ try {
|
|||
dueTasks = queryExecute("
|
||||
SELECT
|
||||
ScheduledTaskID,
|
||||
BusinessID as BusinessID,
|
||||
TaskCategoryID as CategoryID,
|
||||
Title as Title,
|
||||
Details as Details,
|
||||
CronExpression as CronExpression,
|
||||
COALESCE(ScheduleType, 'cron') as ScheduleType,
|
||||
IntervalMinutes as IntervalMinutes
|
||||
ScheduledTaskBusinessID as BusinessID,
|
||||
ScheduledTaskCategoryID as CategoryID,
|
||||
ScheduledTaskTypeID as TypeID,
|
||||
ScheduledTaskTitle as Title,
|
||||
ScheduledTaskDetails as Details,
|
||||
ScheduledTaskCronExpression as CronExpression
|
||||
FROM ScheduledTaskDefinitions
|
||||
WHERE IsActive = 1
|
||||
AND NextRunOn <= NOW()
|
||||
WHERE ScheduledTaskIsActive = 1
|
||||
AND ScheduledTaskNextRunOn <= NOW()
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
createdTasks = [];
|
||||
|
||||
for (task in dueTasks) {
|
||||
// Create the actual task (ClaimedByUserID=0 means unclaimed/pending)
|
||||
// Create the actual task
|
||||
queryExecute("
|
||||
INSERT INTO Tasks (
|
||||
BusinessID, CategoryID, TaskTypeID,
|
||||
Title, Details, CreatedOn, ClaimedByUserID
|
||||
TaskBusinessID, TaskCategoryID, TaskTypeID,
|
||||
TaskTitle, TaskDetails, TaskStatusID, TaskAddedOn,
|
||||
TaskSourceType, TaskSourceID
|
||||
) VALUES (
|
||||
:businessID, :categoryID, :typeID,
|
||||
:title, :details, NOW(), 0
|
||||
:title, :details, 0, NOW(),
|
||||
'scheduled', :scheduledTaskID
|
||||
)
|
||||
", {
|
||||
businessID: { value: task.BusinessID, cfsqltype: "cf_sql_integer" },
|
||||
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" },
|
||||
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" });
|
||||
|
||||
qNew = queryExecute("SELECT LAST_INSERT_ID() as newID", [], { datasource: "payfrit" });
|
||||
|
||||
// Calculate next run based on schedule type
|
||||
if (task.ScheduleType == "interval_after_completion" && !isNull(task.IntervalMinutes) && task.IntervalMinutes > 0) {
|
||||
// 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);
|
||||
}
|
||||
// Calculate next run and update the scheduled task
|
||||
nextRun = calculateNextRun(task.CronExpression);
|
||||
|
||||
queryExecute("
|
||||
UPDATE ScheduledTaskDefinitions SET
|
||||
LastRunOn = NOW(),
|
||||
NextRunOn = :nextRun
|
||||
WHERE ID = :id
|
||||
ScheduledTaskLastRunOn = NOW(),
|
||||
ScheduledTaskNextRunOn = :nextRun
|
||||
WHERE ScheduledTaskID = :id
|
||||
", {
|
||||
nextRun: { value: nextRun, cfsqltype: "cf_sql_timestamp", null: isNull(nextRun) },
|
||||
id: { value: task.ID, cfsqltype: "cf_sql_integer" }
|
||||
nextRun: { value: nextRun, cfsqltype: "cf_sql_timestamp" },
|
||||
id: { value: task.ScheduledTaskID, cfsqltype: "cf_sql_integer" }
|
||||
}, { datasource: "payfrit" });
|
||||
|
||||
arrayAppend(createdTasks, {
|
||||
"ScheduledTaskID": task.ID,
|
||||
"ScheduledTaskID": task.ScheduledTaskID,
|
||||
"TaskID": qNew.newID,
|
||||
"BusinessID": task.BusinessID,
|
||||
"Title": task.Title
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@
|
|||
<cfscript>
|
||||
// Create or update a scheduled task definition
|
||||
// Input: BusinessID (required), ScheduledTaskID (optional - for update),
|
||||
// Name, Title, Details, CategoryID, TypeID, CronExpression, IsActive,
|
||||
// ScheduleType ('cron' or 'interval'), IntervalMinutes (for interval type)
|
||||
// Name, Title, Details, CategoryID, TypeID, CronExpression, IsActive
|
||||
// Output: { OK: true, SCHEDULED_TASK_ID: int }
|
||||
|
||||
function apiAbort(required struct payload) {
|
||||
|
|
@ -109,13 +108,10 @@ try {
|
|||
taskTitle = structKeyExists(data, "Title") ? trim(toString(data.Title)) : "";
|
||||
taskDetails = structKeyExists(data, "Details") ? trim(toString(data.Details)) : "";
|
||||
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)) : "";
|
||||
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
|
||||
if (!len(taskName)) {
|
||||
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "Name is required" });
|
||||
|
|
@ -123,42 +119,24 @@ try {
|
|||
if (!len(taskTitle)) {
|
||||
apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "Title is required" });
|
||||
}
|
||||
|
||||
// Validate based on schedule type
|
||||
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);
|
||||
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
|
||||
nextRunOn = calculateNextRun(cronExpression);
|
||||
|
||||
if (taskID > 0) {
|
||||
// UPDATE existing
|
||||
qCheck = queryExecute("
|
||||
SELECT ScheduledTaskID FROM ScheduledTaskDefinitions
|
||||
WHERE ID = :id AND BusinessID = :businessID
|
||||
WHERE ScheduledTaskID = :id AND ScheduledTaskBusinessID = :businessID
|
||||
", {
|
||||
id: { value: taskID, cfsqltype: "cf_sql_integer" },
|
||||
businessID: { value: businessID, cfsqltype: "cf_sql_integer" }
|
||||
|
|
@ -170,24 +148,22 @@ try {
|
|||
|
||||
queryExecute("
|
||||
UPDATE ScheduledTaskDefinitions SET
|
||||
Name = :name,
|
||||
Title = :title,
|
||||
Details = :details,
|
||||
TaskCategoryID = :categoryID,
|
||||
CronExpression = :cron,
|
||||
ScheduleType = :scheduleType,
|
||||
IntervalMinutes = :intervalMinutes,
|
||||
IsActive = :isActive,
|
||||
NextRunOn = :nextRun
|
||||
WHERE ID = :id
|
||||
ScheduledTaskName = :name,
|
||||
ScheduledTaskTitle = :title,
|
||||
ScheduledTaskDetails = :details,
|
||||
ScheduledTaskCategoryID = :categoryID,
|
||||
ScheduledTaskTypeID = :typeID,
|
||||
ScheduledTaskCronExpression = :cron,
|
||||
ScheduledTaskIsActive = :isActive,
|
||||
ScheduledTaskNextRunOn = :nextRun
|
||||
WHERE ScheduledTaskID = :id
|
||||
", {
|
||||
name: { value: taskName, cfsqltype: "cf_sql_varchar" },
|
||||
title: { value: taskTitle, cfsqltype: "cf_sql_varchar" },
|
||||
details: { value: taskDetails, cfsqltype: "cf_sql_longvarchar", null: !len(taskDetails) },
|
||||
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" },
|
||||
scheduleType: { value: scheduleType, cfsqltype: "cf_sql_varchar" },
|
||||
intervalMinutes: { value: intervalMinutes, cfsqltype: "cf_sql_integer", null: isNull(intervalMinutes) },
|
||||
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
||||
nextRun: { value: nextRunOn, cfsqltype: "cf_sql_timestamp" },
|
||||
id: { value: taskID, cfsqltype: "cf_sql_integer" }
|
||||
|
|
@ -204,12 +180,11 @@ try {
|
|||
// INSERT new
|
||||
queryExecute("
|
||||
INSERT INTO ScheduledTaskDefinitions (
|
||||
BusinessID, Name, Title,
|
||||
Details, TaskCategoryID,
|
||||
CronExpression, ScheduleType, IntervalMinutes,
|
||||
IsActive, NextRunOn
|
||||
ScheduledTaskBusinessID, ScheduledTaskName, ScheduledTaskTitle,
|
||||
ScheduledTaskDetails, ScheduledTaskCategoryID, ScheduledTaskTypeID,
|
||||
ScheduledTaskCronExpression, ScheduledTaskIsActive, ScheduledTaskNextRunOn
|
||||
) 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" },
|
||||
|
|
@ -217,65 +192,19 @@ try {
|
|||
title: { value: taskTitle, cfsqltype: "cf_sql_varchar" },
|
||||
details: { value: taskDetails, cfsqltype: "cf_sql_longvarchar", null: !len(taskDetails) },
|
||||
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" },
|
||||
scheduleType: { value: scheduleType, cfsqltype: "cf_sql_varchar" },
|
||||
intervalMinutes: { value: intervalMinutes, cfsqltype: "cf_sql_integer", null: isNull(intervalMinutes) },
|
||||
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
||||
nextRun: { value: nextRunOn, cfsqltype: "cf_sql_timestamp" }
|
||||
}, { 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({
|
||||
"OK": true,
|
||||
"SCHEDULED_TASK_ID": newScheduledTaskID,
|
||||
"TASK_ID": qTask.taskID,
|
||||
"NEXT_RUN": isNull(actualNextRun) ? "" : dateTimeFormat(actualNextRun, "yyyy-mm-dd HH:nn:ss"),
|
||||
"MESSAGE": "Scheduled task created and first task added"
|
||||
"SCHEDULED_TASK_ID": qNew.newID,
|
||||
"NEXT_RUN": dateTimeFormat(nextRunOn, "yyyy-mm-dd HH:nn:ss"),
|
||||
"MESSAGE": "Scheduled task created"
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,48 +15,27 @@ try {
|
|||
// Create ScheduledTaskDefinitions table
|
||||
queryExecute("
|
||||
CREATE TABLE IF NOT EXISTS ScheduledTaskDefinitions (
|
||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
BusinessID INT NOT NULL,
|
||||
Name VARCHAR(100) NOT NULL,
|
||||
TaskCategoryID INT NULL,
|
||||
TaskTypeID INT NULL,
|
||||
Title VARCHAR(255) NOT NULL,
|
||||
Details TEXT NULL,
|
||||
CronExpression VARCHAR(100) NOT NULL,
|
||||
ScheduleType VARCHAR(20) DEFAULT 'cron',
|
||||
IntervalMinutes INT NULL,
|
||||
IsActive BIT(1) DEFAULT b'1',
|
||||
LastRunOn DATETIME NULL,
|
||||
NextRunOn DATETIME NULL,
|
||||
CreatedOn DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
CreatedByUserID INT NULL,
|
||||
INDEX idx_business (BusinessID),
|
||||
INDEX idx_active_next (IsActive, NextRunOn)
|
||||
ScheduledTaskID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ScheduledTaskBusinessID INT NOT NULL,
|
||||
ScheduledTaskName VARCHAR(100) NOT NULL,
|
||||
ScheduledTaskCategoryID INT NULL,
|
||||
ScheduledTaskTypeID INT NULL,
|
||||
ScheduledTaskTitle VARCHAR(255) NOT NULL,
|
||||
ScheduledTaskDetails TEXT NULL,
|
||||
ScheduledTaskCronExpression VARCHAR(100) NOT NULL,
|
||||
ScheduledTaskIsActive BIT(1) DEFAULT b'1',
|
||||
ScheduledTaskLastRunOn DATETIME NULL,
|
||||
ScheduledTaskNextRunOn DATETIME NULL,
|
||||
ScheduledTaskCreatedOn DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
ScheduledTaskCreatedByUserID INT NULL,
|
||||
INDEX idx_business (ScheduledTaskBusinessID),
|
||||
INDEX idx_active_next (ScheduledTaskIsActive, ScheduledTaskNextRunOn)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
", [], { 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({
|
||||
"OK": true,
|
||||
"MESSAGE": "ScheduledTaskDefinitions table created/verified with interval support"
|
||||
"MESSAGE": "ScheduledTaskDefinitions table created/verified"
|
||||
});
|
||||
|
||||
} catch (any e) {
|
||||
|
|
|
|||
|
|
@ -97,13 +97,11 @@ try {
|
|||
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("
|
||||
SELECT ScheduledTaskID, CronExpression as CronExpression,
|
||||
COALESCE(ScheduleType, 'cron') as ScheduleType,
|
||||
IntervalMinutes as IntervalMinutes
|
||||
SELECT ScheduledTaskID, ScheduledTaskCronExpression as CronExpression
|
||||
FROM ScheduledTaskDefinitions
|
||||
WHERE ID = :id AND BusinessID = :businessID
|
||||
WHERE ScheduledTaskID = :id AND ScheduledTaskBusinessID = :businessID
|
||||
", {
|
||||
id: { value: taskID, 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" });
|
||||
}
|
||||
|
||||
// If enabling, recalculate next run time based on schedule type
|
||||
// If enabling, recalculate next run time
|
||||
nextRunUpdate = "";
|
||||
if (isActive) {
|
||||
if ((qCheck.ScheduleType == "interval" || qCheck.ScheduleType == "interval_after_completion") && !isNull(qCheck.IntervalMinutes) && qCheck.IntervalMinutes > 0) {
|
||||
// Interval-based: next run = NOW + interval minutes
|
||||
nextRunOn = dateAdd("n", qCheck.IntervalMinutes, now());
|
||||
} else {
|
||||
// Cron-based: use cron parser
|
||||
nextRunOn = calculateNextRun(qCheck.CronExpression);
|
||||
}
|
||||
nextRunUpdate = ", NextRunOn = :nextRun";
|
||||
nextRunOn = calculateNextRun(qCheck.CronExpression);
|
||||
nextRunUpdate = ", ScheduledTaskNextRunOn = :nextRun";
|
||||
}
|
||||
|
||||
// Update status
|
||||
if (isActive) {
|
||||
queryExecute("
|
||||
UPDATE ScheduledTaskDefinitions SET
|
||||
IsActive = :isActive,
|
||||
NextRunOn = :nextRun
|
||||
WHERE ID = :id
|
||||
ScheduledTaskIsActive = :isActive,
|
||||
ScheduledTaskNextRunOn = :nextRun
|
||||
WHERE ScheduledTaskID = :id
|
||||
", {
|
||||
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
||||
nextRun: { value: nextRunOn, cfsqltype: "cf_sql_timestamp" },
|
||||
|
|
@ -140,8 +132,8 @@ try {
|
|||
}, { datasource: "payfrit" });
|
||||
} else {
|
||||
queryExecute("
|
||||
UPDATE ScheduledTaskDefinitions SET IsActive = :isActive
|
||||
WHERE ID = :id
|
||||
UPDATE ScheduledTaskDefinitions SET ScheduledTaskIsActive = :isActive
|
||||
WHERE ScheduledTaskID = :id
|
||||
", {
|
||||
isActive: { value: isActive, cfsqltype: "cf_sql_bit" },
|
||||
id: { value: taskID, cfsqltype: "cf_sql_integer" }
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ if (businessId <= 0 || userId <= 0) {
|
|||
try {
|
||||
// Update employee record
|
||||
queryExecute("
|
||||
UPDATE Employees
|
||||
SET IsActive = ?
|
||||
UPDATE lt_Users_Businesses_Employees
|
||||
SET EmployeeIsActive = ?
|
||||
WHERE BusinessID = ? AND UserID = ?
|
||||
", [
|
||||
{ value: isActive, cfsqltype: "cf_sql_bit" },
|
||||
|
|
@ -32,12 +32,12 @@ try {
|
|||
|
||||
// Get updated record
|
||||
q = queryExecute("
|
||||
SELECT e.ID, e.BusinessID, e.UserID, e.StatusID,
|
||||
CAST(e.IsActive AS UNSIGNED) AS IsActive,
|
||||
b.Name, u.FirstName, u.LastName
|
||||
FROM Employees e
|
||||
JOIN Businesses b ON e.BusinessID = b.ID
|
||||
JOIN Users u ON e.UserID = u.ID
|
||||
SELECT e.EmployeeID, e.BusinessID, e.UserID, e.EmployeeStatusID,
|
||||
CAST(e.EmployeeIsActive AS UNSIGNED) AS EmployeeIsActive,
|
||||
b.BusinessName, u.UserFirstName, u.UserLastName
|
||||
FROM lt_Users_Businesses_Employees e
|
||||
JOIN Businesses b ON e.BusinessID = b.BusinessID
|
||||
JOIN Users u ON e.UserID = u.UserID
|
||||
WHERE e.BusinessID = ? AND e.UserID = ?
|
||||
", [
|
||||
{ value: businessId, cfsqltype: "cf_sql_integer" },
|
||||
|
|
@ -49,13 +49,13 @@ try {
|
|||
"OK": true,
|
||||
"MESSAGE": "Employee updated",
|
||||
"EMPLOYEE": {
|
||||
"EmployeeID": q.ID,
|
||||
"EmployeeID": q.EmployeeID,
|
||||
"BusinessID": q.BusinessID,
|
||||
"Name": q.Name,
|
||||
"BusinessName": q.BusinessName,
|
||||
"UserID": q.UserID,
|
||||
"UserName": trim(q.FirstName & " " & q.LastName),
|
||||
"StatusID": q.StatusID,
|
||||
"IsActive": q.IsActive
|
||||
"UserName": trim(q.UserFirstName & " " & q.UserLastName),
|
||||
"StatusID": q.EmployeeStatusID,
|
||||
"IsActive": q.EmployeeIsActive
|
||||
}
|
||||
}));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ response = { "OK": false };
|
|||
|
||||
try {
|
||||
queryExecute("
|
||||
UPDATE Businesses SET HeaderImageExtension = 'jpg' WHERE ID = 37
|
||||
UPDATE Businesses SET BusinessHeaderImageExtension = 'jpg' WHERE BusinessID = 37
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
response.OK = true;
|
||||
response.message = "Set HeaderImageExtension to 'jpg' for business 37";
|
||||
response.message = "Set BusinessHeaderImageExtension to 'jpg' for business 37";
|
||||
} catch (any e) {
|
||||
response.error = e.message;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<cfscript>
|
||||
/**
|
||||
* 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": [] };
|
||||
|
||||
|
|
@ -14,10 +14,10 @@ try {
|
|||
|
||||
// Get all service points for Lazy Daisy
|
||||
qServicePoints = queryExecute("
|
||||
SELECT ID, Name
|
||||
SELECT ServicePointID, ServicePointName
|
||||
FROM ServicePoints
|
||||
WHERE BusinessID = :bizID AND IsActive = 1
|
||||
ORDER BY SortOrder, ID
|
||||
WHERE ServicePointBusinessID = :bizID AND ServicePointIsActive = 1
|
||||
ORDER BY ServicePointID
|
||||
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||
|
||||
response.steps.append("Found " & qServicePoints.recordCount & " service points for Lazy Daisy");
|
||||
|
|
@ -25,20 +25,20 @@ try {
|
|||
// Create a beacon for each service point
|
||||
beaconsCreated = 0;
|
||||
for (sp in qServicePoints) {
|
||||
beaconName = "Beacon - " & sp.Name;
|
||||
beaconName = "Beacon - " & sp.ServicePointName;
|
||||
|
||||
// Check if beacon already exists for this business with this name
|
||||
qExisting = queryExecute("
|
||||
SELECT ID FROM Beacons
|
||||
WHERE BusinessID = :bizId AND Name = :name
|
||||
SELECT BeaconID FROM Beacons
|
||||
WHERE BeaconBusinessID = :bizId AND BeaconName = :name
|
||||
", { bizId: lazyDaisyID, name: beaconName }, { datasource: "payfrit" });
|
||||
|
||||
if (qExisting.recordCount == 0) {
|
||||
// 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("
|
||||
INSERT INTO Beacons (BusinessID, Name, UUID, IsActive)
|
||||
INSERT INTO Beacons (BeaconBusinessID, BeaconName, BeaconUUID, BeaconIsActive)
|
||||
VALUES (:bizId, :name, :uuid, 1)
|
||||
", {
|
||||
bizId: lazyDaisyID,
|
||||
|
|
@ -49,18 +49,18 @@ try {
|
|||
qNewBeacon = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
||||
newBeaconId = qNewBeacon.id;
|
||||
|
||||
// Assign beacon directly to service point
|
||||
// Create assignment to service point
|
||||
queryExecute("
|
||||
UPDATE ServicePoints
|
||||
SET BeaconID = :beaconId, AssignedByUserID = 1
|
||||
WHERE ID = :spId AND BusinessID = :bizId
|
||||
INSERT INTO lt_Beacon_Businesses_ServicePoints
|
||||
(BeaconID, BusinessID, ServicePointID, lt_Beacon_Businesses_ServicePointAssignedByUserID)
|
||||
VALUES (:beaconId, :bizId, :spId, 1)
|
||||
", {
|
||||
beaconId: newBeaconId,
|
||||
bizId: lazyDaisyID,
|
||||
spId: sp.ID
|
||||
spId: sp.ServicePointID
|
||||
}, { datasource: "payfrit" });
|
||||
|
||||
response.steps.append("Created beacon '" & beaconName & "' (ID: " & newBeaconId & ") -> " & sp.Name);
|
||||
response.steps.append("Created beacon '" & beaconName & "' (ID: " & newBeaconId & ") -> " & sp.ServicePointName);
|
||||
beaconsCreated++;
|
||||
} else {
|
||||
response.steps.append("Beacon '" & beaconName & "' already exists, skipping");
|
||||
|
|
@ -69,14 +69,13 @@ try {
|
|||
|
||||
// Get final status
|
||||
qFinal = queryExecute("
|
||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
||||
b.Name AS BeaconName, b.UUID, sp.Name AS ServicePointName,
|
||||
biz.Name AS BusinessName
|
||||
FROM ServicePoints sp
|
||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
||||
WHERE sp.BusinessID = :bizId AND sp.BeaconID IS NOT NULL
|
||||
ORDER BY sp.Name
|
||||
SELECT lt.BeaconID, b.BeaconUUID, b.BeaconName, lt.BusinessID, biz.BusinessName, lt.ServicePointID, sp.ServicePointName
|
||||
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||
JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||
WHERE lt.BusinessID = :bizId
|
||||
ORDER BY sp.ServicePointName
|
||||
", { bizId: lazyDaisyID }, { datasource: "payfrit" });
|
||||
|
||||
beacons = [];
|
||||
|
|
@ -84,9 +83,8 @@ try {
|
|||
arrayAppend(beacons, {
|
||||
"BeaconID": qFinal.BeaconID[i],
|
||||
"BeaconName": qFinal.BeaconName[i],
|
||||
"UUID": qFinal.UUID[i],
|
||||
"UUID": qFinal.BeaconUUID[i],
|
||||
"BusinessName": qFinal.BusinessName[i],
|
||||
"ServicePointID": qFinal.ServicePointID[i],
|
||||
"ServicePointName": qFinal.ServicePointName[i]
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,19 +13,19 @@ try {
|
|||
// Hours: Mon-Thu: 11am-10pm, Fri-Sat: 11am-11pm, Sun: 11am-10pm
|
||||
|
||||
// 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
|
||||
|
||||
// Check if Big Dean's already has an address
|
||||
existingAddr = queryExecute("
|
||||
SELECT ID FROM Addresses
|
||||
WHERE BusinessID = :bizId AND UserID = 0
|
||||
SELECT AddressID FROM Addresses
|
||||
WHERE AddressBusinessID = :bizId AND AddressUserID = 0
|
||||
", { bizId: businessId });
|
||||
|
||||
if (existingAddr.recordCount == 0) {
|
||||
// Insert new address
|
||||
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())
|
||||
", {
|
||||
bizId: businessId,
|
||||
|
|
@ -39,8 +39,8 @@ try {
|
|||
// Update existing address
|
||||
queryExecute("
|
||||
UPDATE Addresses
|
||||
SET Line1 = :line1, City = :city, StateID = :stateId, ZIPCode = :zip
|
||||
WHERE BusinessID = :bizId AND UserID = 0
|
||||
SET AddressLine1 = :line1, AddressCity = :city, AddressStateID = :stateId, AddressZIPCode = :zip
|
||||
WHERE AddressBusinessID = :bizId AND AddressUserID = 0
|
||||
", {
|
||||
bizId: businessId,
|
||||
line1: "1615 Ocean Front Walk",
|
||||
|
|
@ -53,7 +53,7 @@ try {
|
|||
|
||||
// Check existing hours for this business
|
||||
existingHours = queryExecute("
|
||||
SELECT COUNT(*) as cnt FROM Hours WHERE BusinessID = :bizId
|
||||
SELECT COUNT(*) as cnt FROM Hours WHERE HoursBusinessID = :bizId
|
||||
", { bizId: businessId });
|
||||
|
||||
if (existingHours.cnt == 0) {
|
||||
|
|
@ -64,39 +64,39 @@ try {
|
|||
// Sun: 11am-10pm (day 1)
|
||||
|
||||
// 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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";
|
||||
} else {
|
||||
// Update existing hours
|
||||
// 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
|
||||
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";
|
||||
}
|
||||
|
||||
// Update phone on Businesses table (if column exists)
|
||||
try {
|
||||
queryExecute("UPDATE Businesses SET Phone = :phone WHERE ID = :bizId", {
|
||||
queryExecute("UPDATE Businesses SET BusinessPhone = :phone WHERE BusinessID = :bizId", {
|
||||
phone: "(310) 393-2666",
|
||||
bizId: businessId
|
||||
});
|
||||
|
|
@ -107,35 +107,35 @@ try {
|
|||
|
||||
// Verify the data
|
||||
address = queryExecute("
|
||||
SELECT a.*, s.Abbreviation
|
||||
SELECT a.*, s.tt_StateAbbreviation
|
||||
FROM Addresses a
|
||||
LEFT JOIN tt_States s ON s.ID = a.StateID
|
||||
WHERE a.BusinessID = :bizId AND a.UserID = 0
|
||||
LEFT JOIN tt_States s ON s.tt_StateID = a.AddressStateID
|
||||
WHERE a.AddressBusinessID = :bizId AND a.AddressUserID = 0
|
||||
", { bizId: businessId });
|
||||
|
||||
hours = queryExecute("
|
||||
SELECT h.*, d.tt_DayName
|
||||
FROM Hours h
|
||||
JOIN tt_Days d ON d.ID = h.DayID
|
||||
WHERE h.BusinessID = :bizId
|
||||
ORDER BY h.DayID
|
||||
JOIN tt_Days d ON d.tt_DayID = h.HoursDayID
|
||||
WHERE h.HoursBusinessID = :bizId
|
||||
ORDER BY h.HoursDayID
|
||||
", { bizId: businessId });
|
||||
|
||||
response["OK"] = true;
|
||||
response["BUSINESS_ID"] = businessId;
|
||||
response["ADDRESS"] = address.recordCount > 0 ? {
|
||||
"line1": address.Line1,
|
||||
"city": address.City,
|
||||
"state": address.Abbreviation,
|
||||
"zip": address.ZIPCode
|
||||
"line1": address.AddressLine1,
|
||||
"city": address.AddressCity,
|
||||
"state": address.tt_StateAbbreviation,
|
||||
"zip": address.AddressZIPCode
|
||||
} : "not found";
|
||||
|
||||
hoursArr = [];
|
||||
for (h in hours) {
|
||||
arrayAppend(hoursArr, {
|
||||
"day": h.tt_DayName,
|
||||
"open": timeFormat(h.OpenTime, "h:mm tt"),
|
||||
"close": timeFormat(h.ClosingTime, "h:mm tt")
|
||||
"open": timeFormat(h.HoursOpenTime, "h:mm tt"),
|
||||
"close": timeFormat(h.HoursClosingTime, "h:mm tt")
|
||||
});
|
||||
}
|
||||
response["HOURS"] = hoursArr;
|
||||
|
|
|
|||
|
|
@ -9,19 +9,19 @@ response = { "OK": false };
|
|||
try {
|
||||
// Check if Big Dean's already has stations
|
||||
existing = queryExecute("
|
||||
SELECT COUNT(*) as cnt FROM Stations WHERE BusinessID = :bizId
|
||||
SELECT COUNT(*) as cnt FROM Stations WHERE StationBusinessID = :bizId
|
||||
", { bizId: businessId });
|
||||
|
||||
if (existing.cnt == 0) {
|
||||
// Insert Kitchen station
|
||||
queryExecute("
|
||||
INSERT INTO Stations (BusinessID, Name, Color, SortOrder, IsActive)
|
||||
INSERT INTO Stations (StationBusinessID, StationName, StationColor, StationSortOrder, StationIsActive)
|
||||
VALUES (:bizId, 'Kitchen', :color1, 1, 1)
|
||||
", { bizId: businessId, color1: "##FF5722" });
|
||||
|
||||
// Insert Bar station
|
||||
queryExecute("
|
||||
INSERT INTO Stations (BusinessID, Name, Color, SortOrder, IsActive)
|
||||
INSERT INTO Stations (StationBusinessID, StationName, StationColor, StationSortOrder, StationIsActive)
|
||||
VALUES (:bizId, 'Bar', :color2, 2, 1)
|
||||
", { bizId: businessId, color2: "##2196F3" });
|
||||
|
||||
|
|
@ -32,18 +32,18 @@ try {
|
|||
|
||||
// Get current stations
|
||||
stations = queryExecute("
|
||||
SELECT ID, Name, Color, SortOrder
|
||||
SELECT StationID, StationName, StationColor, StationSortOrder
|
||||
FROM Stations
|
||||
WHERE BusinessID = :bizId AND IsActive = 1
|
||||
ORDER BY SortOrder
|
||||
WHERE StationBusinessID = :bizId AND StationIsActive = 1
|
||||
ORDER BY StationSortOrder
|
||||
", { bizId: businessId });
|
||||
|
||||
stationArr = [];
|
||||
for (s in stations) {
|
||||
arrayAppend(stationArr, {
|
||||
"StationID": s.ID,
|
||||
"Name": s.Name,
|
||||
"Color": s.Color
|
||||
"StationID": s.StationID,
|
||||
"StationName": s.StationName,
|
||||
"StationColor": s.StationColor
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,62 +9,67 @@ try {
|
|||
lazyDaisyID = 37;
|
||||
|
||||
// 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");
|
||||
|
||||
// Create service point for Table 1 if it doesn't exist
|
||||
qSP = queryExecute("
|
||||
SELECT ID FROM ServicePoints
|
||||
WHERE BusinessID = :bizID AND Name = 'Table 1'
|
||||
SELECT ServicePointID FROM ServicePoints
|
||||
WHERE ServicePointBusinessID = :bizID AND ServicePointName = 'Table 1'
|
||||
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||
|
||||
if (qSP.recordCount == 0) {
|
||||
queryExecute("
|
||||
INSERT INTO ServicePoints (BusinessID, Name)
|
||||
VALUES (:bizID, 'Table 1')
|
||||
INSERT INTO ServicePoints (ServicePointBusinessID, ServicePointName, ServicePointTypeID)
|
||||
VALUES (:bizID, 'Table 1', 1)
|
||||
", { bizID: lazyDaisyID }, { datasource: "payfrit" });
|
||||
qSP = queryExecute("SELECT LAST_INSERT_ID() as id", {}, { datasource: "payfrit" });
|
||||
servicePointID = qSP.id;
|
||||
response.steps.append("Created service point 'Table 1' (ID: " & servicePointID & ")");
|
||||
} else {
|
||||
servicePointID = qSP.ID;
|
||||
servicePointID = qSP.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++) {
|
||||
beaconID = qBeacons.ID[i];
|
||||
beaconID = qBeacons.BeaconID[i];
|
||||
|
||||
// Unassign this beacon from any other service point first
|
||||
queryExecute("
|
||||
UPDATE ServicePoints SET BeaconID = NULL, AssignedByUserID = NULL
|
||||
WHERE BeaconID = :beaconID
|
||||
// Check if mapping exists
|
||||
qMap = queryExecute("
|
||||
SELECT * FROM lt_Beacon_Businesses_ServicePoints WHERE BeaconID = :beaconID
|
||||
", { beaconID: beaconID }, { datasource: "payfrit" });
|
||||
|
||||
// Assign beacon to Table 1 service point
|
||||
queryExecute("
|
||||
UPDATE ServicePoints SET BeaconID = :beaconID, AssignedByUserID = 1
|
||||
WHERE ID = :spID AND BusinessID = :bizID
|
||||
", { beaconID: beaconID, bizID: lazyDaisyID, spID: servicePointID }, { datasource: "payfrit" });
|
||||
response.steps.append("Assigned beacon " & beaconID & " to Table 1");
|
||||
if (qMap.recordCount == 0) {
|
||||
queryExecute("
|
||||
INSERT INTO lt_Beacon_Businesses_ServicePoints (BeaconID, BusinessID, ServicePointID)
|
||||
VALUES (:beaconID, :bizID, :spID)
|
||||
", { beaconID: beaconID, bizID: lazyDaisyID, spID: servicePointID }, { datasource: "payfrit" });
|
||||
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
|
||||
qFinal = queryExecute("
|
||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
||||
b.Name AS BeaconName, b.UUID, sp.Name AS ServicePointName,
|
||||
biz.Name AS BusinessName
|
||||
FROM ServicePoints sp
|
||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
||||
WHERE sp.BeaconID IS NOT NULL
|
||||
SELECT lt.BeaconID, b.BeaconUUID, lt.BusinessID, biz.BusinessName, lt.ServicePointID, sp.ServicePointName
|
||||
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||
JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
beacons = [];
|
||||
for (i = 1; i <= qFinal.recordCount; i++) {
|
||||
arrayAppend(beacons, {
|
||||
"BeaconID": qFinal.BeaconID[i],
|
||||
"UUID": qFinal.UUID[i],
|
||||
"UUID": qFinal.BeaconUUID[i],
|
||||
"BusinessID": qFinal.BusinessID[i],
|
||||
"BusinessName": qFinal.BusinessName[i],
|
||||
"ServicePointID": qFinal.ServicePointID[i],
|
||||
|
|
|
|||
|
|
@ -11,32 +11,32 @@
|
|||
<cfscript>
|
||||
/**
|
||||
* Setup Modifier Templates system
|
||||
* 1. Add IsModifierTemplate column to Items
|
||||
* 2. Create lt_ItemID_TemplateItemID table
|
||||
* 1. Add ItemIsModifierTemplate column to Items
|
||||
* 2. Create ItemTemplateLinks table
|
||||
*/
|
||||
|
||||
response = { "OK": false, "steps": [] };
|
||||
|
||||
try {
|
||||
// Step 1: Add IsModifierTemplate column if it doesn't exist
|
||||
// Step 1: Add ItemIsModifierTemplate column if it doesn't exist
|
||||
try {
|
||||
queryExecute("
|
||||
ALTER TABLE Items ADD COLUMN IsModifierTemplate TINYINT(1) DEFAULT 0
|
||||
ALTER TABLE Items ADD COLUMN ItemIsModifierTemplate TINYINT(1) DEFAULT 0
|
||||
", {}, { datasource: "payfrit" });
|
||||
arrayAppend(response.steps, "Added IsModifierTemplate column");
|
||||
arrayAppend(response.steps, "Added ItemIsModifierTemplate column");
|
||||
} catch (any e) {
|
||||
if (findNoCase("Duplicate column", e.message)) {
|
||||
arrayAppend(response.steps, "IsModifierTemplate column already exists");
|
||||
arrayAppend(response.steps, "ItemIsModifierTemplate column already exists");
|
||||
} else {
|
||||
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 {
|
||||
queryExecute("
|
||||
CREATE TABLE IF NOT EXISTS lt_ItemID_TemplateItemID (
|
||||
ID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
CREATE TABLE IF NOT EXISTS ItemTemplateLinks (
|
||||
LinkID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ItemID INT NOT NULL,
|
||||
TemplateItemID INT NOT NULL,
|
||||
SortOrder INT DEFAULT 0,
|
||||
|
|
@ -45,9 +45,9 @@ try {
|
|||
INDEX idx_template (TemplateItemID)
|
||||
)
|
||||
", {}, { datasource: "payfrit" });
|
||||
arrayAppend(response.steps, "Created lt_ItemID_TemplateItemID table");
|
||||
arrayAppend(response.steps, "Created ItemTemplateLinks table");
|
||||
} catch (any e) {
|
||||
arrayAppend(response.steps, "lt_ItemID_TemplateItemID: " & e.message);
|
||||
arrayAppend(response.steps, "ItemTemplateLinks: " & e.message);
|
||||
}
|
||||
|
||||
response["OK"] = true;
|
||||
|
|
|
|||
|
|
@ -13,20 +13,20 @@
|
|||
<cfset queryExecute("
|
||||
CREATE TABLE IF NOT EXISTS Stations (
|
||||
StationID INT AUTO_INCREMENT PRIMARY KEY,
|
||||
BusinessID INT NOT NULL,
|
||||
Name VARCHAR(100) NOT NULL,
|
||||
Color VARCHAR(7) DEFAULT '##666666',
|
||||
SortOrder INT DEFAULT 0,
|
||||
IsActive TINYINT(1) DEFAULT 1,
|
||||
AddedOn DATETIME DEFAULT NOW(),
|
||||
FOREIGN KEY (BusinessID) REFERENCES Businesses(BusinessID)
|
||||
StationBusinessID INT NOT NULL,
|
||||
StationName VARCHAR(100) NOT NULL,
|
||||
StationColor VARCHAR(7) DEFAULT '##666666',
|
||||
StationSortOrder INT DEFAULT 0,
|
||||
StationIsActive TINYINT(1) DEFAULT 1,
|
||||
StationAddedOn DATETIME DEFAULT NOW(),
|
||||
FOREIGN KEY (StationBusinessID) REFERENCES Businesses(BusinessID)
|
||||
)
|
||||
", [], { 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>
|
||||
<cfset queryExecute("
|
||||
ALTER TABLE Items ADD COLUMN StationID INT DEFAULT NULL
|
||||
ALTER TABLE Items ADD COLUMN ItemStationID INT DEFAULT NULL
|
||||
", [], { datasource = "payfrit" })>
|
||||
<cfset stationColumnAdded = true>
|
||||
<cfcatch>
|
||||
|
|
@ -39,7 +39,7 @@
|
|||
<cfif stationColumnAdded>
|
||||
<cftry>
|
||||
<cfset queryExecute("
|
||||
ALTER TABLE Items ADD FOREIGN KEY (StationID) REFERENCES Stations(StationID)
|
||||
ALTER TABLE Items ADD FOREIGN KEY (ItemStationID) REFERENCES Stations(StationID)
|
||||
", [], { datasource = "payfrit" })>
|
||||
<cfcatch></cfcatch>
|
||||
</cftry>
|
||||
|
|
@ -47,12 +47,12 @@
|
|||
|
||||
<!--- Create some default stations for business 1 (In and Out Burger) if none exist --->
|
||||
<cfset qCheck = queryExecute("
|
||||
SELECT COUNT(*) AS cnt FROM Stations WHERE BusinessID = 1
|
||||
SELECT COUNT(*) AS cnt FROM Stations WHERE StationBusinessID = 1
|
||||
", [], { datasource = "payfrit" })>
|
||||
|
||||
<cfif qCheck.cnt EQ 0>
|
||||
<cfset queryExecute("
|
||||
INSERT INTO Stations (BusinessID, Name, Color, SortOrder) VALUES
|
||||
INSERT INTO Stations (StationBusinessID, StationName, StationColor, StationSortOrder) VALUES
|
||||
(1, 'Grill', '##FF5722', 1),
|
||||
(1, 'Fry', '##FFC107', 2),
|
||||
(1, 'Drinks', '##2196F3', 3),
|
||||
|
|
|
|||
|
|
@ -3,57 +3,36 @@
|
|||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
|
||||
<cfscript>
|
||||
// Switch beacon mapping from one business to another via join table.
|
||||
// Beacons.BusinessID (owner) is NOT touched.
|
||||
// Switch all beacons from one business to another
|
||||
fromBiz = 17; // In-N-Out
|
||||
toBiz = 27; // Big Dean's
|
||||
|
||||
// Remove mapping for source business
|
||||
queryExecute("
|
||||
DELETE FROM lt_BeaconsID_BusinessesID
|
||||
WHERE BusinessID = :fromBiz
|
||||
", { fromBiz: fromBiz }, { datasource: "payfrit" });
|
||||
|
||||
// Add mapping for target business (for beacons owned by source)
|
||||
queryExecute("
|
||||
INSERT INTO lt_BeaconsID_BusinessesID (BeaconID, BusinessID)
|
||||
SELECT ID, :toBiz FROM Beacons WHERE BusinessID = :fromBiz
|
||||
ON DUPLICATE KEY UPDATE ID = ID
|
||||
UPDATE lt_Beacon_Businesses_ServicePoints
|
||||
SET BusinessID = :toBiz
|
||||
WHERE BusinessID = :fromBiz
|
||||
", { toBiz: toBiz, fromBiz: fromBiz }, { datasource: "payfrit" });
|
||||
|
||||
// Clear ServicePoints.BeaconID for source business (no longer valid)
|
||||
queryExecute("
|
||||
UPDATE ServicePoints
|
||||
SET BeaconID = NULL, AssignedByUserID = NULL
|
||||
WHERE BusinessID = :fromBiz AND BeaconID IS NOT NULL
|
||||
", { fromBiz: fromBiz }, { datasource: "payfrit" });
|
||||
|
||||
// Get current state
|
||||
q = queryExecute("
|
||||
SELECT sp.ID AS ServicePointID, sp.BeaconID, sp.BusinessID,
|
||||
b.Name AS BeaconName, biz.Name AS BusinessName,
|
||||
sp.Name AS ServicePointName
|
||||
FROM ServicePoints sp
|
||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
||||
JOIN Businesses biz ON biz.ID = sp.BusinessID
|
||||
WHERE sp.BeaconID IS NOT NULL
|
||||
SELECT lt.*, b.BusinessName
|
||||
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||
JOIN Businesses b ON b.BusinessID = lt.BusinessID
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
rows = [];
|
||||
for (row in q) {
|
||||
arrayAppend(rows, {
|
||||
"BeaconID": row.BeaconID,
|
||||
"BeaconName": row.BeaconName,
|
||||
"BusinessID": row.BusinessID,
|
||||
"BusinessName": row.BusinessName,
|
||||
"ServicePointID": row.ServicePointID,
|
||||
"ServicePointName": row.ServicePointName
|
||||
});
|
||||
arrayAppend(rows, {
|
||||
"BeaconID": row.BeaconID,
|
||||
"BusinessID": row.BusinessID,
|
||||
"BusinessName": row.BusinessName,
|
||||
"ServicePointID": row.ServicePointID
|
||||
});
|
||||
}
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
"OK": true,
|
||||
"MESSAGE": "Switched beacons from BusinessID #fromBiz# to #toBiz#",
|
||||
"MAPPINGS": rows
|
||||
"OK": true,
|
||||
"MESSAGE": "Switched beacons from BusinessID #fromBiz# to #toBiz#",
|
||||
"MAPPINGS": rows
|
||||
}));
|
||||
</cfscript>
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@
|
|||
<cfset queryExecute(
|
||||
"
|
||||
INSERT INTO Tasks (
|
||||
BusinessID,
|
||||
OrderID,
|
||||
ClaimedByUserID,
|
||||
CreatedOn
|
||||
TaskBusinessID,
|
||||
TaskOrderID,
|
||||
TaskClaimedByUserID,
|
||||
TaskAddedOn
|
||||
) VALUES (
|
||||
1,
|
||||
999,
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@
|
|||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
<cfscript>
|
||||
qTask = queryExecute("
|
||||
SELECT ID, TaskTypeID, ClaimedByUserID, CompletedOn
|
||||
SELECT TaskID, TaskTypeID, TaskClaimedByUserID, TaskCompletedOn
|
||||
FROM Tasks
|
||||
WHERE ID = 57
|
||||
WHERE TaskID = 57
|
||||
", [], { datasource: "payfrit" });
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
"OK": true,
|
||||
"TaskID": qTask.ID,
|
||||
"TaskID": qTask.TaskID,
|
||||
"TaskTypeID": qTask.TaskTypeID,
|
||||
"ClaimedByUserID": qTask.ClaimedByUserID,
|
||||
"CompletedOn": qTask.CompletedOn
|
||||
"TaskClaimedByUserID": qTask.TaskClaimedByUserID,
|
||||
"TaskCompletedOn": qTask.TaskCompletedOn
|
||||
}));
|
||||
</cfscript>
|
||||
|
|
|
|||
|
|
@ -3,65 +3,50 @@
|
|||
<cfcontent type="application/json; charset=utf-8" reset="true">
|
||||
|
||||
<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;
|
||||
oldBusinessId = 37; // previous mapping
|
||||
newBusinessId = 17;
|
||||
|
||||
// Remove old mapping
|
||||
queryExecute("
|
||||
DELETE FROM lt_BeaconsID_BusinessesID
|
||||
WHERE BeaconID = :beaconId AND BusinessID = :oldBizId
|
||||
", { beaconId: beaconId, oldBizId: oldBusinessId }, { datasource: "payfrit" });
|
||||
|
||||
// Add new mapping
|
||||
queryExecute("
|
||||
INSERT INTO lt_BeaconsID_BusinessesID (BeaconID, BusinessID)
|
||||
VALUES (:beaconId, :newBizId)
|
||||
ON DUPLICATE KEY UPDATE ID = ID
|
||||
", { beaconId: beaconId, newBizId: newBusinessId }, { datasource: "payfrit" });
|
||||
|
||||
// Clear ServicePoints.BeaconID for old business where this beacon was assigned
|
||||
queryExecute("
|
||||
UPDATE ServicePoints
|
||||
SET BeaconID = NULL, AssignedByUserID = NULL
|
||||
WHERE BeaconID = :beaconId AND BusinessID = :oldBizId
|
||||
", { beaconId: beaconId, oldBizId: oldBusinessId }, { datasource: "payfrit" });
|
||||
UPDATE lt_Beacon_Businesses_ServicePoints
|
||||
SET BusinessID = :newBizId
|
||||
WHERE BeaconID = :beaconId
|
||||
", { newBizId: newBusinessId, beaconId: beaconId }, { datasource: "payfrit" });
|
||||
|
||||
// Get current state
|
||||
q = queryExecute("
|
||||
SELECT
|
||||
b.ID AS BeaconID,
|
||||
b.UUID,
|
||||
b.Name AS BeaconName,
|
||||
b.BusinessID AS BeaconBusinessID,
|
||||
sp.ID AS ServicePointID,
|
||||
sp.Name AS ServicePointName,
|
||||
sp.BusinessID AS ServicePointBusinessID,
|
||||
biz.Name AS BusinessName
|
||||
FROM Beacons b
|
||||
LEFT JOIN ServicePoints sp ON sp.BeaconID = b.ID
|
||||
LEFT JOIN Businesses biz ON biz.ID = b.BusinessID
|
||||
WHERE b.IsActive = 1
|
||||
ORDER BY b.ID
|
||||
SELECT
|
||||
b.BeaconID,
|
||||
b.BeaconUUID,
|
||||
b.BeaconName,
|
||||
lt.BusinessID,
|
||||
lt.ServicePointID,
|
||||
biz.BusinessName,
|
||||
sp.ServicePointName
|
||||
FROM Beacons b
|
||||
LEFT JOIN lt_Beacon_Businesses_ServicePoints lt ON lt.BeaconID = b.BeaconID
|
||||
LEFT JOIN Businesses biz ON biz.BusinessID = lt.BusinessID
|
||||
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||
WHERE b.BeaconIsActive = 1
|
||||
ORDER BY b.BeaconID
|
||||
", {}, { datasource: "payfrit" });
|
||||
|
||||
rows = [];
|
||||
for (row in q) {
|
||||
arrayAppend(rows, {
|
||||
"BeaconID": row.BeaconID,
|
||||
"UUID": row.UUID,
|
||||
"BeaconName": row.BeaconName,
|
||||
"BeaconBusinessID": row.BeaconBusinessID,
|
||||
"BusinessName": row.BusinessName,
|
||||
"ServicePointID": row.ServicePointID ?: 0,
|
||||
"ServicePointName": row.ServicePointName ?: ""
|
||||
});
|
||||
arrayAppend(rows, {
|
||||
"BeaconID": row.BeaconID,
|
||||
"BeaconUUID": row.BeaconUUID,
|
||||
"BeaconName": row.BeaconName ?: "",
|
||||
"BusinessID": row.BusinessID ?: 0,
|
||||
"BusinessName": row.BusinessName ?: "",
|
||||
"ServicePointID": row.ServicePointID ?: 0,
|
||||
"ServicePointName": row.ServicePointName ?: ""
|
||||
});
|
||||
}
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
"OK": true,
|
||||
"MESSAGE": "Updated beacon #beaconId# to BusinessID #newBusinessId#",
|
||||
"BEACONS": rows
|
||||
"OK": true,
|
||||
"MESSAGE": "Updated beacon #beaconId# to BusinessID #newBusinessId#",
|
||||
"BEACONS": rows
|
||||
}));
|
||||
</cfscript>
|
||||
|
|
|
|||
|
|
@ -6,68 +6,72 @@
|
|||
// Update Big Dean's business info
|
||||
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";
|
||||
hours = "Mon-Thu: 11am-10pm, Fri-Sat: 11am-11pm, Sun: 11am-10pm";
|
||||
|
||||
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("
|
||||
UPDATE Businesses
|
||||
SET Phone = :phone,
|
||||
Hours = :hours
|
||||
WHERE ID = :bizId
|
||||
SET BusinessAddress = :address,
|
||||
BusinessPhone = :phone,
|
||||
BusinessHours = :hours
|
||||
WHERE BusinessID = :bizId
|
||||
", {
|
||||
address: address,
|
||||
phone: phone,
|
||||
hours: hours,
|
||||
bizId: businessId
|
||||
}, { datasource: "payfrit" });
|
||||
|
||||
// Update or insert address in Addresses table
|
||||
qAddr = queryExecute("
|
||||
SELECT ID FROM Addresses
|
||||
WHERE BusinessID = :bizId AND IsDeleted = 0
|
||||
LIMIT 1
|
||||
", { bizId: businessId }, { datasource: "payfrit" });
|
||||
|
||||
if (qAddr.recordCount > 0) {
|
||||
queryExecute("
|
||||
UPDATE Addresses
|
||||
SET Line1 = :line1, City = :city, ZIPCode = :zip
|
||||
WHERE ID = :addrId
|
||||
", {
|
||||
line1: "1615 Ocean Front Walk",
|
||||
city: "Santa Monica",
|
||||
zip: "90401",
|
||||
addrId: qAddr.ID
|
||||
}, { datasource: "payfrit" });
|
||||
} else {
|
||||
queryExecute("
|
||||
INSERT INTO Addresses (BusinessID, UserID, AddressTypeID, Line1, City, ZIPCode, AddedOn)
|
||||
VALUES (:bizId, 0, 'business', :line1, :city, :zip, NOW())
|
||||
", {
|
||||
bizId: businessId,
|
||||
line1: "1615 Ocean Front Walk",
|
||||
city: "Santa Monica",
|
||||
zip: "90401"
|
||||
}, { datasource: "payfrit" });
|
||||
}
|
||||
});
|
||||
|
||||
// Get updated record
|
||||
updated = queryExecute("
|
||||
SELECT ID, Name, Phone, Hours
|
||||
SELECT BusinessID, BusinessName, BusinessAddress, BusinessPhone, BusinessHours
|
||||
FROM Businesses
|
||||
WHERE ID = :bizId
|
||||
", { bizId: businessId }, { datasource: "payfrit" });
|
||||
WHERE BusinessID = :bizId
|
||||
", { bizId: businessId });
|
||||
|
||||
writeOutput(serializeJSON({
|
||||
"OK": true,
|
||||
"MESSAGE": "Updated Big Dean's info",
|
||||
"COLUMNS_EXISTED": { "address": hasAddress, "phone": hasPhone, "hours": hasHours },
|
||||
"BUSINESS": {
|
||||
"BusinessID": updated.ID,
|
||||
"Name": updated.Name,
|
||||
"Phone": updated.Phone,
|
||||
"Hours": updated.Hours
|
||||
"BusinessID": updated.BusinessID,
|
||||
"BusinessName": updated.BusinessName,
|
||||
"BusinessAddress": updated.BusinessAddress,
|
||||
"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 ---------- */
|
||||
data = readJsonBody();
|
||||
|
||||
if (!structKeyExists(data,"ServicePointID") || !isNumeric(data.ServicePointID) || int(data.ServicePointID) LTE 0){
|
||||
apiAbort({OK=false,ERROR="missing_ServicePointID"});
|
||||
if (
|
||||
!structKeyExists(data,"lt_Beacon_Businesses_ServicePointID")
|
||||
|| !isNumeric(data.lt_Beacon_Businesses_ServicePointID)
|
||||
|| int(data.lt_Beacon_Businesses_ServicePointID) LTE 0
|
||||
){
|
||||
apiAbort({OK=false,ERROR="missing_lt_Beacon_Businesses_ServicePointID"});
|
||||
}
|
||||
|
||||
ServicePointID = int(data.ServicePointID);
|
||||
RelID = int(data.lt_Beacon_Businesses_ServicePointID);
|
||||
</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">
|
||||
SELECT ID, BeaconID
|
||||
FROM ServicePoints
|
||||
WHERE ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#ServicePointID#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
AND BeaconID IS NOT NULL
|
||||
SELECT
|
||||
lt_Beacon_Businesses_ServicePointID,
|
||||
BeaconID,
|
||||
ServicePointID
|
||||
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
|
||||
</cfquery>
|
||||
|
||||
|
|
@ -55,28 +63,28 @@ ServicePointID = int(data.ServicePointID);
|
|||
<cfoutput>#serializeJSON({
|
||||
"OK"=false,
|
||||
"ERROR"="not_found",
|
||||
"ServicePointID"=ServicePointID,
|
||||
"lt_Beacon_Businesses_ServicePointID"=RelID,
|
||||
"BusinessID"=(request.BusinessID & "")
|
||||
})#</cfoutput>
|
||||
<cfabort>
|
||||
</cfif>
|
||||
|
||||
<cfset removedBeaconID = qFind.BeaconID>
|
||||
|
||||
<!--- Unassign beacon from service point --->
|
||||
<!--- Delete it --->
|
||||
<cfquery datasource="payfrit">
|
||||
UPDATE ServicePoints
|
||||
SET BeaconID = NULL,
|
||||
AssignedByUserID = NULL
|
||||
WHERE ID = <cfqueryparam cfsqltype="cf_sql_integer" value="#ServicePointID#">
|
||||
AND BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
DELETE 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
|
||||
</cfquery>
|
||||
|
||||
<cfoutput>#serializeJSON({
|
||||
"OK"=true,
|
||||
"ERROR"="",
|
||||
"ACTION"="unassigned",
|
||||
"ServicePointID"=ServicePointID,
|
||||
"BeaconID"=removedBeaconID,
|
||||
"ACTION"="deleted",
|
||||
"lt_Beacon_Businesses_ServicePointID"=RelID,
|
||||
"BeaconID"=qFind.BeaconID,
|
||||
"ServicePointID"=qFind.ServicePointID,
|
||||
"BusinessID"=(request.BusinessID & "")
|
||||
})#</cfoutput>
|
||||
|
|
|
|||
|
|
@ -17,29 +17,32 @@ if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) ||
|
|||
|
||||
<cfquery name="q" datasource="payfrit">
|
||||
SELECT
|
||||
sp.ID AS ServicePointID,
|
||||
sp.BeaconID,
|
||||
sp.BusinessID,
|
||||
sp.AssignedByUserID,
|
||||
b.Name AS BeaconName,
|
||||
b.UUID,
|
||||
sp.Name AS ServicePointName
|
||||
FROM ServicePoints sp
|
||||
JOIN Beacons b ON b.ID = sp.BeaconID
|
||||
WHERE sp.BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
AND sp.BeaconID IS NOT NULL
|
||||
ORDER BY b.Name, sp.Name
|
||||
lt.lt_Beacon_Businesses_ServicePointID,
|
||||
lt.BeaconID,
|
||||
lt.BusinessID,
|
||||
lt.ServicePointID,
|
||||
lt.lt_Beacon_Businesses_ServicePointNotes,
|
||||
b.BeaconName,
|
||||
b.BeaconUUID,
|
||||
sp.ServicePointName
|
||||
FROM lt_Beacon_Businesses_ServicePoints lt
|
||||
JOIN Beacons b ON b.BeaconID = lt.BeaconID
|
||||
LEFT JOIN ServicePoints sp ON sp.ServicePointID = lt.ServicePointID
|
||||
WHERE lt.BusinessID = <cfqueryparam cfsqltype="cf_sql_integer" value="#request.BusinessID#">
|
||||
ORDER BY b.BeaconName, sp.ServicePointName
|
||||
</cfquery>
|
||||
|
||||
<cfset assignments = []>
|
||||
<cfloop query="q">
|
||||
<cfset arrayAppend(assignments, {
|
||||
"ServicePointID" = q.ServicePointID,
|
||||
"lt_Beacon_Businesses_ServicePointID" = q.lt_Beacon_Businesses_ServicePointID,
|
||||
"BeaconID" = q.BeaconID,
|
||||
"BusinessID" = q.BusinessID,
|
||||
"ServicePointID" = q.ServicePointID,
|
||||
"BeaconName" = q.BeaconName,
|
||||
"UUID" = q.UUID,
|
||||
"ServicePointName"= q.ServicePointName
|
||||
"BeaconUUID" = q.BeaconUUID,
|
||||
"ServicePointName"= q.ServicePointName,
|
||||
"lt_Beacon_Businesses_ServicePointNotes" = q.lt_Beacon_Businesses_ServicePointNotes
|
||||
})>
|
||||
</cfloop>
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue