Files
Siro/backend/driver_assurance/eligibility.php
T

111 lines
4.9 KiB
PHP

<?php
/**
* driver_assurance/eligibility.php — حساب أهلية السائق للتأمين
* ─────────────────────────────────────────────────────────────
* ‏قرار المالك: التأمين ليس خدمة تُمنح لكل من سجّل، بل مكافأة استمرار.
* ‏لا يستحقّه السائق إلا بعد عدد رحلات مكتملة وتقييم جيد.
*
* ‏المنطق التجاري خلفه: القسط كلفة متكررة تتحمّلها الشركة عن السائق أو
* ‏تخصمها من أرباحه. منحه لمن قد يختفي بعد أسبوع يحوّل الأداة من
* ‏ولاء إلى نزيف — والسائق الذي أتمّ مئتي رحلة بتقييم جيد أثبت أنه
* ‏باقٍ، وهو بالضبط من نريد قفله معنا.
*
* ‏الأرقام في جدول الخطط لا في هذا الملف: الشريك سيغيّرها، ومصر تختلف
* ‏عن الأردن، وتعديل صف أرخص من نشر إصدار.
*/
/**
* ‏يقيس السائق مقابل شروط خطة.
*
* @return array{
* eligible: bool,
* rides: int, rating: float, account_days: int,
* reasons: string[]
* }
*/
function assuranceCheckEligibility(PDO $con, string $driverId, array $plan): array
{
$rides = 0;
$rating = 0.0;
$days = 0;
try {
// ‏الرحلات المكتملة فقط. الحالة مكتوبة بحرفين مختلفين في
// ‏الجدول تاريخياً ('Finished' و'finished')، وإغفال أحدهما
// ‏يُنقص عدّاد السائق إلى النصف تقريباً.
$st = $con->prepare("
SELECT COUNT(*) FROM ride
WHERE driver_id = ? AND status IN ('Finished', 'finished')
");
$st->execute([$driverId]);
$rides = (int) $st->fetchColumn();
$st = $con->prepare("SELECT AVG(rating) FROM ratingDriver WHERE driver_id = ?");
$st->execute([$driverId]);
$avg = $st->fetchColumn();
// ‏سائق بلا تقييمات ليس سيئاً — لكنه أيضاً غير مثبَت. عدد
// ‏الرحلات المطلوب يضمن أن تقييماته وصلت على أي حال.
$rating = $avg === null || $avg === false ? 0.0 : round((float) $avg, 2);
$st = $con->prepare("SELECT DATEDIFF(NOW(), created_at) FROM driver WHERE id = ? LIMIT 1");
$st->execute([$driverId]);
$d = $st->fetchColumn();
$days = ($d === false || $d === null) ? 0 : (int) $d;
} catch (PDOException $e) {
error_log('[assurance] تعذّر حساب الأهلية: ' . $e->getMessage());
return [
'eligible' => false, 'rides' => 0, 'rating' => 0.0, 'account_days' => 0,
'reasons' => ['تعذّر التحقق حالياً'],
];
}
$minRides = (int) ($plan['min_completed_rides'] ?? 200);
$minRating = (float) ($plan['min_rating'] ?? 4.50);
$minDays = (int) ($plan['min_account_days'] ?? 30);
// ‏نجمع كل الأسباب لا أوّلها: السائق يستحق أن يعرف كل ما ينقصه
// ‏دفعةً واحدة، لا أن يعالج شرطاً فيُفاجأ بالتالي.
$reasons = [];
if ($rides < $minRides) {
$reasons[] = "أكمل $minRides رحلة (لديك $rides)";
}
if ($rating < $minRating) {
$reasons[] = "تقييمك يجب ألّا يقل عن $minRating (تقييمك " . ($rating ?: '—') . ')';
}
if ($days < $minDays) {
$reasons[] = "مضيّ $minDays يوماً على حسابك (مضى $days)";
}
return [
'eligible' => empty($reasons),
'rides' => $rides,
'rating' => $rating,
'account_days' => $days,
'reasons' => $reasons,
];
}
/**
* ‏الوثيقة النشطة للسائق مع بيانات خطتها، أو null.
*/
function assuranceActivePolicy(PDO $con, string $driverId): ?array
{
try {
$st = $con->prepare("
SELECT p.*, pl.code, pl.name_ar AS plan_name, pl.premium, pl.currency,
pl.billing_cycle, pl.coverage_summary,
pr.name AS provider_name, pr.name_ar AS provider_name_ar
FROM driver_insurance_policies p
JOIN insurance_plans pl ON pl.id = p.plan_id
JOIN insurance_providers pr ON pr.id = pl.provider_id
WHERE p.driver_id = ? AND p.status = 'active'
ORDER BY p.id DESC LIMIT 1
");
$st->execute([$driverId]);
return $st->fetch(PDO::FETCH_ASSOC) ?: null;
} catch (PDOException $e) {
error_log('[assurance] تعذّر جلب الوثيقة: ' . $e->getMessage());
return null;
}
}