getMessage() . "\n"); exit(1); } $today = date('Y-m-d'); // ‏الشهري يُقيَّد على أول الشهر لا على يوم الاشتراك: دفتر تتوزّع فيه // ‏تواريخ القيد على ثلاثين يوماً يستحيل تسويته مع الشريك. $monthStart = date('Y-m-01'); $charged = 0; $skipped = 0; try { $st = $con->query(" SELECT p.id, p.driver_id, p.last_charged_on, pl.premium, pl.currency, pl.billing_cycle FROM driver_insurance_policies p JOIN insurance_plans pl ON pl.id = p.plan_id WHERE p.status = 'active' ORDER BY p.id ASC "); foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $policy) { $chargeDate = $policy['billing_cycle'] === 'monthly' ? $monthStart : $today; // ‏الفلترة الرخيصة أولاً — تجنّبنا محاولة إدراج لكل وثيقة كل يوم. if ($policy['last_charged_on'] === $chargeDate) { $skipped++; continue; } try { $con->beginTransaction(); $con->prepare(" INSERT INTO insurance_premium_ledger (policy_id, driver_id, charge_date, amount, currency, status) VALUES (?, ?, ?, ?, ?, 'pending') ")->execute([ $policy['id'], $policy['driver_id'], $chargeDate, $policy['premium'], $policy['currency'], ]); $con->prepare(" UPDATE driver_insurance_policies SET last_charged_on = ? WHERE id = ? ")->execute([$chargeDate, $policy['id']]); $con->commit(); $charged++; } catch (PDOException $e) { if ($con->inTransaction()) $con->rollBack(); // ‏23000 = خرق المفتاح الفريد: نسخة أخرى سبقتنا للقيد نفسه. // ‏هذه ليست حالة خطأ — هي بالضبط ما صُمّم المفتاح لمنعه. if ($e->getCode() === '23000') { $con->prepare(" UPDATE driver_insurance_policies SET last_charged_on = ? WHERE id = ? ")->execute([$chargeDate, $policy['id']]); $skipped++; } else { error_log("[insurance] تعذّر قيد قسط الوثيقة #{$policy['id']}: " . $e->getMessage()); } } } } catch (PDOException $e) { fwrite(STDERR, '[insurance] فشل المرور: ' . $e->getMessage() . "\n"); exit(1); } echo "[insurance] قُيِّد {$charged} قسطاً، تُخطّي {$skipped}\n";