Files
tripz-llc/backend/fuel/functions.php
T
2026-08-09 16:56:13 +03:00

114 lines
4.6 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* fuel/functions.php — منطق محفظة الوقود المشترك
* ─────────────────────────────────────────────────────────────
* ‏محفظة الوقود منتج `drawdown` في محرك الالتزامات: لا دورة فوترة له،
* ‏والاستحقاق يُقيَّد لحظة الصرف من المحطة لا على جدول زمني.
*
* ‏كل ما يخصّ المال هنا يقتصر على **قيد الدَّين**. الخصم من رصيد السائق
* ‏يبقى حكراً على محرك التسوية، كما في التأمين.
*/
require_once __DIR__ . '/../obligations/functions.php';
const FUEL_PRODUCT_CODE = 'fuel_wallet';
const FUEL_VOUCHER_TTL_MIN = 45;
/**
* ‏التزام الوقود النشط للسائق، أو null.
*/
function fuelObligation(PDO $con, string $driverId): ?array
{
$st = $con->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('تعذّر توليد رمز قسيمة فريد');
}