prepare($sql); $stmt->execute(); // Group by order_id $byOrder = []; while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { $oid = $row['order_id']; if (!isset($byOrder[$oid])) { $byOrder[$oid] = [ 'order_id' => $oid, 'member_id' => $row['member_id'], 'pts' => 0, 'items' => [], // each: { symbol, amount, shares } 'status' => $row['status'], 'event_time'=> $row['placed_at'], // will be updated to latest ]; } // Add line item $byOrder[$oid]['items'][] = [ 'symbol' => $row['symbol'], 'amount' => isset($row['amount']) ? (float)$row['amount'] : 0.0, 'shares' => isset($row['shares']) ? (float)$row['shares'] : 0.0, ]; // Sum order-level points_used across rows for total pts $byOrder[$oid]['pts'] += (float)$row['points_used']; // Optional: choose a status—keep first, or implement a precedence rule if you prefer if (!$byOrder[$oid]['status'] && $row['status']) { $byOrder[$oid]['status'] = $row['status']; } // Latest event time: ledger redeem_points time if present, else placed_at $candidate = $row['ledger_time'] ?? $row['placed_at']; if ($candidate && strcmp($candidate, $byOrder[$oid]['event_time']) > 0) { $byOrder[$oid]['event_time'] = $candidate; } } // Sort the grouped result by event_time DESC (most recent first) usort($byOrder, function ($a, $b) { return strcmp($b['event_time'], $a['event_time']); }); // Prepare final payload (limit to 50 most recent) $items = []; $count = 0; foreach ($byOrder as $order) { $items[] = [ 'order_id' => $order['order_id'], 'member_id' => $order['member_id'], 'pts' => $order['pts'], 'status' => $order['status'], 'placed_at' => $order['event_time'], 'lines' => $order['items'], // array of {symbol, amount, shares} ]; if (++$count >= 50) break; } echo json_encode(['success' => true, 'items' => $items], JSON_UNESCAPED_SLASHES); } catch (Throwable $e) { http_response_code(500); echo json_encode(['success' => false, 'error' => 'Server error'], JSON_UNESCAPED_SLASHES); }