555 lines
24 KiB
PHP
555 lines
24 KiB
PHP
<?php
|
|
header('Content-Type: application/json');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Methods: POST, GET, DELETE, OPTIONS');
|
|
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
|
http_response_code(200);
|
|
exit();
|
|
}
|
|
|
|
error_reporting(E_ALL);
|
|
ini_set('display_errors', 1);
|
|
ini_set('log_errors', 1);
|
|
ini_set('error_log', __DIR__ . '/../logs/php_error.log');
|
|
|
|
require_once '../config/database.php';
|
|
require_once '../includes/auth.php';
|
|
|
|
class TambahPengunjung {
|
|
private $conn;
|
|
private $auth;
|
|
|
|
public function __construct() {
|
|
$database = new Database();
|
|
$this->conn = $database->connect();
|
|
$this->auth = new Auth();
|
|
date_default_timezone_set('Asia/Jakarta');
|
|
}
|
|
|
|
public function handleRequest() {
|
|
if (!$this->auth->checkSession()) {
|
|
http_response_code(401);
|
|
echo json_encode([
|
|
'status' => 'error',
|
|
'message' => 'Unauthorized access',
|
|
'redirect' => '../admin/login.html'
|
|
]);
|
|
return;
|
|
}
|
|
|
|
$action = $_GET['action'] ?? $_POST['action'] ?? '';
|
|
$method = $_SERVER['REQUEST_METHOD'];
|
|
|
|
switch($action) {
|
|
case 'add_visitor':
|
|
if ($method === 'POST') $this->addVisitor();
|
|
break;
|
|
case 'clear_temp':
|
|
if ($method === 'POST' || $method === 'GET' || $method === 'DELETE') $this->clearRfidTemp(true);
|
|
break;
|
|
case 'end_session':
|
|
if ($method === 'POST' && isset($_POST['kode_gelang'])) {
|
|
$this->endPlaySession($_POST['kode_gelang']);
|
|
} else {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'error', 'message' => 'Kode gelang tidak ditemukan untuk mengakhiri sesi.']);
|
|
}
|
|
break;
|
|
case 'check_rfid':
|
|
if ($method === 'GET') $this->checkRfidStatus();
|
|
break;
|
|
case 'get_scanned_rfid':
|
|
if ($method === 'GET') $this->getScannedRfid();
|
|
break;
|
|
case 'simulate_scan':
|
|
if ($method === 'POST' && isset($_POST['kode_gelang'])) {
|
|
$this->simulateScan($_POST['kode_gelang']);
|
|
} else {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'error', 'message' => 'Kode gelang tidak ditemukan untuk simulasi scan.']);
|
|
}
|
|
break;
|
|
default:
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'error', 'message' => 'Action tidak ditentukan atau tidak valid.']);
|
|
}
|
|
}
|
|
|
|
private function getScannedRfid() {
|
|
try {
|
|
$query = "SELECT kode_gelang FROM rfid_temp ORDER BY id DESC LIMIT 1";
|
|
$stmt = $this->conn->prepare($query);
|
|
$stmt->execute();
|
|
|
|
if ($stmt->rowCount() > 0) {
|
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'data' => [
|
|
'kode_gelang' => $row['kode_gelang'],
|
|
'scanned' => true
|
|
]
|
|
]);
|
|
} else {
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'data' => [
|
|
'kode_gelang' => null,
|
|
'scanned' => false
|
|
]
|
|
]);
|
|
}
|
|
} catch(PDOException $e) {
|
|
error_log("Database error di getScannedRfid: " . $e->getMessage());
|
|
http_response_code(500);
|
|
echo json_encode([
|
|
'status' => 'error',
|
|
'message' => 'Database error di getScannedRfid: ' . $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function simulateScan($kodeGelang) {
|
|
try {
|
|
$query = "DELETE FROM rfid_temp";
|
|
$stmt = $this->conn->prepare($query);
|
|
$stmt->execute();
|
|
|
|
$query = "INSERT INTO rfid_temp (kode_gelang) VALUES (:kode_gelang)";
|
|
$stmt = $this->conn->prepare($query);
|
|
$stmt->bindParam(':kode_gelang', $kodeGelang);
|
|
$stmt->execute();
|
|
|
|
echo json_encode([
|
|
'status' => 'success',
|
|
'message' => 'RFID scan disimulasikan',
|
|
'kode_gelang' => $kodeGelang
|
|
]);
|
|
} catch(PDOException $e) {
|
|
error_log("Error simulasi scan: " . $e->getMessage());
|
|
http_response_code(500);
|
|
echo json_encode([
|
|
'status' => 'error',
|
|
'message' => 'Error simulasi scan: ' . $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function checkRfidStatus() {
|
|
try {
|
|
$query = "SELECT kode_gelang FROM rfid_temp ORDER BY id DESC LIMIT 1";
|
|
$stmt = $this->conn->prepare($query);
|
|
$stmt->execute();
|
|
|
|
if ($stmt->rowCount() === 0) {
|
|
echo json_encode([
|
|
'status' => 'error',
|
|
'message' => 'Belum ada gelang yang di-scan'
|
|
]);
|
|
return;
|
|
}
|
|
|
|
$tempData = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
$kodeGelang = $tempData['kode_gelang'];
|
|
|
|
// Cek status gelang di rfid_tags
|
|
$query = "SELECT id, status FROM rfid_tags WHERE kode_gelang = :kode_gelang";
|
|
$stmt = $this->conn->prepare($query);
|
|
$stmt->bindParam(':kode_gelang', $kodeGelang);
|
|
$stmt->execute();
|
|
|
|
if ($stmt->rowCount() === 0) {
|
|
echo json_encode([
|
|
'status' => 'error',
|
|
'message' => 'Gelang tidak dikenali'
|
|
]);
|
|
return;
|
|
}
|
|
|
|
$rfidData = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($rfidData['status'] === 'digunakan') {
|
|
// Gelang sedang digunakan. Cari sesi aktif terakhir yang menggunakan gelang ini.
|
|
$userData = $this->getCurrentActiveSessionData($kodeGelang);
|
|
|
|
if ($userData['status_waktu'] === 'tidak_aktif' || $userData['id_kunjungan'] === null) {
|
|
// Ini berarti rfid_tags bilang 'digunakan' tapi tidak ada sesi aktif di kunjungan.
|
|
// Ini adalah inkonsistensi data. Kita bisa coba reset status gelang ini.
|
|
// Namun, untuk alur normal, ini adalah error.
|
|
http_response_code(400); // Atau 500, tergantung seberapa parah ini dianggap
|
|
echo json_encode([
|
|
'status' => 'error',
|
|
'message' => 'Inkonsistensi data: Gelang ' . $kodeGelang . ' berstatus "digunakan" tetapi tidak ada sesi aktif yang ditemukan.',
|
|
'data' => $userData // Masih bisa tampilkan nama anak terakhir yang pakai
|
|
]);
|
|
// Opsional: Langsung reset status gelang di sini jika ini dianggap error yang bisa diatasi otomatis
|
|
// $this->resetRfidTagStatus($kodeGelang, $rfidData['id']);
|
|
} else {
|
|
echo json_encode([
|
|
'status' => 'in_use',
|
|
'message' => 'Gelang sedang digunakan',
|
|
'data' => $userData
|
|
]);
|
|
}
|
|
} else {
|
|
// Gelang tersedia, siap untuk pendaftaran baru
|
|
echo json_encode([
|
|
'status' => 'available',
|
|
'message' => 'Gelang siap digunakan',
|
|
'data' => [
|
|
'kode_gelang' => $kodeGelang
|
|
]
|
|
]);
|
|
}
|
|
} catch(PDOException $e) {
|
|
error_log("Database error di checkRfidStatus: " . $e->getMessage());
|
|
http_response_code(500);
|
|
echo json_encode([
|
|
'status' => 'error',
|
|
'message' => 'Database error di checkRfidStatus: ' . $e->getMessage()
|
|
]);
|
|
} catch(Exception $e) {
|
|
error_log("Error umum di checkRfidStatus: " . $e->getMessage());
|
|
http_response_code(500);
|
|
echo json_encode(['status' => 'error', 'message' => 'Error sistem di checkRfidStatus: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mencari data sesi aktif terakhir untuk sebuah kode gelang.
|
|
* Mengambil id_anak dari kunjungan terbaru dan mendapatkan detail anak dari tabel anak.
|
|
* @param string $kodeGelang
|
|
* @return array
|
|
*/
|
|
private function getCurrentActiveSessionData($kodeGelang) {
|
|
try {
|
|
// Kita perlu mencari kunjungan yang paling baru dan aktif, yang kode gelangnya sesuai.
|
|
// Langkah ini membutuhkan JOIN antara kunjungan dan anak untuk mendapatkan kode_gelang
|
|
// Serta JOIN dengan rfid_tags untuk memastikan status gelang (meskipun rfid_tags sudah dicek di checkRfidStatus)
|
|
$query = "
|
|
SELECT
|
|
k.id AS id_kunjungan,
|
|
k.waktu_masuk,
|
|
a.nama AS nama_anak,
|
|
a.durasi AS durasi_anak_db
|
|
FROM
|
|
kunjungan k
|
|
JOIN
|
|
anak a ON k.id_anak = a.id
|
|
JOIN
|
|
rfid_tags rt ON a.kode_gelang = rt.kode_gelang -- Join untuk memastikan kode gelang ini
|
|
WHERE
|
|
rt.kode_gelang = :kode_gelang AND k.waktu_keluar IS NULL
|
|
ORDER BY
|
|
k.waktu_masuk DESC, k.id DESC -- Ambil yang paling baru masuk, lalu id terbaru
|
|
LIMIT 1
|
|
";
|
|
|
|
$stmt = $this->conn->prepare($query);
|
|
$stmt->bindParam(':kode_gelang', $kodeGelang);
|
|
$stmt->execute();
|
|
$kunjunganData = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$kunjunganData) {
|
|
// Tidak ada sesi aktif ditemukan untuk kode gelang ini
|
|
return [
|
|
'nama' => 'Tidak Ada',
|
|
'kode_gelang' => $kodeGelang,
|
|
'sisa_waktu' => 'Tidak ada sesi aktif',
|
|
'status_waktu' => 'tidak_aktif',
|
|
'color_class' => 'text-gray-500',
|
|
'id_kunjungan' => null
|
|
];
|
|
}
|
|
|
|
$waktuMasuk = new DateTime($kunjunganData['waktu_masuk']);
|
|
|
|
// Konversi durasi dari format HH:MM:SS ke total detik
|
|
list($h, $m, $s) = explode(':', $kunjunganData['durasi_anak_db']);
|
|
$durasiTotalDetik = ($h * 3600) + ($m * 60) + $s;
|
|
|
|
$waktuSelesaiSeharusnya = clone $waktuMasuk;
|
|
$waktuSelesaiSeharusnya->modify("+$durasiTotalDetik seconds");
|
|
|
|
$now = new DateTime();
|
|
$sisaWaktuDetik = $waktuSelesaiSeharusnya->getTimestamp() - $now->getTimestamp();
|
|
|
|
$sisaWaktuFormatted = "";
|
|
$colorClass = "";
|
|
|
|
if ($sisaWaktuDetik <= 0) {
|
|
$sisaWaktuFormatted = "Telat " . floor(abs($sisaWaktuDetik) / 60) . " menit";
|
|
$colorClass = "text-red-500";
|
|
} else if ($sisaWaktuDetik <= (10 * 60)) {
|
|
$sisaWaktuFormatted = floor($sisaWaktuDetik / 60) . " menit " . ($sisaWaktuDetik % 60) . " detik";
|
|
$colorClass = "text-orange-500";
|
|
} else {
|
|
$hours = floor($sisaWaktuDetik / 3600);
|
|
$minutes = floor(($sisaWaktuDetik % 3600) / 60);
|
|
$sisaWaktuFormatted = sprintf("%02d:%02d", $hours, $minutes);
|
|
$colorClass = "text-green-500";
|
|
}
|
|
|
|
return [
|
|
'nama' => $kunjunganData['nama_anak'],
|
|
'kode_gelang' => $kodeGelang,
|
|
'sisa_waktu' => $sisaWaktuFormatted,
|
|
'status_waktu' => ($sisaWaktuDetik <= 0) ? 'habis' : 'tersisa',
|
|
'color_class' => $colorClass,
|
|
'id_kunjungan' => $kunjunganData['id_kunjungan'] // ID kunjungan yang sedang aktif
|
|
];
|
|
} catch(Exception $e) {
|
|
error_log("Error in getCurrentActiveSessionData: " . $e->getMessage());
|
|
return [
|
|
'nama' => 'Error',
|
|
'kode_gelang' => $kodeGelang,
|
|
'sisa_waktu' => 'N/A',
|
|
'status_waktu' => 'error',
|
|
'color_class' => 'text-red-500',
|
|
'id_kunjungan' => null
|
|
];
|
|
}
|
|
}
|
|
|
|
private function addVisitor() {
|
|
$namaAnak = $_POST['namaAnak'] ?? '';
|
|
$noHpOrtu = $_POST['noHpOrtu'] ?? '';
|
|
$durasiMenit = $_POST['durasi'] ?? '';
|
|
$kodeGelang = $_POST['kodeGelang'] ?? '';
|
|
|
|
if (empty($namaAnak) || empty($noHpOrtu) || empty($durasiMenit) || empty($kodeGelang)) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'error', 'message' => 'Semua field wajib diisi.']);
|
|
return;
|
|
}
|
|
|
|
if (strlen($namaAnak) < 2) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'error', 'message' => 'Nama anak minimal 2 karakter.', 'field' => 'namaAnak']);
|
|
return;
|
|
}
|
|
|
|
$noHpOrtuClean = preg_replace('/\D/', '', $noHpOrtu);
|
|
if (!preg_match('/^\d{10,15}$/', $noHpOrtuClean)) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'error', 'message' => 'Nomor HP tidak valid (10-15 digit angka).', 'field' => 'noHpOrtu']);
|
|
return;
|
|
}
|
|
|
|
$validDurations = [30, 60, 90, 120, 180, 240];
|
|
if (!in_array((int)$durasiMenit, $validDurations)) {
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'error', 'message' => 'Durasi bermain tidak valid.', 'field' => 'durasi']);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$this->conn->beginTransaction();
|
|
|
|
// 1. Cek status RFID di tabel rfid_tags
|
|
$queryRfid = "SELECT id, status FROM rfid_tags WHERE kode_gelang = :kode_gelang";
|
|
$stmtRfid = $this->conn->prepare($queryRfid);
|
|
$stmtRfid->bindParam(':kode_gelang', $kodeGelang);
|
|
$stmtRfid->execute();
|
|
$rfidData = $stmtRfid->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$rfidData) {
|
|
$this->conn->rollBack();
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'error', 'message' => 'Kode gelang tidak ditemukan di sistem.']);
|
|
return;
|
|
}
|
|
if ($rfidData['status'] === 'digunakan') {
|
|
$this->conn->rollBack();
|
|
http_response_code(400);
|
|
echo json_encode(['status' => 'error', 'message' => 'Gelang sudah digunakan oleh pengunjung lain.']);
|
|
return;
|
|
}
|
|
$idGelangRfid = $rfidData['id']; // ID internal gelang dari rfid_tags, tetap simpan untuk update status rfid_tags
|
|
|
|
// 2. Insert atau update ke tabel 'anak'
|
|
// Cari anak berdasarkan nama dan no_hp (jika ada, update durasi dan kode_gelang)
|
|
$queryCheckAnak = "SELECT id FROM anak WHERE nama = :nama_anak AND no_hp = :no_hp_ortu LIMIT 1";
|
|
$stmtCheckAnak = $this->conn->prepare($queryCheckAnak);
|
|
$stmtCheckAnak->bindParam(':nama_anak', $namaAnak);
|
|
$stmtCheckAnak->bindParam(':no_hp_ortu', $noHpOrtuClean);
|
|
$stmtCheckAnak->execute();
|
|
$idAnak = $stmtCheckAnak->fetchColumn();
|
|
|
|
$durasiFormattedForAnakTable = $this->formatDuration($durasiMenit);
|
|
|
|
if (!$idAnak) {
|
|
// Jika anak belum ada, insert baru
|
|
// Kode gelang disimpan di tabel anak (sesuai kebutuhan Anda)
|
|
$queryInsertAnak = "INSERT INTO anak (nama, kode_gelang, no_hp, durasi) VALUES (:nama, :kode_gelang, :no_hp, :durasi)";
|
|
$stmtInsertAnak = $this->conn->prepare($queryInsertAnak);
|
|
$stmtInsertAnak->bindParam(':nama', $namaAnak);
|
|
$stmtInsertAnak->bindParam(':kode_gelang', $kodeGelang);
|
|
$stmtInsertAnak->bindParam(':no_hp', $noHpOrtuClean);
|
|
$stmtInsertAnak->bindParam(':durasi', $durasiFormattedForAnakTable);
|
|
$stmtInsertAnak->execute();
|
|
$idAnak = $this->conn->lastInsertId();
|
|
} else {
|
|
// Jika anak sudah ada, update info gelang dan durasi di tabel anak
|
|
$queryUpdateAnak = "UPDATE anak SET kode_gelang = :kode_gelang, durasi = :durasi WHERE id = :id_anak";
|
|
$stmtUpdateAnak = $this->conn->prepare($queryUpdateAnak);
|
|
$stmtUpdateAnak->bindParam(':kode_gelang', $kodeGelang);
|
|
$stmtUpdateAnak->bindParam(':durasi', $durasiFormattedForAnakTable);
|
|
$stmtUpdateAnak->bindParam(':id_anak', $idAnak);
|
|
$stmtUpdateAnak->execute();
|
|
}
|
|
|
|
// 3. Insert ke tabel 'kunjungan'
|
|
// Hanya ada id_anak, waktu_masuk, waktu_keluar
|
|
$queryKunjungan = "INSERT INTO kunjungan (id_anak, waktu_masuk, waktu_keluar) VALUES (:id_anak, NOW(), NULL)";
|
|
$stmtKunjungan = $this->conn->prepare($queryKunjungan);
|
|
$stmtKunjungan->bindParam(':id_anak', $idAnak);
|
|
$stmtKunjungan->execute();
|
|
|
|
// 4. Update status di tabel 'rfid_tags'
|
|
$queryUpdateRfid = "UPDATE rfid_tags SET status = 'digunakan' WHERE id = :id_gelang";
|
|
$stmtUpdateRfid = $this->conn->prepare($queryUpdateRfid);
|
|
$stmtUpdateRfid->bindParam(':id_gelang', $idGelangRfid);
|
|
$stmtUpdateRfid->execute();
|
|
|
|
// 5. Clear rfid_temp after successful registration
|
|
$this->clearRfidTemp();
|
|
|
|
$this->conn->commit();
|
|
echo json_encode(['status' => 'success', 'message' => 'Pengunjung berhasil didaftarkan!']);
|
|
|
|
} catch(PDOException $e) {
|
|
$this->conn->rollBack();
|
|
error_log("PDOException di addVisitor: " . $e->getMessage() . " di baris " . $e->getLine());
|
|
http_response_code(500);
|
|
echo json_encode(['status' => 'error', 'message' => 'Error mendaftarkan pengunjung (DB): ' . $e->getMessage()]);
|
|
} catch(Exception $e) {
|
|
$this->conn->rollBack();
|
|
error_log("Exception umum di addVisitor: " . $e->getMessage() . " di baris " . $e->getLine());
|
|
http_response_code(500);
|
|
echo json_encode(['status' => 'error', 'message' => 'Error sistem (umum): ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mengakhiri sesi permainan untuk kode gelang yang diberikan.
|
|
* Mencari sesi kunjungan aktif paling baru yang terkait dengan kode gelang tersebut.
|
|
* @param string $kodeGelang
|
|
*/
|
|
private function endPlaySession($kodeGelang) {
|
|
try {
|
|
$this->conn->beginTransaction();
|
|
|
|
// 1. Dapatkan ID kunjungan aktif paling baru yang terkait dengan kode_gelang ini
|
|
// JOIN dengan tabel anak untuk mendapatkan id_anak yang terhubung dengan kode_gelang,
|
|
// lalu cari kunjungan aktif terbaru untuk id_anak tersebut.
|
|
$queryKunjungan = "
|
|
SELECT
|
|
k.id AS id_kunjungan_to_end,
|
|
a.id AS id_anak_affected
|
|
FROM
|
|
kunjungan k
|
|
JOIN
|
|
anak a ON k.id_anak = a.id
|
|
WHERE
|
|
a.kode_gelang = :kode_gelang AND k.waktu_keluar IS NULL
|
|
ORDER BY
|
|
k.waktu_masuk DESC, k.id DESC
|
|
LIMIT 1
|
|
";
|
|
$stmtKunjungan = $this->conn->prepare($queryKunjungan);
|
|
$stmtKunjungan->bindParam(':kode_gelang', $kodeGelang);
|
|
$stmtKunjungan->execute();
|
|
$activeKunjungan = $stmtKunjungan->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$activeKunjungan) {
|
|
// Ini bisa terjadi jika gelang sudah di-set 'digunakan' di rfid_tags,
|
|
// tapi tidak ada kunjungan aktif yang cocok di tabel kunjungan.
|
|
// Ini adalah inkonsistensi data. Kita tetap bebaskan gelangnya.
|
|
error_log("Peringatan: Gelang " . $kodeGelang . " berstatus 'digunakan' di rfid_tags, tetapi tidak ada sesi aktif di kunjungan. Mencoba reset status gelang saja.");
|
|
$this->resetRfidTagStatus($kodeGelang); // Panggil fungsi reset
|
|
$this->clearRfidTemp();
|
|
$this->conn->commit();
|
|
echo json_encode(['status' => 'warning', 'message' => 'Tidak ada sesi aktif ditemukan, tetapi status gelang telah direset menjadi "tersedia".']);
|
|
return;
|
|
}
|
|
|
|
$idKunjunganToEnd = $activeKunjungan['id_kunjungan_to_end'];
|
|
$idAnakAffected = $activeKunjungan['id_anak_affected'];
|
|
|
|
// 2. Update waktu_keluar di tabel 'kunjungan' untuk sesi yang ditemukan
|
|
$queryUpdateKunjungan = "UPDATE kunjungan SET waktu_keluar = NOW() WHERE id = :id_kunjungan";
|
|
$stmtUpdateKunjungan = $this->conn->prepare($queryUpdateKunjungan);
|
|
$stmtUpdateKunjungan->bindParam(':id_kunjungan', $idKunjunganToEnd);
|
|
$stmtUpdateKunjungan->execute();
|
|
|
|
// 3. Update status di tabel 'rfid_tags' menjadi 'tersedia'
|
|
$queryUpdateRfid = "UPDATE rfid_tags SET status = 'tersedia' WHERE kode_gelang = :kode_gelang";
|
|
$stmtUpdateRfid = $this->conn->prepare($queryUpdateRfid);
|
|
$stmtUpdateRfid->bindParam(':kode_gelang', $kodeGelang);
|
|
$stmtUpdateRfid->execute();
|
|
|
|
// 4. Clear rfid_temp after ending session
|
|
$this->clearRfidTemp();
|
|
|
|
$this->conn->commit();
|
|
echo json_encode(['status' => 'success', 'message' => 'Sesi permainan berhasil diakhiri! Gelang telah dibebaskan.']);
|
|
|
|
} catch(PDOException $e) {
|
|
$this->conn->rollBack();
|
|
error_log("PDOException di endPlaySession: " . $e->getMessage() . " di baris " . $e->getLine());
|
|
http_response_code(500);
|
|
echo json_encode(['status' => 'error', 'message' => 'Error mengakhiri sesi (DB): ' . $e->getMessage()]);
|
|
} catch(Exception $e) {
|
|
$this->conn->rollBack();
|
|
error_log("Exception umum di endPlaySession: " . $e->getMessage() . " di baris " . $e->getLine());
|
|
http_response_code(500);
|
|
echo json_encode(['status' => 'error', 'message' => 'Error sistem (umum): ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fungsi untuk mereset status gelang di rfid_tags menjadi 'tersedia'.
|
|
* Berguna untuk mengatasi inkonsistensi data.
|
|
* @param string $kodeGelang
|
|
*/
|
|
private function resetRfidTagStatus($kodeGelang) {
|
|
try {
|
|
$query = "UPDATE rfid_tags SET status = 'tersedia' WHERE kode_gelang = :kode_gelang";
|
|
$stmt = $this->conn->prepare($query);
|
|
$stmt->bindParam(':kode_gelang', $kodeGelang);
|
|
$stmt->execute();
|
|
error_log("Gelang " . $kodeGelang . " statusnya berhasil direset menjadi 'tersedia' karena inkonsistensi data.");
|
|
} catch(PDOException $e) {
|
|
error_log("Error resetting RFID tag status for " . $kodeGelang . ": " . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
private function clearRfidTemp($returnJson = false) {
|
|
try {
|
|
$query = "DELETE FROM rfid_temp";
|
|
$stmt = $this->conn->prepare($query);
|
|
$stmt->execute();
|
|
if ($returnJson) {
|
|
echo json_encode(['status' => 'success', 'message' => 'RFID temp cleared']);
|
|
}
|
|
} catch(PDOException $e) {
|
|
error_log("Error clearing RFID temp: " . $e->getMessage());
|
|
if ($returnJson) {
|
|
http_response_code(500);
|
|
echo json_encode(['status' => 'error', 'message' => 'Error clearing RFID temp: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function formatDuration($minutes) {
|
|
$hours = floor($minutes / 60);
|
|
$remainingMinutes = $minutes % 60;
|
|
return sprintf('%02d:%02d:00', $hours, $remainingMinutes);
|
|
}
|
|
}
|
|
|
|
$controller = new TambahPengunjung();
|
|
$controller->handleRequest(); |