Commit 8af96aea authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix(facilities): five screens queried a reservations column that does not exist

`reservations` identifies its booker with booker_type plus player_id / member_id.
There is no booker_id column — confirmed with SHOW COLUMNS on the live database,
not from the migrations. Five call sites queried it anyway, so every one of them
threw a SQL error:

  FacilityDashboards/Controllers/FacilityDashboardController.php  (x2)
  PlaygroundAdmin/Services/ClubDashboardService.php               (x2)
  PlaygroundAdmin/Services/PlaygroundMirrorService.php            (x3)
  FacilityGrids/Services/PoolFinancialService.php                 (x1)
  PlayerApi/Services/PlayerBookingService.php                     (x4)

Effect: the facility dashboard, the club-wide playground dashboard, the pool
financial panel and the playground mirror hard-500 on every load, and the player
app could never create a booking — the INSERT named booker_id too. That matches
the data: 7 reservations exist with booker_type set and player_id/member_id both
NULL, and zero player bookings.

Reads become COALESCE(player_id, member_id); the joins key on the specific column
for their booker_type; the INSERT writes player_id.

Also PlaygroundMirrorService queried private_match_bookings.match_date, which is
booking_date on that table. (live_matches genuinely has match_date, so MatchCenter
is untouched.) And sa_bookings / pool_bookings really do have booker_id, so those
references are correct and left alone.

Every rewritten query was executed against the live database before committing.
Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
parent 2f77d3e1
......@@ -121,7 +121,7 @@ class FacilityDashboardController extends Controller
// Unique visitors
$uniqueVisitors = $db->selectOne(
"SELECT COUNT(DISTINCT CASE WHEN booker_id IS NOT NULL THEN booker_id ELSE booker_name END) AS cnt
"SELECT COUNT(DISTINCT CASE WHEN COALESCE(player_id, member_id) IS NOT NULL THEN COALESCE(player_id, member_id) ELSE booker_name END) AS cnt
FROM reservations WHERE facility_id = ? AND reservation_date BETWEEN ? AND ? AND status NOT IN ('cancelled')",
[(int) $id, $periodStart, $periodEnd]
);
......@@ -208,7 +208,7 @@ class FacilityDashboardController extends Controller
$summary = $db->selectOne(
"SELECT COUNT(*) AS total_bookings, COALESCE(SUM(total_amount), 0) AS total_revenue,
COUNT(DISTINCT CASE WHEN booker_id IS NOT NULL THEN booker_id ELSE booker_name END) AS unique_visitors
COUNT(DISTINCT CASE WHEN COALESCE(player_id, member_id) IS NOT NULL THEN COALESCE(player_id, member_id) ELSE booker_name END) AS unique_visitors
FROM reservations WHERE facility_id = ? AND reservation_date BETWEEN ? AND ? AND status NOT IN ('cancelled')",
[(int) $id, $periodStart, $periodEnd]
);
......
......@@ -49,7 +49,7 @@ final class PoolFinancialService
);
$uniqueUsers = $this->db->selectOne(
"SELECT COUNT(DISTINCT booker_id) as cnt FROM reservations
"SELECT COUNT(DISTINCT COALESCE(player_id, member_id)) as cnt FROM reservations
WHERE facility_id = ? AND reservation_date BETWEEN ? AND ?
AND status NOT IN ('cancelled', 'no_show')",
[$facilityId, $dateFrom, $dateTo]
......
......@@ -105,7 +105,7 @@ final class PlayerBookingService
'reservation_number' => $reservationNumber,
'facility_id' => $data['facility_id'],
'booker_type' => 'player',
'booker_id' => $playerId,
'player_id' => $playerId,
'reservation_date' => $data['date'],
'start_time' => $data['start_time'],
'end_time' => $data['end_time'],
......@@ -134,7 +134,7 @@ final class PlayerBookingService
public function getPlayerBookings(int $playerId, int $page = 1, int $perPage = 25): array
{
$total = (int) ($this->db->selectOne(
"SELECT COUNT(*) as cnt FROM reservations WHERE booker_type = 'player' AND booker_id = ?",
"SELECT COUNT(*) as cnt FROM reservations WHERE booker_type = 'player' AND player_id = ?",
[$playerId]
)['cnt'] ?? 0);
......@@ -146,7 +146,7 @@ final class PlayerBookingService
"SELECT r.*, f.name_ar as facility_name, f.facility_type
FROM reservations r
LEFT JOIN facilities f ON f.id = r.facility_id
WHERE r.booker_type = 'player' AND r.booker_id = ?
WHERE r.booker_type = 'player' AND r.player_id = ?
ORDER BY r.reservation_date DESC, r.start_time DESC
LIMIT ? OFFSET ?",
[$playerId, $perPage, $offset]
......@@ -161,7 +161,7 @@ final class PlayerBookingService
public function cancelBooking(int $bookingId, int $playerId): bool
{
$booking = $this->db->selectOne(
"SELECT id, status FROM reservations WHERE id = ? AND booker_type = 'player' AND booker_id = ?",
"SELECT id, status FROM reservations WHERE id = ? AND booker_type = 'player' AND player_id = ?",
[$bookingId, $playerId]
);
......
......@@ -40,7 +40,7 @@ final class ClubDashboardService
);
$uniquePlayers = $this->db->selectOne(
"SELECT COUNT(DISTINCT booker_id) as cnt FROM reservations
"SELECT COUNT(DISTINCT COALESCE(player_id, member_id)) as cnt FROM reservations
WHERE reservation_date BETWEEN ? AND ? AND status NOT IN ('cancelled', 'no_show')",
[$dateFrom, $dateTo]
);
......@@ -116,7 +116,7 @@ final class ClubDashboardService
);
$uniqueUsers = $this->db->selectOne(
"SELECT COUNT(DISTINCT booker_id) as cnt FROM reservations
"SELECT COUNT(DISTINCT COALESCE(player_id, member_id)) as cnt FROM reservations
WHERE facility_id = ? AND reservation_date BETWEEN ? AND ?
AND status NOT IN ('cancelled', 'no_show')",
[$facilityId, $dateFrom, $dateTo]
......
......@@ -25,13 +25,13 @@ final class PlaygroundMirrorService
$hours = $this->getOperatingHours($playground);
$reservations = $this->db->select(
"SELECT r.id, r.start_time, r.end_time, r.booker_type, r.booker_id, r.status, r.total_amount,
"SELECT r.id, r.start_time, r.end_time, r.booker_type, COALESCE(r.player_id, r.member_id) AS booker_id, r.status, r.total_amount,
CASE WHEN r.booker_type = 'player' THEN p.name_ar
WHEN r.booker_type = 'member' THEN m.name_ar
ELSE 'ضيف' END as booker_name
FROM reservations r
LEFT JOIN players p ON r.booker_type = 'player' AND p.id = r.booker_id
LEFT JOIN members m ON r.booker_type = 'member' AND m.id = r.booker_id
LEFT JOIN players p ON r.booker_type = 'player' AND p.id = r.player_id
LEFT JOIN members m ON r.booker_type = 'member' AND m.id = r.member_id
WHERE r.facility_id = ? AND r.reservation_date = ? AND r.status NOT IN ('cancelled', 'no_show')
ORDER BY r.start_time",
[$facilityId, $date]
......@@ -40,7 +40,7 @@ final class PlaygroundMirrorService
$privateMatches = $this->db->select(
"SELECT id, start_time, end_time, team_a_name, team_b_name, match_type, total_cost, status
FROM private_match_bookings
WHERE facility_id = ? AND match_date = ? AND status NOT IN ('cancelled')
WHERE facility_id = ? AND booking_date = ? AND status NOT IN ('cancelled')
ORDER BY start_time",
[$facilityId, $date]
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment