100000) { $WasDecoded = true; $ItemID = $ItemID % 100000; } $IsSelected = false; if (isset($data['IsSelected'])) { $v = $data['IsSelected']; $IsSelected = ($v === true || $v === 1 || (is_string($v) && strtolower($v) === 'true')); } $Quantity = (int) ($data['Quantity'] ?? 0); $Remark = (string) ($data['Remark'] ?? ''); $ForceNew = false; if (isset($data['ForceNew'])) { $v = $data['ForceNew']; $ForceNew = ($v === true || $v === 1 || (is_string($v) && strtolower($v) === 'true')); } if ($OrderID <= 0 || $ItemID <= 0) { apiAbort(['OK' => false, 'ERROR' => 'missing_params', 'MESSAGE' => 'OrderID and ItemID are required.']); } try { // Load item $qItem = queryOne("SELECT ID, Price, ParentItemID, IsActive FROM Items WHERE ID = ? LIMIT 1", [$ItemID]); if (!$qItem || (int) $qItem['IsActive'] !== 1) { apiAbort(['OK' => false, 'ERROR' => 'bad_item', 'MESSAGE' => "Item not found or inactive. Original={$OriginalItemID} Decoded={$ItemID} WasDecoded=" . ($WasDecoded ? 'true' : 'false')]); } // Root vs modifier rules if ($ParentLineItemID === 0) { if ($IsSelected && $Quantity <= 0) { apiAbort(['OK' => false, 'ERROR' => 'bad_quantity', 'MESSAGE' => 'Root line items require Quantity > 0.']); } } else { $Quantity = $IsSelected ? 1 : 0; // Exclusive selection group handling if ($IsSelected) { $qParentLI = queryOne("SELECT ItemID FROM OrderLineItems WHERE ID = ? LIMIT 1", [$ParentLineItemID]); if ($qParentLI) { $qParentItem = queryOne("SELECT MaxNumSelectionReq FROM Items WHERE ID = ? LIMIT 1", [(int) $qParentLI['ItemID']]); if ($qParentItem && (int) $qParentItem['MaxNumSelectionReq'] === 1) { queryTimed( "UPDATE OrderLineItems SET IsDeleted = 1 WHERE OrderID = ? AND ParentOrderLineItemID = ? AND ItemID != ? AND IsDeleted = 0", [$OrderID, $ParentLineItemID, $ItemID] ); } } } } // Find existing line item if ($ForceNew) { $qExisting = null; } elseif ($OrderLineItemID > 0) { $qExisting = queryOne( "SELECT ID FROM OrderLineItems WHERE ID = ? AND OrderID = ? AND IsDeleted = 0 LIMIT 1", [$OrderLineItemID, $OrderID] ); } else { $qExisting = queryOne( "SELECT ID FROM OrderLineItems WHERE OrderID = ? AND ParentOrderLineItemID = ? AND ItemID = ? AND IsDeleted = 0 LIMIT 1", [$OrderID, $ParentLineItemID, $ItemID] ); } if ($qExisting) { // Update existing if ($IsSelected) { queryTimed( "UPDATE OrderLineItems SET IsDeleted = 0, Quantity = ?, Price = ?, Remark = ?, StatusID = 0 WHERE ID = ?", [$Quantity, (float) $qItem['Price'], trim($Remark) !== '' ? $Remark : null, (int) $qExisting['ID']] ); attachDefaultChildren($OrderID, (int) $qExisting['ID'], $ItemID); } else { // Deselecting if ($ParentLineItemID > 0) { $qItemCheck = queryOne("SELECT IsCheckedByDefault FROM Items WHERE ID = ? LIMIT 1", [$ItemID]); if ($qItemCheck && (int) $qItemCheck['IsCheckedByDefault'] === 1) { // Default modifier: keep with Quantity=0 queryTimed("UPDATE OrderLineItems SET Quantity = 0 WHERE ID = ?", [(int) $qExisting['ID']]); } else { queryTimed("UPDATE OrderLineItems SET IsDeleted = 1 WHERE ID = ?", [(int) $qExisting['ID']]); } } else { // Root item: always delete queryTimed("UPDATE OrderLineItems SET IsDeleted = 1 WHERE ID = ?", [(int) $qExisting['ID']]); } } } else { // Insert new if selecting if ($IsSelected) { $NewLIID = nextId('OrderLineItems', 'ID'); queryTimed( "INSERT INTO OrderLineItems (ID, ParentOrderLineItemID, OrderID, ItemID, StatusID, Price, Quantity, Remark, IsDeleted, AddedOn) VALUES (?, ?, ?, ?, 0, ?, ?, ?, 0, NOW())", [ $NewLIID, $ParentLineItemID, $OrderID, $ItemID, (float) $qItem['Price'], ($ParentLineItemID === 0 ? $Quantity : 1), trim($Remark) !== '' ? $Remark : null, ] ); attachDefaultChildren($OrderID, $NewLIID, $ItemID); } } // Touch order last edited queryTimed("UPDATE Orders SET LastEditedOn = NOW() WHERE ID = ?", [$OrderID]); $payload = loadCartPayload($OrderID); jsonResponse($payload); } catch (Exception $e) { jsonResponse([ 'OK' => false, 'ERROR' => 'server_error', 'MESSAGE' => 'DB error setting line item: ' . $e->getMessage(), ]); }