Fix inverted modifier groups in KDS

The inverted group header item isn't always an order line item itself,
so RemovedDefaults was never computed. Now detects inverted groups
via children's ParentIsInvertedGroup flag and attaches RemovedDefaults
to the first child as a proxy. KDS JS handles both patterns.

Also skips showing default modifiers from inverted groups since those
are represented by "NO removed-item" instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
John Mizerek 2026-03-11 17:06:18 -07:00
parent c6767eb2c4
commit a8257b2509
2 changed files with 20 additions and 11 deletions

View file

@ -126,7 +126,8 @@
i.IsCheckedByDefault, i.IsCheckedByDefault,
i.IsInvertedGroup, i.IsInvertedGroup,
i.StationID, i.StationID,
parent.Name AS ItemParentName parent.Name AS ItemParentName,
COALESCE(parent.IsInvertedGroup, 0) AS ParentIsInvertedGroup
FROM OrderLineItems oli FROM OrderLineItems oli
INNER JOIN Items i ON i.ID = oli.ItemID INNER JOIN Items i ON i.ID = oli.ItemID
LEFT JOIN Items parent ON parent.ID = i.ParentItemID LEFT JOIN Items parent ON parent.ID = i.ParentItemID
@ -149,15 +150,20 @@
"ItemParentName": qLineItems.ItemParentName, "ItemParentName": qLineItems.ItemParentName,
"IsCheckedByDefault": qLineItems.IsCheckedByDefault, "IsCheckedByDefault": qLineItems.IsCheckedByDefault,
"IsInvertedGroup": qLineItems.IsInvertedGroup, "IsInvertedGroup": qLineItems.IsInvertedGroup,
"ParentIsInvertedGroup": qLineItems.ParentIsInvertedGroup,
"StationID": qLineItems.StationID, "StationID": qLineItems.StationID,
"StatusID": val(qLineItems.StatusID) "StatusID": val(qLineItems.StatusID)
})> })>
</cfloop> </cfloop>
<!--- For inverted modifier groups, compute removed defaults ---> <!--- For inverted modifier groups, compute removed defaults --->
<!--- The inverted group header may not be an order line item itself,
so we detect inverted groups by finding children whose parent item is inverted --->
<cfset invertedGroupsSeen = {}>
<cfloop array="#lineItems#" index="li"> <cfloop array="#lineItems#" index="li">
<cfif li.IsInvertedGroup> <cfif li.ParentIsInvertedGroup AND NOT structKeyExists(invertedGroupsSeen, li.ParentItemID)>
<!--- This is an inverted modifier group in the order — find defaults NOT ordered ---> <!--- First child of this inverted group — compute removed defaults once --->
<cfset invertedGroupsSeen[li.ParentItemID] = true>
<cfset qRemovedDefaults = queryTimed(" <cfset qRemovedDefaults = queryTimed("
SELECT i.Name SELECT i.Name
FROM Items i FROM Items i
@ -170,15 +176,17 @@
) )
ORDER BY i.SortOrder ORDER BY i.SortOrder
", [ ", [
{ value = li.ItemID, cfsqltype = "cf_sql_integer" }, { value = li.ParentItemID, cfsqltype = "cf_sql_integer" },
{ value = qOrders.ID, cfsqltype = "cf_sql_integer" }, { value = qOrders.ID, cfsqltype = "cf_sql_integer" },
{ value = li.OrderLineItemID, cfsqltype = "cf_sql_integer" } { value = li.ParentOrderLineItemID, cfsqltype = "cf_sql_integer" }
], { datasource = "payfrit" })> ], { datasource = "payfrit" })>
<cfset removedNames = []> <cfset removedNames = []>
<cfloop query="qRemovedDefaults"> <cfloop query="qRemovedDefaults">
<cfset arrayAppend(removedNames, qRemovedDefaults.Name)> <cfset arrayAppend(removedNames, qRemovedDefaults.Name)>
</cfloop> </cfloop>
<!--- Attach RemovedDefaults to the first child so the JS can find it --->
<cfset li["RemovedDefaults"] = removedNames> <cfset li["RemovedDefaults"] = removedNames>
<cfset li["IsInvertedGroupProxy"] = true>
</cfif> </cfif>
</cfloop> </cfloop>

View file

@ -408,20 +408,21 @@ function renderAllModifiers(modifiers, allItems) {
function collectLeafModifiers(mods, depth = 0) { function collectLeafModifiers(mods, depth = 0) {
mods.forEach(mod => { mods.forEach(mod => {
// Inverted groups: show removed defaults with "NO" prefix instead of listing all selected defaults // Inverted groups: show removed defaults with "NO" prefix instead of listing all selected defaults
if (mod.IsInvertedGroup || mod.ISINVERTEDGROUP) { // Check both the item itself (if group header is in order) and proxy (first child carries the data)
const isInverted = mod.IsInvertedGroup || mod.ISINVERTEDGROUP || mod.IsInvertedGroupProxy || mod.ISINVERTEDGROUPPROXY;
if (isInverted) {
const removed = mod.RemovedDefaults || mod.REMOVEDDEFAULTS || []; const removed = mod.RemovedDefaults || mod.REMOVEDDEFAULTS || [];
if (removed.length > 0) { if (removed.length > 0) {
const groupName = mod.ItemParentName || mod.Name;
removed.forEach(name => { removed.forEach(name => {
leafModifiers.push({ mod: { Name: 'NO ' + name, ItemParentName: mod.Name }, path: [] }); leafModifiers.push({ mod: { Name: 'NO ' + name, ItemParentName: groupName }, path: [] });
}); });
} }
return; return;
} }
// Skip default modifiers only inside non-inverted groups // Skip default modifiers inside inverted groups — handled above with "NO" prefix
// (Inverted groups are already handled above with "NO" prefix) if (mod.IsCheckedByDefault && (mod.ParentIsInvertedGroup || mod.PARENTISINVERTEDGROUP)) return;
// For regular groups, show all selected modifiers including defaults
const children = allItems.filter(item => item.ParentOrderLineItemID === mod.OrderLineItemID); const children = allItems.filter(item => item.ParentOrderLineItemID === mod.OrderLineItemID);
if (children.length === 0) { if (children.length === 0) {