prepare(" SELECT o.*, p.currency, p.daily_cap_percent FROM driver_obligations o JOIN obligation_products p ON p.id = o.product_id WHERE o.driver_id = ? AND p.code = ? AND o.status = 'active' LIMIT 1 "); $st->execute([$driverId, FUEL_PRODUCT_CODE]); return $st->fetch(PDO::FETCH_ASSOC) ?: null; } /** * ‏يُنهي صلاحية القسائم التي مضى وقتها. * * ‏يُستدعى قبل أي حساب سقف لا في كرون: القسيمة المنتهية تحجز من سقف * ‏السائق، وتأخير تحريرها ساعةً كاملةً حتى يمرّ الكرون يعني منعه من * ‏التزوّد بسبب قسيمة ماتت. التنظيف عند القراءة يجعل الرقم صادقاً دائماً. */ function fuelExpireStaleVouchers(PDO $con, string $driverId): void { $con->prepare(" UPDATE fuel_vouchers SET status = 'expired' WHERE driver_id = ? AND status = 'issued' AND expires_at < NOW() ")->execute([$driverId]); } /** * ‏حالة سقف السائق: المستخدَم، المحجوز، والمتاح. * * ‏المحجوز يُطرح كالمستخدَم تماماً: قسيمة أُصدرت ولم تُصرف بعد قد تُصرف * ‏بعد لحظة، والسماح بإصدار قسائم بمجموع يتجاوز السقف يعني سائقاً * ‏يتزوّد بضعف ما يستحق ثم لا نجد ما نخصم منه. * * @return array{limit: float, outstanding: float, held: float, available: float} */ function fuelCreditState(PDO $con, array $obligation): array { $obligationId = (int) $obligation['id']; $st = $con->prepare(" SELECT COALESCE(SUM(amount_remaining), 0) FROM obligation_ledger WHERE obligation_id = ? AND status IN ('pending', 'partial') "); $st->execute([$obligationId]); $outstanding = (float) $st->fetchColumn(); $st = $con->prepare(" SELECT COALESCE(SUM(amount_authorized), 0) FROM fuel_vouchers WHERE obligation_id = ? AND status = 'issued' AND expires_at >= NOW() "); $st->execute([$obligationId]); $held = (float) $st->fetchColumn(); $limit = (float) $obligation['credit_limit']; $available = round($limit - $outstanding - $held, 3); return [ 'limit' => $limit, 'outstanding' => round($outstanding, 3), 'held' => round($held, 3), 'available' => max($available, 0.0), ]; } /** * ‏يولّد رمز قسيمة غير متوقَّع. * * ‏`random_int` لا `rand`: الرمز مفتاحُ صرفٍ فعلي، ومولّد عشوائية قابل * ‏للتنبّؤ يعني أن من يعرف رمزاً واحداً قد يخمّن التالي ويتزوّد على * ‏حساب سائق آخر. عشرة أرقام تُبقي المجال واسعاً والرقم قابلاً للإملاء * ‏على عامل المحطة هاتفياً. */ function fuelGenerateCode(PDO $con): string { for ($i = 0; $i < 10; $i++) { $code = (string) random_int(1000000000, 9999999999); $st = $con->prepare("SELECT 1 FROM fuel_vouchers WHERE code = ? LIMIT 1"); $st->execute([$code]); if (!$st->fetchColumn()) { return $code; } } // ‏عشر محاولات فاشلة على مجال من تسعة مليارات ليست صدفة — هي عطل // ‏(قاعدة ممتلئة أو مولّد معطوب). الاستمرار هنا يعني رمزاً مكرّراً. throw new RuntimeException('تعذّر توليد رمز قسيمة فريد'); }