Files
karczma-aplikacja-stoliki/api/analytics_reports.php

221 lines
7.6 KiB
PHP

<?php
header('Content-Type: application/json; charset=utf-8');
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../public/staff/auth.php';
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
echo json_encode([
'status' => 'error',
'message' => 'Method not allowed'
], JSON_UNESCAPED_UNICODE);
exit;
}
if (!isAdminLoggedIn()) {
http_response_code(401);
echo json_encode([
'status' => 'error',
'message' => 'Unauthorized'
], JSON_UNESCAPED_UNICODE);
exit;
}
$range = isset($_GET['days']) ? trim((string)$_GET['days']) : '7';
$allowedRanges = ['7', '30', '90', 'all', 'this_year', 'last_year'];
if (!in_array($range, $allowedRanges, true)) {
$range = '7';
}
$whereWindow = '';
$baseParams = [];
$now = new DateTimeImmutable('now');
switch ($range) {
case 'all':
break;
case 'this_year':
$start = new DateTimeImmutable(date('Y-01-01 00:00:00'));
$end = $start->modify('+1 year');
$whereWindow = ' AND created_at >= :start_at AND created_at < :end_at';
$baseParams = [
':start_at' => $start->format('Y-m-d H:i:s'),
':end_at' => $end->format('Y-m-d H:i:s'),
];
break;
case 'last_year':
$start = new DateTimeImmutable((date('Y') - 1) . '-01-01 00:00:00');
$end = $start->modify('+1 year');
$whereWindow = ' AND created_at >= :start_at AND created_at < :end_at';
$baseParams = [
':start_at' => $start->format('Y-m-d H:i:s'),
':end_at' => $end->format('Y-m-d H:i:s'),
];
break;
default:
$daysInt = (int)$range;
if ($daysInt < 1) $daysInt = 1;
if ($daysInt > 3650) $daysInt = 3650;
$start = $now->modify("-{$daysInt} days");
$whereWindow = ' AND created_at >= :start_at';
$baseParams = [
':start_at' => $start->format('Y-m-d H:i:s'),
];
break;
}
try {
$pdo = getAnalyticsPdo();
$sqlTopTables = "
SELECT
COALESCE(NULLIF(table_id, ''), 'unknown') AS table_id,
SUM(CASE WHEN event_name = 'qr_scan' THEN 1 ELSE 0 END) AS qr_scans,
SUM(CASE WHEN event_name = 'session_start' THEN 1 ELSE 0 END) AS sessions,
SUM(CASE WHEN event_name = 'geo_check_passed' THEN 1 ELSE 0 END) AS geo_pass,
SUM(CASE WHEN event_name = 'geo_check_failed' THEN 1 ELSE 0 END) AS geo_fail
FROM analytics_events
WHERE 1=1 {$whereWindow}
GROUP BY COALESCE(NULLIF(table_id, ''), 'unknown')
ORDER BY qr_scans DESC, sessions DESC
LIMIT 20
";
$stmtTopTables = $pdo->prepare($sqlTopTables);
$stmtTopTables->execute($baseParams);
$topTables = $stmtTopTables->fetchAll();
$sqlByZone = "
SELECT
COALESCE(NULLIF(zone, ''), 'unknown') AS zone,
SUM(CASE WHEN event_name = 'qr_scan' THEN 1 ELSE 0 END) AS qr_scans,
SUM(CASE WHEN event_name = 'session_start' THEN 1 ELSE 0 END) AS sessions,
SUM(CASE WHEN event_name = 'geo_check_passed' THEN 1 ELSE 0 END) AS geo_pass,
SUM(CASE WHEN event_name = 'geo_check_failed' THEN 1 ELSE 0 END) AS geo_fail
FROM analytics_events
WHERE 1=1 {$whereWindow}
GROUP BY COALESCE(NULLIF(zone, ''), 'unknown')
ORDER BY sessions DESC, qr_scans DESC
";
$stmtByZone = $pdo->prepare($sqlByZone);
$stmtByZone->execute($baseParams);
$zoneStats = $stmtByZone->fetchAll();
$sqlFunnel = "
SELECT
event_name,
COUNT(*) AS total
FROM analytics_events
WHERE 1=1 {$whereWindow}
AND event_name IN ('qr_scan','session_start','view_menu','bill_dialog_opened','bill_request_sent','waiter_call_requested')
GROUP BY event_name
";
$stmtFunnel = $pdo->prepare($sqlFunnel);
$stmtFunnel->execute($baseParams);
$funnelRows = $stmtFunnel->fetchAll();
$funnelMap = [];
foreach ($funnelRows as $row) {
$funnelMap[$row['event_name']] = (int)$row['total'];
}
$sqlGeo = "
SELECT
SUM(CASE WHEN event_name = 'geo_check_passed' THEN 1 ELSE 0 END) AS geo_passed,
SUM(CASE WHEN event_name = 'geo_check_failed' THEN 1 ELSE 0 END) AS geo_failed,
SUM(CASE WHEN event_name = 'geo_bypass_host' THEN 1 ELSE 0 END) AS geo_bypass
FROM analytics_events
WHERE 1=1 {$whereWindow}
";
$stmtGeo = $pdo->prepare($sqlGeo);
$stmtGeo->execute($baseParams);
$geo = $stmtGeo->fetch() ?: ['geo_passed' => 0, 'geo_failed' => 0, 'geo_bypass' => 0];
$sqlRecentOpens = "
SELECT
created_at,
table_id,
zone,
device_type,
browser,
JSON_UNQUOTE(JSON_EXTRACT(payload_json, '$.ipAddress')) AS ip_address
FROM analytics_events
WHERE event_name = 'qr_scan' {$whereWindow}
ORDER BY created_at DESC
LIMIT 50
";
$stmtRecentOpens = $pdo->prepare($sqlRecentOpens);
$stmtRecentOpens->execute($baseParams);
$recentOpens = $stmtRecentOpens ? $stmtRecentOpens->fetchAll() : [];
$sqlQueueSummary = "
SELECT
COUNT(*) AS total_actions,
SUM(CASE WHEN api_sent = 0 THEN 1 ELSE 0 END) AS pending_api,
SUM(CASE WHEN status_kds = 0 THEN 1 ELSE 0 END) AS pending_kds,
SUM(CASE WHEN status_kds = 1 THEN 1 ELSE 0 END) AS done_kds
FROM guest_action_queue
WHERE 1=1 {$whereWindow}
";
$stmtQueueSummary = $pdo->prepare($sqlQueueSummary);
$stmtQueueSummary->execute($baseParams);
$queueSummary = $stmtQueueSummary->fetch() ?: [
'total_actions' => 0,
'pending_api' => 0,
'pending_kds' => 0,
'done_kds' => 0,
];
$sqlQueueItems = "
SELECT
id,
table_id,
message_type,
message_text,
api_sent,
status_kds,
created_at
FROM guest_action_queue
WHERE 1=1 {$whereWindow}
ORDER BY created_at DESC
LIMIT 100
";
$stmtQueueItems = $pdo->prepare($sqlQueueItems);
$stmtQueueItems->execute($baseParams);
$queueItems = $stmtQueueItems->fetchAll();
echo json_encode([
'status' => 'success',
'days' => $range,
'topTables' => $topTables,
'zoneStats' => $zoneStats,
'funnel' => [
'qr_scan' => (int)($funnelMap['qr_scan'] ?? 0),
'session_start' => (int)($funnelMap['session_start'] ?? 0),
'view_menu' => (int)($funnelMap['view_menu'] ?? 0),
'bill_dialog_opened' => (int)($funnelMap['bill_dialog_opened'] ?? 0),
'bill_request_sent' => (int)($funnelMap['bill_request_sent'] ?? 0),
'waiter_call_requested' => (int)($funnelMap['waiter_call_requested'] ?? 0),
],
'geolocation' => [
'passed' => (int)$geo['geo_passed'],
'failed' => (int)$geo['geo_failed'],
'bypass' => (int)$geo['geo_bypass'],
],
'recentOpens' => $recentOpens,
'guestQueueSummary' => [
'total' => (int)$queueSummary['total_actions'],
'pendingApi' => (int)$queueSummary['pending_api'],
'pendingKds' => (int)$queueSummary['pending_kds'],
'doneKds' => (int)$queueSummary['done_kds'],
],
'guestQueue' => $queueItems,
], JSON_UNESCAPED_UNICODE);
} catch (Throwable $e) {
http_response_code(500);
echo json_encode([
'status' => 'error',
'message' => 'Nie udało się pobrać raportów analitycznych.'
], JSON_UNESCAPED_UNICODE);
}