beginTransaction(); // ‏الشرط على driver_id إلى جانب المعرّف: الوثيقة أتت من استعلام // ‏مقيَّد بالسائق أصلاً، لكن الشرط هنا يجعل الاستعلام آمناً بذاته // ‏لو أعيد استعماله يوماً في سياق آخر. $st = $con->prepare(" UPDATE driver_insurance_policies SET status = 'cancelled', ended_at = CURDATE(), cancel_reason = ? WHERE id = ? AND driver_id = ? AND status = 'active' "); $st->execute([mb_substr($reason, 0, 255), $policy['id'], $driverId]); if ($st->rowCount() === 0) { $con->rollBack(); jsonError('تعذّر إلغاء الوثيقة'); } obligationClose($con, $driverId, $policy['code'], $reason); $con->commit(); } catch (Throwable $e) { if ($con->inTransaction()) $con->rollBack(); error_log('[assurance/cancel] ' . $e->getMessage()); jsonError('Server error'); } // ‏المستحق يُقرأ من الدفتر الموحّد لا من دفتر التأمين القديم: القديم // ‏مجمَّد بعد الترحيل، وقراءته تعني رقماً لا يتغيّر مهما سدّد السائق. $pending = obligationPendingTotal($con, $driverId, $policy['code']); error_log("[assurance] أُلغيت وثيقة #{$policy['id']} للسائق $driverId"); jsonSuccess([ 'cancelled' => true, 'pending_balance' => $pending, 'currency' => $policy['currency'], ], $pending > 0 ? 'أُلغيت الوثيقة. يبقى عليك مستحق أقساط سابقة قدره ' . $pending . ' ' . $policy['currency'] : 'أُلغيت الوثيقة');