#!/usr/bin/env php format('Y-m-d') !== $date) { echo "Error: Invalid date format. Expected Y-m-d (e.g., 2025-01-01) or 'today'/'yesterday'\n"; exit(1); } try { // Get database connection $dbHost = AppConfig::get('DB_HOST', 'localhost'); $dbName = AppConfig::get('DB_NAME', ''); $dbUser = AppConfig::get('DB_USER', ''); $dbPass = AppConfig::get('DB_PASS', ''); if (empty($dbName) || empty($dbUser)) { echo "Error: Database configuration not found in .env\n"; exit(1); } $db = Database::getConnection($dbHost, $dbName, $dbUser, $dbPass); echo "=== Debug Hourly Amount Calculation ===\n\n"; echo "Date: {$date}\n"; if ($hourInput !== null) { echo "Hour: {$hourInput}\n"; } else { echo "Hour: All hours\n"; } echo "\n"; // 1. Cek entry_events untuk tanggal/jam tersebut $eventsSql = " SELECT DATE(e.event_time) as event_date, HOUR(e.event_time) as event_hour, e.location_code, e.gate_code, e.category, COUNT(*) as event_count FROM entry_events e WHERE DATE(e.event_time) = ? "; $eventsParams = [$date]; if ($hourInput !== null) { $eventsSql .= " AND HOUR(e.event_time) = ?"; $eventsParams[] = $hourInput; } $eventsSql .= " GROUP BY DATE(e.event_time), HOUR(e.event_time), e.location_code, e.gate_code, e.category"; $stmt = $db->prepare($eventsSql); $stmt->execute($eventsParams); $events = $stmt->fetchAll(PDO::FETCH_ASSOC); if (empty($events)) { echo "❌ Tidak ada event untuk tanggal/jam tersebut\n"; exit(0); } echo "1. Entry Events Found:\n"; echo str_repeat("-", 80) . "\n"; foreach ($events as $event) { echo sprintf( " Date: %s, Hour: %02d, Location: %s, Gate: %s, Category: %s, Count: %d\n", $event['event_date'], $event['event_hour'], $event['location_code'], $event['gate_code'], $event['category'], $event['event_count'] ); } echo "\n"; // 2. Cek apakah tariff ada untuk setiap kombinasi echo "2. Tariff Check:\n"; echo str_repeat("-", 80) . "\n"; $missingTariffs = []; $foundTariffs = []; foreach ($events as $event) { $tariffSql = " SELECT location_code, gate_code, category, price FROM tariffs WHERE location_code = ? AND gate_code = ? AND category = ? "; $tariffStmt = $db->prepare($tariffSql); $tariffStmt->execute([ $event['location_code'], $event['gate_code'], $event['category'] ]); $tariff = $tariffStmt->fetch(PDO::FETCH_ASSOC); $key = sprintf("%s|%s|%s", $event['location_code'], $event['gate_code'], $event['category']); if ($tariff === false || empty($tariff)) { $missingTariffs[] = [ 'location_code' => $event['location_code'], 'gate_code' => $event['gate_code'], 'category' => $event['category'], 'event_count' => $event['event_count'] ]; echo sprintf( " ❌ TARIF TIDAK DITEMUKAN: Location: %s, Gate: %s, Category: %s\n", $event['location_code'], $event['gate_code'], $event['category'] ); } else { $foundTariffs[$key] = $tariff; $expectedAmount = $event['event_count'] * (int) $tariff['price']; echo sprintf( " ✅ Tarif ditemukan: Location: %s, Gate: %s, Category: %s, Price: %s, Expected Amount: %s\n", $tariff['location_code'], $tariff['gate_code'], $tariff['category'], number_format($tariff['price'], 0, ',', '.'), number_format($expectedAmount, 0, ',', '.') ); } } echo "\n"; // 3. Cek data di hourly_summary echo "3. Hourly Summary Data:\n"; echo str_repeat("-", 80) . "\n"; $summarySql = " SELECT summary_date, summary_hour, location_code, gate_code, category, total_count, total_amount FROM hourly_summary WHERE summary_date = ? "; $summaryParams = [$date]; if ($hourInput !== null) { $summarySql .= " AND summary_hour = ?"; $summaryParams[] = $hourInput; } $summaryStmt = $db->prepare($summarySql); $summaryStmt->execute($summaryParams); $summaries = $summaryStmt->fetchAll(PDO::FETCH_ASSOC); if (empty($summaries)) { echo " ⚠️ Belum ada data di hourly_summary untuk tanggal/jam tersebut\n"; } else { foreach ($summaries as $summary) { $key = sprintf("%s|%s|%s", $summary['location_code'], $summary['gate_code'], $summary['category']); $tariff = $foundTariffs[$key] ?? null; $expectedAmount = $tariff ? $summary['total_count'] * (int) $tariff['price'] : 0; $status = ($summary['total_amount'] == $expectedAmount) ? '✅' : '❌'; echo sprintf( " %s Date: %s, Hour: %02d, Location: %s, Gate: %s, Category: %s\n", $status, $summary['summary_date'], $summary['summary_hour'], $summary['location_code'], $summary['gate_code'], $summary['category'] ); echo sprintf( " Count: %d, Amount: %s (Expected: %s)\n", $summary['total_count'], number_format($summary['total_amount'], 0, ',', '.'), number_format($expectedAmount, 0, ',', '.') ); } } echo "\n"; // 4. Summary dan rekomendasi echo "4. Summary:\n"; echo str_repeat("-", 80) . "\n"; if (!empty($missingTariffs)) { echo "❌ MASALAH DITEMUKAN:\n"; echo " Ada " . count($missingTariffs) . " kombinasi yang TIDAK punya tarif:\n"; foreach ($missingTariffs as $missing) { echo sprintf( " - Location: %s, Gate: %s, Category: %s (Event count: %d)\n", $missing['location_code'], $missing['gate_code'], $missing['category'], $missing['event_count'] ); } echo "\n"; echo "💡 SOLUSI:\n"; echo " 1. Tambahkan tarif untuk kombinasi yang missing di tabel tariffs\n"; echo " 2. Atau pastikan location_code, gate_code, category match dengan entry_events\n"; echo " 3. Setelah tambah tarif, jalankan lagi:\n"; echo " php bin/hourly_summary.php {$date} " . ($hourInput ?? '') . "\n"; } else { echo "✅ Semua kombinasi punya tarif\n"; echo "✅ Jika total_amount masih 0, kemungkinan:\n"; echo " 1. Tarif price = 0 (cek di tabel tariffs)\n"; echo " 2. Data belum di-rekap (jalankan hourly_summary.php)\n"; } echo "\n"; // 5. Test query aggregation echo "5. Test Aggregation Query:\n"; echo str_repeat("-", 80) . "\n"; $testSql = " SELECT DATE(e.event_time) as summary_date, HOUR(e.event_time) as summary_hour, e.location_code, e.gate_code, e.category, COUNT(*) as total_count, COALESCE(t.price, 0) as tariff_amount, COUNT(*) * COALESCE(t.price, 0) as calculated_total_amount FROM entry_events e INNER JOIN locations l ON e.location_code = l.code AND l.is_active = 1 INNER JOIN gates g ON e.location_code = g.location_code AND e.gate_code = g.gate_code AND g.is_active = 1 LEFT JOIN tariffs t ON e.location_code = t.location_code AND e.gate_code = t.gate_code AND e.category = t.category WHERE DATE(e.event_time) = ? "; $testParams = [$date]; if ($hourInput !== null) { $testSql .= " AND HOUR(e.event_time) = ?"; $testParams[] = $hourInput; } $testSql .= " GROUP BY DATE(e.event_time), HOUR(e.event_time), e.location_code, e.gate_code, e.category, COALESCE(t.price, 0) "; $testStmt = $db->prepare($testSql); $testStmt->execute($testParams); $testResults = $testStmt->fetchAll(PDO::FETCH_ASSOC); foreach ($testResults as $result) { $tariffStatus = ($result['tariff_amount'] > 0) ? '✅' : '❌'; echo sprintf( " %s Location: %s, Gate: %s, Category: %s\n", $tariffStatus, $result['location_code'], $result['gate_code'], $result['category'] ); echo sprintf( " Count: %d, Tariff: %s, Calculated Amount: %s\n", $result['total_count'], number_format($result['tariff_amount'], 0, ',', '.'), number_format($result['calculated_total_amount'], 0, ',', '.') ); } echo "\n=== Debug Complete ===\n"; } catch (Exception $e) { echo "Error: " . $e->getMessage() . "\n"; echo $e->getTraceAsString() . "\n"; exit(1); }