Add: Database verification scripts and troubleshooting guide
This commit is contained in:
195
TROUBLESHOOTING.md
Normal file
195
TROUBLESHOOTING.md
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
# Troubleshooting Guide
|
||||||
|
|
||||||
|
## Error: "Unknown column 't.amount' in 'SELECT'"
|
||||||
|
|
||||||
|
### Kemungkinan Penyebab:
|
||||||
|
1. **OPcache belum di-clear** - PHP masih menggunakan file lama
|
||||||
|
2. **Struktur database berbeda** - Kolom `amount` mungkin tidak ada atau nama berbeda
|
||||||
|
3. **File belum ter-update** - Meskipun sudah `git pull`, file mungkin belum benar-benar ter-update
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Solusi di Production
|
||||||
|
|
||||||
|
### Step 1: Clear OPcache
|
||||||
|
```bash
|
||||||
|
# Di production server
|
||||||
|
cd /www/wwwroot/api.btekno.cloud/api
|
||||||
|
|
||||||
|
# Clear OPcache via PHP CLI
|
||||||
|
php -r "opcache_reset();"
|
||||||
|
|
||||||
|
# Atau restart PHP-FPM
|
||||||
|
systemctl restart php-fpm
|
||||||
|
# atau
|
||||||
|
/www/server/php/83/bin/php-fpm restart
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Verify File Sudah Ter-update
|
||||||
|
```bash
|
||||||
|
# Cek apakah file sudah benar-benar ter-update
|
||||||
|
grep -n "COALESCE(t.amount, 0)" src/Modules/Retribusi/Summary/DailySummaryService.php
|
||||||
|
|
||||||
|
# Harus muncul di line 46 dan 61
|
||||||
|
# Line 46: COALESCE(t.amount, 0) as tariff_amount
|
||||||
|
# Line 61: COALESCE(t.amount, 0)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Verify Struktur Database
|
||||||
|
```bash
|
||||||
|
# Login ke MySQL
|
||||||
|
mysql -u sql_retribusi -p sql_retribusi
|
||||||
|
|
||||||
|
# Cek struktur tabel tariffs
|
||||||
|
DESCRIBE tariffs;
|
||||||
|
|
||||||
|
# Harus ada kolom:
|
||||||
|
# - location_code
|
||||||
|
# - gate_code
|
||||||
|
# - category
|
||||||
|
# - amount <-- INI HARUS ADA!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Test Query Manual
|
||||||
|
```bash
|
||||||
|
# Di MySQL client
|
||||||
|
mysql -u sql_retribusi -p sql_retribusi < bin/verify_query.sql
|
||||||
|
|
||||||
|
# Atau jalankan query ini manual:
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT
|
||||||
|
DATE(e.event_time) as summary_date,
|
||||||
|
e.location_code,
|
||||||
|
e.gate_code,
|
||||||
|
e.category,
|
||||||
|
COUNT(*) as total_count,
|
||||||
|
COALESCE(t.amount, 0) as tariff_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) = CURDATE()
|
||||||
|
GROUP BY
|
||||||
|
DATE(e.event_time),
|
||||||
|
e.location_code,
|
||||||
|
e.gate_code,
|
||||||
|
e.category,
|
||||||
|
COALESCE(t.amount, 0)
|
||||||
|
LIMIT 5;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Test Script Lagi
|
||||||
|
```bash
|
||||||
|
cd /www/wwwroot/api.btekno.cloud/api
|
||||||
|
php bin/daily_summary.php 2025-12-16
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cek Database Lokal
|
||||||
|
|
||||||
|
### Step 1: Setup .env (jika belum)
|
||||||
|
```bash
|
||||||
|
# Copy .env.example ke .env
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
# Edit .env, isi dengan database lokal:
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_NAME=sql_retribusi
|
||||||
|
DB_USER=sql_retribusi
|
||||||
|
DB_PASS=your_password_here
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Jalankan Script Check Database
|
||||||
|
```bash
|
||||||
|
php bin/check_database.php
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Verify Query di Lokal
|
||||||
|
```bash
|
||||||
|
# Via MySQL client
|
||||||
|
mysql -u sql_retribusi -p sql_retribusi < bin/verify_query.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Test Daily Summary di Lokal
|
||||||
|
```bash
|
||||||
|
php bin/daily_summary.php 2025-12-16
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Apply Migrations
|
||||||
|
|
||||||
|
### Migration yang Tersedia:
|
||||||
|
1. `001_create_audit_logs.sql` - Tabel audit_logs
|
||||||
|
2. `002_create_hourly_summary.sql` - Tabel hourly_summary
|
||||||
|
3. `003_create_realtime_events.sql` - Tabel realtime_events
|
||||||
|
|
||||||
|
### Cara Apply (Lokal):
|
||||||
|
```bash
|
||||||
|
# Via MySQL command line
|
||||||
|
mysql -u sql_retribusi -p sql_retribusi < migrations/001_create_audit_logs.sql
|
||||||
|
mysql -u sql_retribusi -p sql_retribusi < migrations/002_create_hourly_summary.sql
|
||||||
|
mysql -u sql_retribusi -p sql_retribusi < migrations/003_create_realtime_events.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cara Apply (Production):
|
||||||
|
```bash
|
||||||
|
# Di production server
|
||||||
|
cd /www/wwwroot/api.btekno.cloud/api
|
||||||
|
|
||||||
|
# Backup dulu!
|
||||||
|
mysqldump -u sql_retribusi -p sql_retribusi > backup_$(date +%Y%m%d_%H%M%S).sql
|
||||||
|
|
||||||
|
# Apply migration
|
||||||
|
mysql -u sql_retribusi -p sql_retribusi < migrations/001_create_audit_logs.sql
|
||||||
|
mysql -u sql_retribusi -p sql_retribusi < migrations/002_create_hourly_summary.sql
|
||||||
|
mysql -u sql_retribusi -p sql_retribusi < migrations/003_create_realtime_events.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Jika Masih Error
|
||||||
|
|
||||||
|
### Cek Log Error Detail:
|
||||||
|
```bash
|
||||||
|
# Di production
|
||||||
|
cd /www/wwwroot/api.btekno.cloud/api
|
||||||
|
php bin/daily_summary.php 2025-12-16 2>&1 | tee error.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cek Apakah Tabel Tariffs Ada:
|
||||||
|
```sql
|
||||||
|
-- Di MySQL
|
||||||
|
SHOW TABLES LIKE 'tariffs';
|
||||||
|
SELECT COUNT(*) FROM tariffs;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cek Apakah Ada Data di Entry Events:
|
||||||
|
```sql
|
||||||
|
-- Di MySQL
|
||||||
|
SELECT COUNT(*) FROM entry_events WHERE DATE(event_time) = CURDATE();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Fix (Jika OPcache Issue)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Di production, restart PHP-FPM
|
||||||
|
systemctl restart php-fpm
|
||||||
|
|
||||||
|
# Atau via aaPanel
|
||||||
|
# PHP → PHP-FPM → Restart
|
||||||
|
|
||||||
|
# Lalu test lagi
|
||||||
|
cd /www/wwwroot/api.btekno.cloud/api
|
||||||
|
php bin/daily_summary.php 2025-12-16
|
||||||
|
```
|
||||||
|
|
||||||
133
bin/check_database.php
Normal file
133
bin/check_database.php
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Script to check database structure
|
||||||
|
* Usage: php bin/check_database.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use App\Config\AppConfig;
|
||||||
|
use App\Support\Database;
|
||||||
|
|
||||||
|
// Load environment variables
|
||||||
|
AppConfig::loadEnv(__DIR__ . '/..');
|
||||||
|
|
||||||
|
// 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 credentials not configured in .env\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = Database::getConnection($dbHost, $dbName, $dbUser, $dbPass);
|
||||||
|
|
||||||
|
echo "=== Database Structure Check ===\n\n";
|
||||||
|
|
||||||
|
// Check tariffs table structure
|
||||||
|
echo "1. Checking tariffs table structure:\n";
|
||||||
|
$stmt = $db->query("DESCRIBE tariffs");
|
||||||
|
$columns = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($columns)) {
|
||||||
|
echo " ❌ Table 'tariffs' does not exist!\n";
|
||||||
|
} else {
|
||||||
|
echo " ✅ Table 'tariffs' exists with columns:\n";
|
||||||
|
foreach ($columns as $col) {
|
||||||
|
echo " - {$col['Field']} ({$col['Type']})\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n2. Checking locations table structure:\n";
|
||||||
|
$stmt = $db->query("DESCRIBE locations");
|
||||||
|
$columns = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($columns)) {
|
||||||
|
echo " ❌ Table 'locations' does not exist!\n";
|
||||||
|
} else {
|
||||||
|
echo " ✅ Table 'locations' exists with columns:\n";
|
||||||
|
foreach ($columns as $col) {
|
||||||
|
echo " - {$col['Field']} ({$col['Type']})\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n3. Checking gates table structure:\n";
|
||||||
|
$stmt = $db->query("DESCRIBE gates");
|
||||||
|
$columns = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($columns)) {
|
||||||
|
echo " ❌ Table 'gates' does not exist!\n";
|
||||||
|
} else {
|
||||||
|
echo " ✅ Table 'gates' exists with columns:\n";
|
||||||
|
foreach ($columns as $col) {
|
||||||
|
echo " - {$col['Field']} ({$col['Type']})\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n4. Checking entry_events table structure:\n";
|
||||||
|
$stmt = $db->query("DESCRIBE entry_events");
|
||||||
|
$columns = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (empty($columns)) {
|
||||||
|
echo " ❌ Table 'entry_events' does not exist!\n";
|
||||||
|
} else {
|
||||||
|
echo " ✅ Table 'entry_events' exists with columns:\n";
|
||||||
|
foreach ($columns as $col) {
|
||||||
|
echo " - {$col['Field']} ({$col['Type']})\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n5. Testing query (similar to DailySummaryService):\n";
|
||||||
|
$testSql = "
|
||||||
|
SELECT
|
||||||
|
DATE(e.event_time) as summary_date,
|
||||||
|
e.location_code,
|
||||||
|
e.gate_code,
|
||||||
|
e.category,
|
||||||
|
COUNT(*) as total_count,
|
||||||
|
COALESCE(t.amount, 0) as tariff_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) = CURDATE()
|
||||||
|
GROUP BY
|
||||||
|
DATE(e.event_time),
|
||||||
|
e.location_code,
|
||||||
|
e.gate_code,
|
||||||
|
e.category,
|
||||||
|
COALESCE(t.amount, 0)
|
||||||
|
LIMIT 1
|
||||||
|
";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $db->query($testSql);
|
||||||
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
echo " ✅ Query executed successfully!\n";
|
||||||
|
if ($result) {
|
||||||
|
echo " Sample result: " . json_encode($result, JSON_PRETTY_PRINT) . "\n";
|
||||||
|
} else {
|
||||||
|
echo " No data found for today.\n";
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo " ❌ Query failed: " . $e->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "\n=== Check Complete ===\n";
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo "Database Error: " . $e->getMessage() . "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user