Commit c9938287 authored by DevPilot's avatar DevPilot

fix(sql): final pass — schema checker now clean across app/

كمّلت باقي الأعمدة الغلط: payments (مفيهاش status/receipt_number/payable_*)،
academy_contracts، facility_zone_schedules (جدول متكرر بيوم الأسبوع مش بتاريخ)،
carnets، sa_attendance (المجموعة على الحجز)، وsubscriptions للسنة المالية.

tools/sql_schema_check.py بيعدّي دلوقتي على app/ كلها من غير أي ملاحظة.
parent b29e4e27
...@@ -127,9 +127,9 @@ class CoachPerformanceMetric extends Model ...@@ -127,9 +127,9 @@ class CoachPerformanceMetric extends Model
// Revenue generated (from payments linked to sessions) // Revenue generated (from payments linked to sessions)
$revenue = $db->selectOne( $revenue = $db->selectOne(
"SELECT COALESCE(SUM(cp.amount), 0) AS total_revenue "SELECT COALESCE(SUM(cp.net_amount), 0) AS total_revenue
FROM coach_payments cp FROM coach_payments cp
WHERE cp.coach_id = ? AND cp.period_month = ?", WHERE cp.coach_id = ? AND cp.payment_period = ?",
[$coachId, $month] [$coachId, $month]
); );
$revenueGenerated = (string) ($revenue['total_revenue'] ?? '0.00'); $revenueGenerated = (string) ($revenue['total_revenue'] ?? '0.00');
......
...@@ -76,7 +76,7 @@ class AccessControlService ...@@ -76,7 +76,7 @@ class AccessControlService
if (!$memberId) return false; if (!$memberId) return false;
$db = App::getInstance()->db(); $db = App::getInstance()->db();
$member = $db->selectOne( $member = $db->selectOne(
"SELECT id FROM members WHERE id = ? AND membership_status = 'active' AND membership_type IN ('vip', 'premium', 'gold')", "SELECT id FROM members WHERE id = ? AND status = 'active' AND membership_type IN ('vip', 'premium', 'gold')",
[$memberId] [$memberId]
); );
return $member !== null && $member !== false; return $member !== null && $member !== false;
......
...@@ -32,9 +32,8 @@ final class FacilityAttendanceController extends Controller ...@@ -32,9 +32,8 @@ final class FacilityAttendanceController extends Controller
$coaches = $db->select( $coaches = $db->select(
"SELECT DISTINCT fzs.coach_id, c.full_name_ar "SELECT DISTINCT fzs.coach_id, c.full_name_ar
FROM facility_zone_schedules fzs FROM facility_zone_schedules fzs
INNER JOIN facility_grid_zones fgz ON fgz.id = fzs.zone_id
INNER JOIN coaches c ON c.id = fzs.coach_id INNER JOIN coaches c ON c.id = fzs.coach_id
WHERE fgz.grid_id = ? AND fzs.is_active = 1", WHERE fzs.grid_id = ? AND fzs.is_active = 1",
[(int) $gridId] [(int) $gridId]
); );
...@@ -43,7 +42,7 @@ final class FacilityAttendanceController extends Controller ...@@ -43,7 +42,7 @@ final class FacilityAttendanceController extends Controller
FROM facility_zone_trainees fzt FROM facility_zone_trainees fzt
INNER JOIN facility_grid_zones fgz ON fgz.id = fzt.zone_id INNER JOIN facility_grid_zones fgz ON fgz.id = fzt.zone_id
INNER JOIN players p ON p.id = fzt.player_id INNER JOIN players p ON p.id = fzt.player_id
WHERE fgz.grid_id = ? AND fzt.is_active = 1", WHERE fgz.grid_id = ?",
[(int) $gridId] [(int) $gridId]
); );
......
...@@ -103,7 +103,7 @@ final class FacilityAttendanceService ...@@ -103,7 +103,7 @@ final class FacilityAttendanceService
FROM facility_zone_trainees fzt FROM facility_zone_trainees fzt
INNER JOIN facility_grid_zones fgz ON fgz.id = fzt.zone_id INNER JOIN facility_grid_zones fgz ON fgz.id = fzt.zone_id
INNER JOIN players p ON p.id = fzt.player_id INNER JOIN players p ON p.id = fzt.player_id
WHERE fgz.grid_id = ? AND fzt.is_active = 1", WHERE fgz.grid_id = ?",
[$gridId] [$gridId]
); );
......
...@@ -132,7 +132,7 @@ final class AttendanceViolationService ...@@ -132,7 +132,7 @@ final class AttendanceViolationService
if ($dayOfWeek === 5) return []; if ($dayOfWeek === 5) return [];
$isHoliday = $db->selectOne( $isHoliday = $db->selectOne(
"SELECT id FROM hr_holidays WHERE holiday_date = ?", "SELECT id FROM hr_holidays WHERE `date` = ?",
[$date] [$date]
); );
if ($isHoliday) return []; if ($isHoliday) return [];
......
...@@ -67,11 +67,12 @@ final class AssetCustodyService ...@@ -67,11 +67,12 @@ final class AssetCustodyService
return $db->select( return $db->select(
"SELECT ach.*, "SELECT ach.*,
ef.name_ar as from_name, et.name_ar as to_name, eb.name_ar as transferred_by_name ef.full_name_ar as from_name, et.full_name_ar as to_name,
eb.full_name_ar as transferred_by_name
FROM asset_custody_history ach FROM asset_custody_history ach
LEFT JOIN employees ef ON ef.id = ach.from_employee_id LEFT JOIN employees ef ON ef.id = ach.from_employee_id
LEFT JOIN employees et ON et.id = ach.to_employee_id LEFT JOIN employees et ON et.id = ach.to_employee_id
LEFT JOIN employees eb ON eb.id = ach.transferred_by LEFT JOIN employees eb ON eb.id = ach.created_by
WHERE ach.asset_id = ? WHERE ach.asset_id = ?
ORDER BY ach.transfer_date DESC, ach.id DESC", ORDER BY ach.transfer_date DESC, ach.id DESC",
[$assetId] [$assetId]
...@@ -87,7 +88,7 @@ final class AssetCustodyService ...@@ -87,7 +88,7 @@ final class AssetCustodyService
FROM asset_register ar FROM asset_register ar
LEFT JOIN asset_categories ac ON ac.id = ar.category_id LEFT JOIN asset_categories ac ON ac.id = ar.category_id
WHERE ar.custodian_employee_id = ? WHERE ar.custodian_employee_id = ?
ORDER BY ar.asset_name_ar", ORDER BY ar.asset_name",
[$employeeId] [$employeeId]
); );
} }
......
...@@ -1101,7 +1101,11 @@ final class MembershipRulesService ...@@ -1101,7 +1101,11 @@ final class MembershipRulesService
if (!$firstYearCovered) { if (!$firstYearCovered) {
$paid = $db->selectOne( $paid = $db->selectOne(
"SELECT id FROM payments WHERE member_id = ? AND payment_type = 'annual_subscription' AND financial_year = ? AND is_voided = 0 LIMIT 1", // السنة المالية متسجّلة على الاشتراك مش على الدفعة
"SELECT id FROM subscriptions
WHERE member_id = ? AND financial_year = ?
AND person_type = 'member' AND status = 'paid'
LIMIT 1",
[$memberId, $currentYear] [$memberId, $currentYear]
); );
......
...@@ -127,7 +127,7 @@ final class CronNotificationService ...@@ -127,7 +127,7 @@ final class CronNotificationService
JOIN players p ON p.id = asub.player_id JOIN players p ON p.id = asub.player_id
JOIN sport_disciplines a ON a.id = asub.discipline_id JOIN sport_disciplines a ON a.id = asub.discipline_id
WHERE asub.status = 'active' WHERE asub.status = 'active'
AND asub.next_payment_date = ? AND asub.due_date = ?
AND p.is_archived = 0 AND p.is_archived = 0
", [$targetDate]); ", [$targetDate]);
......
...@@ -63,8 +63,12 @@ final class PaymentApiV1Controller extends ApiController ...@@ -63,8 +63,12 @@ final class PaymentApiV1Controller extends ApiController
$offset = ($page - 1) * $perPage; $offset = ($page - 1) * $perPage;
$rows = $db->select( $rows = $db->select(
"SELECT p.id, p.member_id, p.payment_type, p.payment_method, p.amount, p.payment_date, p.receipt_number, p.status, p.created_at "SELECT p.id, p.member_id, p.payment_type, p.payment_method, p.amount, p.payment_date,
r.receipt_number,
CASE WHEN p.is_voided = 1 THEN 'voided' ELSE 'completed' END AS status,
p.created_at
FROM payments p FROM payments p
LEFT JOIN receipts r ON r.id = p.receipt_id
WHERE {$whereSql} WHERE {$whereSql}
ORDER BY p.id DESC ORDER BY p.id DESC
LIMIT {$perPage} OFFSET {$offset}", LIMIT {$perPage} OFFSET {$offset}",
...@@ -83,7 +87,7 @@ final class PaymentApiV1Controller extends ApiController ...@@ -83,7 +87,7 @@ final class PaymentApiV1Controller extends ApiController
"SELECT p.*, m.full_name_ar as member_name, m.membership_number "SELECT p.*, m.full_name_ar as member_name, m.membership_number
FROM payments p FROM payments p
LEFT JOIN members m ON m.id = p.member_id LEFT JOIN members m ON m.id = p.member_id
WHERE p.id = ? AND p.is_archived = 0", WHERE p.id = ?",
[(int) $id] [(int) $id]
); );
......
...@@ -100,7 +100,8 @@ final class EnrollmentController extends ApiController ...@@ -100,7 +100,8 @@ final class EnrollmentController extends ApiController
INNER JOIN training_groups tg ON tg.id = gm.group_id INNER JOIN training_groups tg ON tg.id = gm.group_id
LEFT JOIN coaches c ON c.id = tg.coach_id LEFT JOIN coaches c ON c.id = tg.coach_id
LEFT JOIN facilities f ON f.id = tg.facility_id LEFT JOIN facilities f ON f.id = tg.facility_id
LEFT JOIN sport_disciplines sd ON sd.id = tg.discipline_id LEFT JOIN academies acd ON acd.id = tg.academy_id
LEFT JOIN sport_disciplines sd ON sd.id = acd.discipline_id
WHERE gm.player_id = ? AND gm.status = 'active' WHERE gm.player_id = ? AND gm.status = 'active'
ORDER BY tg.day_of_week, tg.start_time", ORDER BY tg.day_of_week, tg.start_time",
[$player->id] [$player->id]
......
...@@ -29,7 +29,9 @@ final class AcademyRevenueReportService ...@@ -29,7 +29,9 @@ final class AcademyRevenueReportService
$academies = $db->select( $academies = $db->select(
"SELECT a.id, a.name_ar, a.code, "SELECT a.id, a.name_ar, a.code,
ac.minimum_guarantee, ac.revenue_share_percent, ac.start_date, ac.end_date ac.minimum_revenue_guarantee AS minimum_guarantee,
ac.academy_share_pct AS revenue_share_percent,
ac.start_date, ac.end_date
FROM academies a FROM academies a
LEFT JOIN academy_contracts ac ON ac.academy_id = a.id AND ac.status = 'active' LEFT JOIN academy_contracts ac ON ac.academy_id = a.id AND ac.status = 'active'
WHERE a.is_archived = 0{$academyFilter} WHERE a.is_archived = 0{$academyFilter}
...@@ -53,10 +55,10 @@ final class AcademyRevenueReportService ...@@ -53,10 +55,10 @@ final class AcademyRevenueReportService
$revenue = $db->selectOne( $revenue = $db->selectOne(
"SELECT COALESCE(SUM(p.amount), 0) AS total_revenue "SELECT COALESCE(SUM(p.amount), 0) AS total_revenue
FROM payments p FROM payments p
WHERE p.payable_type = 'academy' WHERE p.related_entity_type = 'academy'
AND p.payable_id = ? AND p.related_entity_id = ?
AND p.payment_date BETWEEN ? AND ? AND p.payment_date BETWEEN ? AND ?
AND p.status = 'completed'", AND p.is_voided = 0",
[$aId, $periodFrom, $periodTo] [$aId, $periodFrom, $periodTo]
); );
...@@ -75,10 +77,10 @@ final class AcademyRevenueReportService ...@@ -75,10 +77,10 @@ final class AcademyRevenueReportService
"SELECT DATE_FORMAT(p.payment_date, '%Y-%m') AS month, "SELECT DATE_FORMAT(p.payment_date, '%Y-%m') AS month,
COALESCE(SUM(p.amount), 0) AS revenue COALESCE(SUM(p.amount), 0) AS revenue
FROM payments p FROM payments p
WHERE p.payable_type = 'academy' WHERE p.related_entity_type = 'academy'
AND p.payable_id = ? AND p.related_entity_id = ?
AND p.payment_date BETWEEN ? AND ? AND p.payment_date BETWEEN ? AND ?
AND p.status = 'completed' AND p.is_voided = 0
GROUP BY DATE_FORMAT(p.payment_date, '%Y-%m') GROUP BY DATE_FORMAT(p.payment_date, '%Y-%m')
ORDER BY month ASC", ORDER BY month ASC",
[$aId, $periodFrom, $periodTo] [$aId, $periodFrom, $periodTo]
......
...@@ -65,8 +65,8 @@ final class CommissionService ...@@ -65,8 +65,8 @@ final class CommissionService
"SELECT sc.*, s.invoice_number "SELECT sc.*, s.invoice_number
FROM sales_commissions sc FROM sales_commissions sc
JOIN sales s ON s.id = sc.sale_id JOIN sales s ON s.id = sc.sale_id
WHERE sc.representative_id = ? AND sc.commission_date BETWEEN ? AND ? WHERE sc.representative_id = ? AND sc.period_month BETWEEN ? AND ?
ORDER BY sc.commission_date DESC", ORDER BY sc.period_month DESC",
[$repId, $fromDate, $toDate] [$repId, $fromDate, $toDate]
); );
......
...@@ -41,7 +41,7 @@ final class ScheduleConflictResolver ...@@ -41,7 +41,7 @@ final class ScheduleConflictResolver
if ($coachId !== null) { if ($coachId !== null) {
$coachConflict = $db->selectOne(" $coachConflict = $db->selectOne("
SELECT id FROM training_groups SELECT id FROM training_groups
WHERE coach_id = ? AND day_of_week = ? AND status = 'active' WHERE coach_id = ? AND day_of_week = ? AND is_active = 1
AND (start_time < ? AND end_time > ?) AND (start_time < ? AND end_time > ?)
", [$coachId, $dayOfWeek, $slotEnd, $slotStart]); ", [$coachId, $dayOfWeek, $slotEnd, $slotStart]);
...@@ -88,7 +88,7 @@ final class ScheduleConflictResolver ...@@ -88,7 +88,7 @@ final class ScheduleConflictResolver
} }
$enrolledCount = $db->selectOne( $enrolledCount = $db->selectOne(
"SELECT COUNT(*) AS cnt FROM group_memberships WHERE group_id = ? AND status = 'active'", "SELECT COUNT(*) AS cnt FROM group_memberships WHERE group_id = ? AND is_active = 1",
[$groupId] [$groupId]
)['cnt'] ?? 0; )['cnt'] ?? 0;
......
...@@ -51,10 +51,10 @@ class ServiceDeskController extends Controller ...@@ -51,10 +51,10 @@ class ServiceDeskController extends Controller
$carnet = null; $carnet = null;
if (!empty($result['member_id'])) { if (!empty($result['member_id'])) {
$carnet = $db->selectOne( $carnet = $db->selectOne(
"SELECT c.id, c.max_invitations, "SELECT c.id, c.total_invitations AS max_invitations,
(SELECT COUNT(*) FROM carnet_guest_entries cge WHERE cge.carnet_id = c.id AND cge.status != 'cancelled') as used_count (SELECT COUNT(*) FROM carnet_guest_entries cge WHERE cge.carnet_id = c.id AND cge.status != 'cancelled') as used_count
FROM carnets c FROM carnets c
WHERE c.member_id = ? AND c.status = 'active' WHERE c.member_id = ? AND c.is_active = 1
ORDER BY c.created_at DESC LIMIT 1", ORDER BY c.created_at DESC LIMIT 1",
[(int) $result['member_id']] [(int) $result['member_id']]
); );
......
...@@ -84,14 +84,16 @@ final class AttendanceRuleService ...@@ -84,14 +84,16 @@ final class AttendanceRuleService
$threshold = (int) ($thresholdRow['config_value'] ?? self::DEFAULT_ABSENCE_THRESHOLD); $threshold = (int) ($thresholdRow['config_value'] ?? self::DEFAULT_ABSENCE_THRESHOLD);
$absentees = $db->select( $absentees = $db->select(
"SELECT a.player_id, a.group_id, COUNT(*) as absence_count, // الحضور مربوط بالحجز، والمجموعة متسجّلة على الحجز مش على الحضور
"SELECT a.player_id, b.group_id, COUNT(*) as absence_count,
p.full_name_ar, p.phone, p.guardian_phone, g.name_ar as group_name p.full_name_ar, p.phone, p.guardian_phone, g.name_ar as group_name
FROM sa_attendance a FROM sa_attendance a
JOIN sa_bookings b ON b.id = a.booking_id
JOIN sa_players p ON p.id = a.player_id JOIN sa_players p ON p.id = a.player_id
JOIN sa_groups g ON g.id = a.group_id JOIN sa_groups g ON g.id = b.group_id
WHERE a.status = 'absent' WHERE a.status = 'absent'
AND a.attendance_date BETWEEN ? AND ? AND a.attendance_date BETWEEN ? AND ?
GROUP BY a.player_id, a.group_id, p.full_name_ar, p.phone, p.guardian_phone, g.name_ar GROUP BY a.player_id, b.group_id, p.full_name_ar, p.phone, p.guardian_phone, g.name_ar
HAVING COUNT(*) >= ?", HAVING COUNT(*) >= ?",
[$lastMonth, $lastMonthEnd, $threshold] [$lastMonth, $lastMonthEnd, $threshold]
); );
......
...@@ -139,12 +139,18 @@ final class DashboardMetricsService ...@@ -139,12 +139,18 @@ final class DashboardMetricsService
return $db->select(" return $db->select("
SELECT DISTINCT c.id, c.full_name_ar, c.full_name_en, SELECT DISTINCT c.id, c.full_name_ar, c.full_name_en,
(SELECT COUNT(*) FROM facility_zone_schedules fzs2 WHERE fzs2.coach_id = c.id AND fzs2.schedule_date BETWEEN ? AND ?) AS session_count (SELECT COUNT(*) FROM facility_zone_schedules fzs2
WHERE fzs2.coach_id = c.id
AND fzs2.effective_from <= ?
AND (fzs2.effective_to IS NULL OR fzs2.effective_to >= ?)) AS session_count
FROM coaches c FROM coaches c
INNER JOIN facility_zone_schedules fzs ON fzs.coach_id = c.id INNER JOIN facility_zone_schedules fzs ON fzs.coach_id = c.id
WHERE fzs.discipline_id = ? AND fzs.schedule_date BETWEEN ? AND ? INNER JOIN sport_disciplines d ON d.code = fzs.activity_type
WHERE d.id = ?
AND fzs.effective_from <= ?
AND (fzs.effective_to IS NULL OR fzs.effective_to >= ?)
ORDER BY session_count DESC ORDER BY session_count DESC
", [$start, $end, $disciplineId, $start, $end]); ", [$end, $start, $disciplineId, $end, $start]);
} }
public static function getPopularTimeSlots(int $facilityId, string $start, string $end): array public static function getPopularTimeSlots(int $facilityId, string $start, string $end): array
......
...@@ -49,10 +49,10 @@ final class CoachProfileController extends ApiController ...@@ -49,10 +49,10 @@ final class CoachProfileController extends ApiController
$db = App::getInstance()->db(); $db = App::getInstance()->db();
$assignments = $db->select( $assignments = $db->select(
"SELECT caa.id, caa.academy_id, caa.role, caa.assigned_at, "SELECT caa.id, caa.academy_id, caa.role, caa.assigned_from,
a.name_ar as academy_name, a.description_ar, a.name_ar as academy_name, a.description_ar,
ac.id as contract_id, ac.contract_type, ac.revenue_share_percent, ac.id as contract_id, ac.contract_type, ac.academy_share_pct,
ac.start_date, ac.end_date, ac.status as contract_status, ac.contract_image_path ac.start_date, ac.end_date, ac.status as contract_status, ac.contract_document_path
FROM coach_academy_assignments caa FROM coach_academy_assignments caa
INNER JOIN academies a ON a.id = caa.academy_id INNER JOIN academies a ON a.id = caa.academy_id
LEFT JOIN academy_contracts ac ON ac.academy_id = a.id AND ac.status = 'active' LEFT JOIN academy_contracts ac ON ac.academy_id = a.id AND ac.status = 'active'
......
...@@ -33,7 +33,8 @@ final class CoachScheduleController extends ApiController ...@@ -33,7 +33,8 @@ final class CoachScheduleController extends ApiController
FROM training_sessions ts FROM training_sessions ts
INNER JOIN training_groups tg ON tg.id = ts.group_id INNER JOIN training_groups tg ON tg.id = ts.group_id
LEFT JOIN facilities f ON f.id = ts.facility_id LEFT JOIN facilities f ON f.id = ts.facility_id
LEFT JOIN sport_disciplines sd ON sd.id = tg.discipline_id LEFT JOIN academies acd ON acd.id = tg.academy_id
LEFT JOIN sport_disciplines sd ON sd.id = acd.discipline_id
WHERE ts.coach_id = ? AND ts.session_date BETWEEN ? AND ? WHERE ts.coach_id = ? AND ts.session_date BETWEEN ? AND ?
ORDER BY ts.session_date, ts.start_time", ORDER BY ts.session_date, ts.start_time",
[$coach->id, $weekStart, $weekEnd] [$coach->id, $weekStart, $weekEnd]
...@@ -79,7 +80,8 @@ final class CoachScheduleController extends ApiController ...@@ -79,7 +80,8 @@ final class CoachScheduleController extends ApiController
al.name_ar as level_name al.name_ar as level_name
FROM training_groups tg FROM training_groups tg
LEFT JOIN facilities f ON f.id = tg.facility_id LEFT JOIN facilities f ON f.id = tg.facility_id
LEFT JOIN sport_disciplines sd ON sd.id = tg.discipline_id LEFT JOIN academies acd ON acd.id = tg.academy_id
LEFT JOIN sport_disciplines sd ON sd.id = acd.discipline_id
LEFT JOIN academy_levels al ON al.id = tg.level_id LEFT JOIN academy_levels al ON al.id = tg.level_id
WHERE tg.coach_id = ? AND tg.is_active = 1 AND tg.is_archived = 0 WHERE tg.coach_id = ? AND tg.is_active = 1 AND tg.is_archived = 0
ORDER BY tg.day_of_week, tg.start_time", ORDER BY tg.day_of_week, tg.start_time",
......
...@@ -39,7 +39,7 @@ SQL_KEYWORDS = { ...@@ -39,7 +39,7 @@ SQL_KEYWORDS = {
'asc', 'binary', 'collate', 'div', 'mod', 'xor', 'rlike', 'regexp', 'last_insert_id', 'asc', 'binary', 'collate', 'div', 'mod', 'xor', 'rlike', 'regexp', 'last_insert_id',
# وحدات الوقت اللي بتيجي بعد INTERVAL # وحدات الوقت اللي بتيجي بعد INTERVAL
'second', 'minute', 'hour', 'week', 'quarter', 'microsecond', 'dayofweek', 'second', 'minute', 'hour', 'week', 'quarter', 'microsecond', 'dayofweek',
'unsigned', 'signed', 'char', 'decimal', 'integer', 'separator', 'both', 'leading', 'trailing', 'lateral', 'unsigned', 'signed', 'char', 'decimal', 'integer', 'separator', 'both', 'leading', 'trailing',
} }
......
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