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
// Revenue generated (from payments linked to sessions)
$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
WHERE cp.coach_id = ? AND cp.period_month = ?",
WHERE cp.coach_id = ? AND cp.payment_period = ?",
[$coachId, $month]
);
$revenueGenerated = (string) ($revenue['total_revenue'] ?? '0.00');
......
......@@ -76,7 +76,7 @@ class AccessControlService
if (!$memberId) return false;
$db = App::getInstance()->db();
$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]
);
return $member !== null && $member !== false;
......
......@@ -32,9 +32,8 @@ final class FacilityAttendanceController extends Controller
$coaches = $db->select(
"SELECT DISTINCT fzs.coach_id, c.full_name_ar
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
WHERE fgz.grid_id = ? AND fzs.is_active = 1",
WHERE fzs.grid_id = ? AND fzs.is_active = 1",
[(int) $gridId]
);
......@@ -43,7 +42,7 @@ final class FacilityAttendanceController extends Controller
FROM facility_zone_trainees fzt
INNER JOIN facility_grid_zones fgz ON fgz.id = fzt.zone_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]
);
......
......@@ -103,7 +103,7 @@ final class FacilityAttendanceService
FROM facility_zone_trainees fzt
INNER JOIN facility_grid_zones fgz ON fgz.id = fzt.zone_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]
);
......
......@@ -132,7 +132,7 @@ final class AttendanceViolationService
if ($dayOfWeek === 5) return [];
$isHoliday = $db->selectOne(
"SELECT id FROM hr_holidays WHERE holiday_date = ?",
"SELECT id FROM hr_holidays WHERE `date` = ?",
[$date]
);
if ($isHoliday) return [];
......
......@@ -67,11 +67,12 @@ final class AssetCustodyService
return $db->select(
"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
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 eb ON eb.id = ach.transferred_by
LEFT JOIN employees eb ON eb.id = ach.created_by
WHERE ach.asset_id = ?
ORDER BY ach.transfer_date DESC, ach.id DESC",
[$assetId]
......@@ -87,7 +88,7 @@ final class AssetCustodyService
FROM asset_register ar
LEFT JOIN asset_categories ac ON ac.id = ar.category_id
WHERE ar.custodian_employee_id = ?
ORDER BY ar.asset_name_ar",
ORDER BY ar.asset_name",
[$employeeId]
);
}
......
......@@ -1101,7 +1101,11 @@ final class MembershipRulesService
if (!$firstYearCovered) {
$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]
);
......
......@@ -127,7 +127,7 @@ final class CronNotificationService
JOIN players p ON p.id = asub.player_id
JOIN sport_disciplines a ON a.id = asub.discipline_id
WHERE asub.status = 'active'
AND asub.next_payment_date = ?
AND asub.due_date = ?
AND p.is_archived = 0
", [$targetDate]);
......
......@@ -63,8 +63,12 @@ final class PaymentApiV1Controller extends ApiController
$offset = ($page - 1) * $perPage;
$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
LEFT JOIN receipts r ON r.id = p.receipt_id
WHERE {$whereSql}
ORDER BY p.id DESC
LIMIT {$perPage} OFFSET {$offset}",
......@@ -83,7 +87,7 @@ final class PaymentApiV1Controller extends ApiController
"SELECT p.*, m.full_name_ar as member_name, m.membership_number
FROM payments p
LEFT JOIN members m ON m.id = p.member_id
WHERE p.id = ? AND p.is_archived = 0",
WHERE p.id = ?",
[(int) $id]
);
......
......@@ -100,7 +100,8 @@ final class EnrollmentController extends ApiController
INNER JOIN training_groups tg ON tg.id = gm.group_id
LEFT JOIN coaches c ON c.id = tg.coach_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'
ORDER BY tg.day_of_week, tg.start_time",
[$player->id]
......
......@@ -29,7 +29,9 @@ final class AcademyRevenueReportService
$academies = $db->select(
"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
LEFT JOIN academy_contracts ac ON ac.academy_id = a.id AND ac.status = 'active'
WHERE a.is_archived = 0{$academyFilter}
......@@ -53,10 +55,10 @@ final class AcademyRevenueReportService
$revenue = $db->selectOne(
"SELECT COALESCE(SUM(p.amount), 0) AS total_revenue
FROM payments p
WHERE p.payable_type = 'academy'
AND p.payable_id = ?
WHERE p.related_entity_type = 'academy'
AND p.related_entity_id = ?
AND p.payment_date BETWEEN ? AND ?
AND p.status = 'completed'",
AND p.is_voided = 0",
[$aId, $periodFrom, $periodTo]
);
......@@ -75,10 +77,10 @@ final class AcademyRevenueReportService
"SELECT DATE_FORMAT(p.payment_date, '%Y-%m') AS month,
COALESCE(SUM(p.amount), 0) AS revenue
FROM payments p
WHERE p.payable_type = 'academy'
AND p.payable_id = ?
WHERE p.related_entity_type = 'academy'
AND p.related_entity_id = ?
AND p.payment_date BETWEEN ? AND ?
AND p.status = 'completed'
AND p.is_voided = 0
GROUP BY DATE_FORMAT(p.payment_date, '%Y-%m')
ORDER BY month ASC",
[$aId, $periodFrom, $periodTo]
......
......@@ -65,8 +65,8 @@ final class CommissionService
"SELECT sc.*, s.invoice_number
FROM sales_commissions sc
JOIN sales s ON s.id = sc.sale_id
WHERE sc.representative_id = ? AND sc.commission_date BETWEEN ? AND ?
ORDER BY sc.commission_date DESC",
WHERE sc.representative_id = ? AND sc.period_month BETWEEN ? AND ?
ORDER BY sc.period_month DESC",
[$repId, $fromDate, $toDate]
);
......
......@@ -41,7 +41,7 @@ final class ScheduleConflictResolver
if ($coachId !== null) {
$coachConflict = $db->selectOne("
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 > ?)
", [$coachId, $dayOfWeek, $slotEnd, $slotStart]);
......@@ -88,7 +88,7 @@ final class ScheduleConflictResolver
}
$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]
)['cnt'] ?? 0;
......
......@@ -51,10 +51,10 @@ class ServiceDeskController extends Controller
$carnet = null;
if (!empty($result['member_id'])) {
$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
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",
[(int) $result['member_id']]
);
......
......@@ -84,14 +84,16 @@ final class AttendanceRuleService
$threshold = (int) ($thresholdRow['config_value'] ?? self::DEFAULT_ABSENCE_THRESHOLD);
$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
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_groups g ON g.id = a.group_id
JOIN sa_groups g ON g.id = b.group_id
WHERE a.status = 'absent'
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(*) >= ?",
[$lastMonth, $lastMonthEnd, $threshold]
);
......
......@@ -139,12 +139,18 @@ final class DashboardMetricsService
return $db->select("
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
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
", [$start, $end, $disciplineId, $start, $end]);
", [$end, $start, $disciplineId, $end, $start]);
}
public static function getPopularTimeSlots(int $facilityId, string $start, string $end): array
......
......@@ -49,10 +49,10 @@ final class CoachProfileController extends ApiController
$db = App::getInstance()->db();
$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,
ac.id as contract_id, ac.contract_type, ac.revenue_share_percent,
ac.start_date, ac.end_date, ac.status as contract_status, ac.contract_image_path
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_document_path
FROM coach_academy_assignments caa
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'
......
......@@ -33,7 +33,8 @@ final class CoachScheduleController extends ApiController
FROM training_sessions ts
INNER JOIN training_groups tg ON tg.id = ts.group_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 ?
ORDER BY ts.session_date, ts.start_time",
[$coach->id, $weekStart, $weekEnd]
......@@ -79,7 +80,8 @@ final class CoachScheduleController extends ApiController
al.name_ar as level_name
FROM training_groups tg
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
WHERE tg.coach_id = ? AND tg.is_active = 1 AND tg.is_archived = 0
ORDER BY tg.day_of_week, tg.start_time",
......
......@@ -39,7 +39,7 @@ SQL_KEYWORDS = {
'asc', 'binary', 'collate', 'div', 'mod', 'xor', 'rlike', 'regexp', 'last_insert_id',
# وحدات الوقت اللي بتيجي بعد INTERVAL
'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