Fix daily_summary dan hourly_summary aggregation, tambah fallback logic untuk dashboard, update validator untuk camera dan location type

This commit is contained in:
mwpn
2025-12-18 11:13:06 +07:00
parent 9416de7d87
commit d05fa2f4cd
31 changed files with 2041 additions and 45 deletions

View File

@@ -0,0 +1,91 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
use App\Config\AppConfig;
use App\Support\Database;
AppConfig::loadEnv(__DIR__ . '/..');
$db = Database::getConnection(
AppConfig::get('DB_HOST'),
AppConfig::get('DB_NAME'),
AppConfig::get('DB_USER'),
AppConfig::get('DB_PASS')
);
echo "=== Comparing entry_events vs daily_summary ===\n\n";
// Check dates that have entry_events
$stmt = $db->query('SELECT DATE(event_time) as date, COUNT(*) as count FROM entry_events GROUP BY DATE(event_time) ORDER BY date DESC LIMIT 10');
$dates = $stmt->fetchAll();
foreach ($dates as $dateRow) {
$date = $dateRow['date'];
$entryCount = $dateRow['count'];
echo "--- Date: $date ---\n";
// Count from entry_events
$stmt = $db->prepare('SELECT COUNT(*) as count FROM entry_events WHERE DATE(event_time) = ?');
$stmt->execute([$date]);
$entryEvents = $stmt->fetch()['count'];
// Count from daily_summary
$stmt = $db->prepare('SELECT COUNT(*) as records, SUM(total_count) as total_count, SUM(total_amount) as total_amount FROM daily_summary WHERE summary_date = ?');
$stmt->execute([$date]);
$summary = $stmt->fetch();
$summaryRecords = $summary['records'] ?? 0;
$summaryTotal = $summary['total_count'] ?? 0;
$summaryAmount = $summary['total_amount'] ?? 0;
echo " entry_events: $entryEvents events\n";
echo " daily_summary: $summaryRecords records, total_count: $summaryTotal, total_amount: $summaryAmount\n";
// Check if counts match
if ($entryEvents > 0 && $summaryTotal == 0) {
echo " ❌ PROBLEM: entry_events has data but daily_summary is empty!\n";
echo " Run: php bin/daily_summary.php $date\n";
} elseif ($entryEvents > 0 && $summaryTotal > 0 && $entryEvents != $summaryTotal) {
$diff = $entryEvents - $summaryTotal;
echo " ⚠️ WARNING: Count mismatch! entry_events: $entryEvents, daily_summary: $summaryTotal (diff: $diff)\n";
// Check why there's a difference
echo " Checking why...\n";
// Count active locations/gates/tariffs
$stmt = $db->query('SELECT COUNT(*) as count 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
WHERE DATE(e.event_time) = "' . $date . '"');
$activeCount = $stmt->fetch()['count'];
echo " Events with active locations & gates: $activeCount\n";
// Count all events
echo " All events (including inactive): $entryEvents\n";
if ($activeCount == $summaryTotal) {
echo " ✓ Reason: daily_summary only counts events with active locations/gates\n";
} else {
echo " ⚠️ Still a mismatch even with active filter\n";
}
} else {
echo " ✓ OK: Counts match\n";
}
echo "\n";
}
// Check if there are dates in daily_summary that don't have entry_events
echo "=== Dates in daily_summary without entry_events ===\n";
$stmt = $db->query('SELECT summary_date, SUM(total_count) as total FROM daily_summary
WHERE summary_date NOT IN (SELECT DISTINCT DATE(event_time) FROM entry_events)
GROUP BY summary_date ORDER BY summary_date DESC LIMIT 10');
$orphanDates = $stmt->fetchAll();
if (empty($orphanDates)) {
echo "None found - OK\n";
} else {
foreach ($orphanDates as $row) {
echo $row['summary_date'] . ' - ' . $row['total'] . ' total (orphaned data)' . "\n";
}
}