Implement polling-based order status notifications

Backend changes:
- New API endpoint: checkStatusUpdate.cfm - polls order status and detects changes
- Updated admin.html: added test section for manually updating order status
- Status flow: 1(submitted) → 2(preparing) → 3(ready) → 4(completed)
- Human-readable status messages for each state

Testing interface:
- Order ID input field
- Status dropdown selector
- Direct integration with existing updateStatus.cfm endpoint

This enables real-time status notifications for customer orders with 30-second polling interval (Option 2 approach, with planned migration to self-hosted push).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
John Mizerek 2025-12-31 16:07:09 -08:00
parent b812222314
commit ecea71c533
2 changed files with 168 additions and 0 deletions

View file

@ -0,0 +1,105 @@
<cfset payload = {
"OK": false,
"ERROR": "",
"HAS_UPDATE": false,
"ORDER_STATUS": {},
"MESSAGE": ""
}>
<cftry>
<!--- Parse request body --->
<cfset requestBody = toString(getHttpRequestData().content)>
<cfset params = deserializeJSON(requestBody)>
<!--- Validate required parameters --->
<cfif not structKeyExists(params, "OrderID")>
<cfset payload.ERROR = "OrderID is required">
<cfabort>
</cfif>
<cfif not structKeyExists(params, "LastKnownStatusID")>
<cfset payload.ERROR = "LastKnownStatusID is required">
<cfabort>
</cfif>
<cfset OrderID = params.OrderID>
<cfset LastKnownStatusID = params.LastKnownStatusID>
<!--- Query current order status --->
<cfquery name="qOrder" datasource="payfrit">
SELECT
OrderID,
OrderStatusID,
OrderLastEditedOn,
OrderServicePointID,
OrderBusinessID,
OrderUserID
FROM Orders
WHERE OrderID = <cfqueryparam value="#OrderID#" cfsqltype="cf_sql_integer">
AND OrderIsDeleted = <cfqueryparam value="0" cfsqltype="cf_sql_bit">
</cfquery>
<cfif qOrder.recordCount EQ 0>
<cfset payload.ERROR = "Order not found or deleted">
<cfabort>
</cfif>
<!--- Check if status has changed --->
<cfset currentStatus = qOrder.OrderStatusID>
<cfset hasUpdate = (currentStatus NEQ LastKnownStatusID)>
<!--- Build response --->
<cfset payload.OK = true>
<cfset payload.HAS_UPDATE = hasUpdate>
<cfif hasUpdate>
<!--- Map status ID to human-readable message --->
<cfswitch expression="#currentStatus#">
<cfcase value="0">
<cfset statusName = "Cart">
<cfset statusMessage = "Your order is in the cart">
</cfcase>
<cfcase value="1">
<cfset statusName = "Submitted">
<cfset statusMessage = "Your order has been received and is being prepared">
</cfcase>
<cfcase value="2">
<cfset statusName = "Preparing">
<cfset statusMessage = "Your order is now being prepared">
</cfcase>
<cfcase value="3">
<cfset statusName = "Ready">
<cfset statusMessage = "Your order is ready for pickup!">
</cfcase>
<cfcase value="4">
<cfset statusName = "Completed">
<cfset statusMessage = "Thank you! Your order is complete">
</cfcase>
<cfdefaultcase>
<cfset statusName = "Unknown">
<cfset statusMessage = "Order status updated">
</cfdefaultcase>
</cfswitch>
<cfset payload.ORDER_STATUS = {
"OrderID": qOrder.OrderID,
"StatusID": currentStatus,
"StatusName": statusName,
"Message": statusMessage,
"LastEditedOn": dateFormat(qOrder.OrderLastEditedOn, "yyyy-mm-dd") & " " & timeFormat(qOrder.OrderLastEditedOn, "HH:mm:ss")
}>
<cfset payload.MESSAGE = statusMessage>
<cfelse>
<cfset payload.MESSAGE = "No status update">
</cfif>
<cfcatch>
<cfset payload.ERROR = "Error checking status: " & cfcatch.message>
<cfset payload.OK = false>
</cfcatch>
</cftry>
<!--- Return JSON response --->
<cfcontent type="application/json" reset="true">
<cfoutput>#serializeJSON(payload)#</cfoutput>

View file

@ -219,6 +219,29 @@
<button class="btn btn-secondary" onclick="window.location.href='index.html'">View KDS Display</button> <button class="btn btn-secondary" onclick="window.location.href='index.html'">View KDS Display</button>
<button class="btn btn-secondary" onclick="window.location.href='debug.html'">Debug View</button> <button class="btn btn-secondary" onclick="window.location.href='debug.html'">Debug View</button>
</div> </div>
<!-- Test Status Updates Section -->
<div style="margin-top: 40px; padding-top: 30px; border-top: 2px solid #e1e8ed;">
<h2 style="margin-bottom: 20px;">Test Order Status Updates</h2>
<p class="subtitle">Manually update order status to test push notifications</p>
<div class="form-group">
<label>Order ID to Update</label>
<input type="number" id="testOrderId" placeholder="e.g., 318" min="1">
</div>
<div class="form-group">
<label>New Status</label>
<select id="testStatusId">
<option value="1">1 - Submitted</option>
<option value="2" selected>2 - Preparing</option>
<option value="3">3 - Ready</option>
<option value="4">4 - Completed</option>
</select>
</div>
<button class="btn btn-primary" onclick="updateOrderStatus()">Update Order Status</button>
</div>
</div> </div>
<script> <script>
@ -409,6 +432,46 @@
} }
} }
async function updateOrderStatus() {
const orderId = document.getElementById('testOrderId').value;
const statusId = document.getElementById('testStatusId').value;
if (!orderId) {
showAlert('Please enter an Order ID', 'error');
return;
}
try {
const response = await fetch(`${API_BASE}/orders/updateStatus.cfm`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
OrderID: parseInt(orderId),
StatusID: parseInt(statusId)
})
});
const data = await response.json();
if (!data.OK) {
throw new Error(data.ERROR || data.MESSAGE || 'Failed to update status');
}
const statusNames = {
1: 'Submitted',
2: 'Preparing',
3: 'Ready',
4: 'Completed'
};
showAlert(`Order #${orderId} updated to status: ${statusNames[statusId]}`, 'success');
} catch (error) {
showAlert('Error updating status: ' + error.message, 'error');
console.error(error);
}
}
function showAlert(message, type) { function showAlert(message, type) {
const alertDiv = document.getElementById('alert'); const alertDiv = document.getElementById('alert');
alertDiv.className = `alert alert-${type}`; alertDiv.className = `alert alert-${type}`;