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:
parent
b812222314
commit
ecea71c533
2 changed files with 168 additions and 0 deletions
105
api/orders/checkStatusUpdate.cfm
Normal file
105
api/orders/checkStatusUpdate.cfm
Normal 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>
|
||||||
|
|
@ -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}`;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue