This repository has been archived on 2026-03-21. You can view files and clone it, but cannot push or open issues or pull requests.
payfrit-biz/api/orders/markStationDone.cfm
John Mizerek d822fcad5a feat: per-station item completion on KDS
Each station can mark their items done independently. When all
stations are done, the order auto-promotes to Ready (status 3)
and delivery/pickup tasks are created automatically.

- New markStationDone.cfm endpoint for per-station completion
- Extract task creation into shared _createOrderTasks.cfm include
- Add line item StatusID to listForKDS.cfm response
- KDS shows per-station "Mark Station Done" button when filtered
- Done items display with strikethrough and checkmark
- Manager view retains full manual control (no station selected)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 19:19:25 -08:00

149 lines
4.8 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cffunction name="apiAbort" access="public" returntype="void" output="true">
<cfargument name="payload" type="struct" required="true">
<cfcontent type="application/json; charset=utf-8">
<cfoutput>#serializeJSON(arguments.payload)#</cfoutput>
<cfabort>
</cffunction>
<cffunction name="readJsonBody" access="public" returntype="struct" output="false">
<cfset var raw = getHttpRequestData().content>
<cfif isNull(raw) OR len(trim(raw)) EQ 0>
<cfreturn {}>
</cfif>
<cftry>
<cfset var data = deserializeJSON(raw)>
<cfif isStruct(data)>
<cfreturn data>
<cfelse>
<cfreturn {}>
</cfif>
<cfcatch>
<cfreturn {}>
</cfcatch>
</cftry>
</cffunction>
<cfset data = readJsonBody()>
<cfset OrderID = val( structKeyExists(data,"OrderID") ? data.OrderID : 0 )>
<cfset StationID = val( structKeyExists(data,"StationID") ? data.StationID : 0 )>
<cfif OrderID LTE 0 OR StationID LTE 0>
<cfset apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "OrderID and StationID are required.", "DETAIL": "" })>
</cfif>
<cftry>
<!--- Verify order exists and get details --->
<cfset qOrder = queryExecute("
SELECT o.ID, o.StatusID, o.BusinessID, o.ServicePointID,
sp.Name
FROM Orders o
LEFT JOIN ServicePoints sp ON sp.ID = o.ServicePointID
WHERE o.ID = ?
LIMIT 1
", [ { value = OrderID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })>
<cfif qOrder.recordCount EQ 0>
<cfset apiAbort({ "OK": false, "ERROR": "not_found", "MESSAGE": "Order not found.", "DETAIL": "" })>
</cfif>
<cfset oldStatusID = qOrder.StatusID>
<!--- Mark root line items for this station as done (StatusID = 1) --->
<cfset queryExecute("
UPDATE OrderLineItems oli
INNER JOIN Items i ON i.ID = oli.ItemID
SET oli.StatusID = 1
WHERE oli.OrderID = ?
AND i.StationID = ?
AND oli.ParentOrderLineItemID = 0
AND oli.IsDeleted = b'0'
", [
{ value = OrderID, cfsqltype = "cf_sql_integer" },
{ value = StationID, cfsqltype = "cf_sql_integer" }
], { datasource = "payfrit" })>
<!--- Also mark children (modifiers) of those root items as done --->
<cfset queryExecute("
UPDATE OrderLineItems oli
SET oli.StatusID = 1
WHERE oli.OrderID = ?
AND oli.IsDeleted = b'0'
AND oli.ParentOrderLineItemID IN (
SELECT sub.ID FROM (
SELECT oli2.ID
FROM OrderLineItems oli2
INNER JOIN Items i2 ON i2.ID = oli2.ItemID
WHERE oli2.OrderID = ?
AND i2.StationID = ?
AND oli2.ParentOrderLineItemID = 0
AND oli2.IsDeleted = b'0'
) sub
)
", [
{ value = OrderID, cfsqltype = "cf_sql_integer" },
{ value = OrderID, cfsqltype = "cf_sql_integer" },
{ value = StationID, cfsqltype = "cf_sql_integer" }
], { datasource = "payfrit" })>
<!--- If order was at status 1 (Submitted), auto-promote to status 2 (Preparing) --->
<cfif oldStatusID EQ 1>
<cfset queryExecute("
UPDATE Orders
SET StatusID = 2, LastEditedOn = NOW()
WHERE ID = ?
", [ { value = OrderID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })>
<cfset oldStatusID = 2>
</cfif>
<!--- Check if ALL station-assigned root items are now done --->
<cfset qRemaining = queryExecute("
SELECT COUNT(*) AS RemainingCount
FROM OrderLineItems oli
INNER JOIN Items i ON i.ID = oli.ItemID
WHERE oli.OrderID = ?
AND oli.ParentOrderLineItemID = 0
AND oli.IsDeleted = b'0'
AND i.StationID > 0
AND oli.StatusID = 0
", [ { value = OrderID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })>
<cfset allStationsDone = val(qRemaining.RemainingCount) EQ 0>
<cfset NewStatusID = oldStatusID>
<!--- If all stations done, auto-promote to status 3 (Ready) and create tasks --->
<cfif allStationsDone AND oldStatusID LT 3>
<cfset NewStatusID = 3>
<cfset queryExecute("
UPDATE Orders
SET StatusID = 3, LastEditedOn = NOW()
WHERE ID = ?
", [ { value = OrderID, cfsqltype = "cf_sql_integer" } ], { datasource = "payfrit" })>
<!--- Create delivery/pickup tasks via shared include --->
<cfinclude template="_createOrderTasks.cfm">
</cfif>
<cfset apiAbort({
"OK": true,
"ERROR": "",
"MESSAGE": "Station items marked as done.",
"OrderID": OrderID,
"StationID": StationID,
"StationDone": true,
"AllStationsDone": allStationsDone,
"NewOrderStatusID": NewStatusID,
"TaskCreated": allStationsDone AND isDefined("taskCreated") AND taskCreated
})>
<cfcatch>
<cfset apiAbort({
"OK": false,
"ERROR": "server_error",
"MESSAGE": "Error marking station done",
"DETAIL": cfcatch.message
})>
</cfcatch>
</cftry>