API
This commit is contained in:
@@ -7,9 +7,15 @@ require_once __DIR__ . '/resolve_table_operator.php';
|
||||
|
||||
$kdsSecret = 'karczma_kuchnia';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
function verifyKdsSecret(): bool
|
||||
{
|
||||
global $kdsSecret;
|
||||
$secret = isset($_GET['kds_secret']) ? trim((string) $_GET['kds_secret']) : '';
|
||||
if ($secret !== $kdsSecret) {
|
||||
return $secret === $kdsSecret;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
if (!verifyKdsSecret()) {
|
||||
http_response_code(403);
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
@@ -28,20 +34,25 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
message_text,
|
||||
otwierajacy_imie,
|
||||
otwierajacy_nazwisko,
|
||||
api_sent,
|
||||
status_kds,
|
||||
created_at
|
||||
created_at,
|
||||
updated_at
|
||||
FROM guest_action_queue
|
||||
WHERE status_kds = 0
|
||||
AND created_at >= DATE_SUB(NOW(), INTERVAL 12 HOUR)
|
||||
ORDER BY created_at ASC
|
||||
LIMIT 50
|
||||
LIMIT 100
|
||||
");
|
||||
$rows = $stmt->fetchAll();
|
||||
|
||||
foreach ($rows as &$row) {
|
||||
$row['id'] = (int) $row['id'];
|
||||
}
|
||||
unset($row);
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'count' => count($rows),
|
||||
'polled_at' => date('Y-m-d H:i:s'),
|
||||
'poll_interval_seconds' => 30,
|
||||
'data' => $rows,
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
} catch (Throwable $e) {
|
||||
@@ -54,6 +65,70 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'PATCH') {
|
||||
if (!verifyKdsSecret()) {
|
||||
http_response_code(403);
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Forbidden',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
$rawBody = file_get_contents('php://input');
|
||||
$data = json_decode($rawBody, true);
|
||||
if (!is_array($data)) {
|
||||
http_response_code(400);
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Invalid JSON payload',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
$id = isset($data['id']) ? (int) $data['id'] : 0;
|
||||
if ($id < 1) {
|
||||
http_response_code(422);
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'id is required',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = getAnalyticsPdo();
|
||||
$stmt = $pdo->prepare("
|
||||
UPDATE guest_action_queue
|
||||
SET status_kds = 1
|
||||
WHERE id = :id
|
||||
AND status_kds = 0
|
||||
");
|
||||
$stmt->execute([':id' => $id]);
|
||||
|
||||
if ($stmt->rowCount() === 0) {
|
||||
http_response_code(404);
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Queue item not found or already dismissed',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'success',
|
||||
'id' => $id,
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
} catch (Throwable $e) {
|
||||
http_response_code(500);
|
||||
echo json_encode([
|
||||
'status' => 'error',
|
||||
'message' => 'Queue dismiss failed',
|
||||
], JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
http_response_code(405);
|
||||
echo json_encode([
|
||||
|
||||
@@ -100,7 +100,7 @@ requireAdminAuth(true);
|
||||
<div class="card col-12">
|
||||
<h3>Ostatnie otwarcia stron stolików</h3>
|
||||
<table>
|
||||
<thead><tr><th>Kiedy</th><th>Stolik</th><th>Strefa</th><th>Menu</th><th>Urządzenie</th><th>Przeglądarka</th><th>IP</th></tr></thead>
|
||||
<thead><tr><th>Kiedy</th><th>Stolik</th><th>Strefa</th><th>W aplikacji</th><th>Urządzenie</th><th>Przeglądarka</th><th>IP</th></tr></thead>
|
||||
<tbody id="recentOpensBody"><tr><td colspan="7" class="muted">Ładowanie...</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -129,7 +129,7 @@ requireAdminAuth(true);
|
||||
<li><strong>Przywołania kelnera</strong> - ile razy gość poprosił o podejście obsługi.</li>
|
||||
<li><strong>Top stoliki</strong> - które stoliki są najczęściej otwierane i używane.</li>
|
||||
<li><strong>Lejek użycia</strong> - droga użytkownika: wejście -> start aplikacji -> menu -> rachunek.</li>
|
||||
<li><strong>Kolumna Menu (✓/✗)</strong> - ✓ oznacza wejście do menu w tej sesji; ✗ oznacza brak wejścia do menu (w tym zatrzymanie na geo).</li>
|
||||
<li><strong>Kolumna W aplikacji (✓/✗)</strong> - ✓ oznacza przejście przez ekran lokalizacji (widok statusu zamówień); ✗ oznacza zatrzymanie na geo.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -200,15 +200,11 @@ requireAdminAuth(true);
|
||||
const when = dt && !Number.isNaN(dt.getTime()) ? dt.toLocaleString("pl-PL") : (r.created_at || "-");
|
||||
const device = r.device_type || "-";
|
||||
const browser = r.browser || "-";
|
||||
const enteredMenu = Number(r.entered_menu) === 1;
|
||||
const reachedApp = Number(r.reached_app) === 1;
|
||||
let menuCell = `<span class="status-fail" title="Zatrzymano na ekranie lokalizacji">✗</span>`;
|
||||
if (enteredMenu) {
|
||||
menuCell = `<span class="status-ok" title="Wszedł do menu">✓</span>`;
|
||||
} else if (reachedApp) {
|
||||
menuCell = `<span class="status-fail" title="Wszedł do aplikacji, ale nie otworzył menu">✗</span>`;
|
||||
}
|
||||
return `<tr><td>${when}</td><td>${r.table_id || "-"}</td><td>${r.zone || "-"}</td><td>${menuCell}</td><td>${device}</td><td>${browser}</td><td>${r.ip_address || "-"}</td></tr>`;
|
||||
const appCell = reachedApp
|
||||
? `<span class="status-ok" title="Przeszedł lokalizację — widok statusu zamówień">✓</span>`
|
||||
: `<span class="status-fail" title="Zatrzymano na ekranie lokalizacji">✗</span>`;
|
||||
return `<tr><td>${when}</td><td>${r.table_id || "-"}</td><td>${r.zone || "-"}</td><td>${appCell}</td><td>${device}</td><td>${browser}</td><td>${r.ip_address || "-"}</td></tr>`;
|
||||
}).join("")
|
||||
: `<tr><td colspan="7" class="muted">Brak danych</td></tr>`;
|
||||
|
||||
|
||||
59
scripts/seed_guest_action_queue_demo.php
Normal file
59
scripts/seed_guest_action_queue_demo.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../config/database.php';
|
||||
|
||||
$pdo = getAnalyticsPdo();
|
||||
|
||||
try {
|
||||
$pdo->exec('DROP TABLE IF EXISTS kds_orders');
|
||||
echo "Usunięto tabelę kds_orders (jeśli istniała).\n";
|
||||
} catch (Throwable $e) {
|
||||
echo "Uwaga: nie udało się usunąć kds_orders: {$e->getMessage()}\n";
|
||||
}
|
||||
|
||||
$pdo->exec("DELETE FROM guest_action_queue WHERE message_text LIKE '[DEMO]%'");
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO guest_action_queue (
|
||||
table_id,
|
||||
message_type,
|
||||
message_text,
|
||||
otwierajacy_imie,
|
||||
otwierajacy_nazwisko,
|
||||
api_sent,
|
||||
status_kds,
|
||||
created_at
|
||||
) VALUES (
|
||||
:table_id,
|
||||
:message_type,
|
||||
:message_text,
|
||||
:otwierajacy_imie,
|
||||
:otwierajacy_nazwisko,
|
||||
0,
|
||||
0,
|
||||
NOW(3)
|
||||
)
|
||||
");
|
||||
|
||||
$samples = [
|
||||
[
|
||||
'table_id' => '12',
|
||||
'message_type' => 'waiter_call',
|
||||
'message_text' => '[DEMO] Przywołanie kelnera',
|
||||
'otwierajacy_imie' => 'Jan',
|
||||
'otwierajacy_nazwisko' => 'Kowalski',
|
||||
],
|
||||
[
|
||||
'table_id' => 'taras 5',
|
||||
'message_type' => 'bill_request',
|
||||
'message_text' => '[DEMO] Prośba o rachunek | forma płatności: karta | dokument: paragon',
|
||||
'otwierajacy_imie' => 'Anna',
|
||||
'otwierajacy_nazwisko' => 'Nowak',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($samples as $sample) {
|
||||
$stmt->execute($sample);
|
||||
echo "Wstawiono demo: {$sample['message_type']} / stolik {$sample['table_id']}\n";
|
||||
}
|
||||
|
||||
echo "KDS feed: GET api/guest_action_queue.php?kds_secret=karczma_kuchnia\n";
|
||||
Reference in New Issue
Block a user