Files
Siro/backend/migrations/2026_08_07_driver_insurance.sql
T

117 lines
7.4 KiB
SQL
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.
-- ============================================================
-- التأمين للسائق — بند 3.5 من دراسة الفرص
--
-- ‏ما كان موجوداً قبل هذا: جدول `driver_health_assurance` فيه بوليان
-- ‏`assured` واسم شركة نصّاً، وملف add.php وحيد بلا حارس مصادقة —
-- ‏و get.php و update.php **فارغان تماماً** (صفر بايت). أي أن الفكرة
-- ‏لم "تبدأ وتتوقف" كما تقول الدراسة، بل لم تبدأ.
--
-- ‏قرار المالك: شريك مرخّص (ميتلايف وآخر في مصر)، قسط يومي أو شهري
-- ‏يُخصم من أرباح السائق، وأهلية مشروطة بعدد رحلات وتقييم — التأمين
-- ‏مكافأة استمرار لا خدمة تُمنح لكل من سجّل.
--
-- ‏لا نلمس driver_health_assurance: يبقى كما هو لمن سُجّل فيه سابقاً،
-- ‏والجداول هنا هي المسار الجديد.
-- ============================================================
-- ── ١) شركات التأمين ────────────────────────────────────────
CREATE TABLE IF NOT EXISTS `insurance_providers` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(120) NOT NULL COMMENT 'MetLife وغيرها',
`name_ar` VARCHAR(120) DEFAULT NULL,
`country` VARCHAR(60) NOT NULL DEFAULT 'Egypt',
`contact` VARCHAR(255) DEFAULT NULL,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_country_active` (`country`, `is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ── ٢) الخطط ────────────────────────────────────────────────
-- ‏شروط الأهلية تُخزَّن مع الخطة لا في الكود: الشريك سيغيّرها، والسوق
-- ‏المصري يختلف عن الأردني، وتغيير رقم في صف أرخص من نشر إصدار.
CREATE TABLE IF NOT EXISTS `insurance_plans` (
`id` INT NOT NULL AUTO_INCREMENT,
`provider_id` INT NOT NULL,
`code` VARCHAR(60) NOT NULL COMMENT 'معرّف ثابت يُستعمل في الكود',
`name_ar` VARCHAR(160) NOT NULL,
`description_ar` TEXT DEFAULT NULL,
`billing_cycle` ENUM('daily','monthly') NOT NULL DEFAULT 'daily',
`premium` DECIMAL(10,3) NOT NULL COMMENT 'قسط الدورة الواحدة',
`currency` VARCHAR(10) NOT NULL DEFAULT 'EGP',
`coverage_summary` TEXT DEFAULT NULL,
-- ── شروط الأهلية ──
-- ‏قرار المالك: لا تأمين قبل ~٢٠٠ رحلة بتقييم جيد. المنطق سليم —
-- ‏التأمين كلفة متكررة على الشركة، ومنحه لمن قد يختفي بعد أسبوع
-- ‏يحوّله من أداة ولاء إلى نزيف.
`min_completed_rides` INT NOT NULL DEFAULT 200,
`min_rating` DECIMAL(3,2) NOT NULL DEFAULT 4.50,
`min_account_days` INT NOT NULL DEFAULT 30,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_code` (`code`),
KEY `idx_provider_active` (`provider_id`, `is_active`),
CONSTRAINT `fk_plan_provider` FOREIGN KEY (`provider_id`)
REFERENCES `insurance_providers` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ── ٣) وثائق السائقين ───────────────────────────────────────
CREATE TABLE IF NOT EXISTS `driver_insurance_policies` (
`id` INT NOT NULL AUTO_INCREMENT,
`driver_id` VARCHAR(100) NOT NULL,
`plan_id` INT NOT NULL,
`policy_number` VARCHAR(120) DEFAULT NULL COMMENT 'رقم الوثيقة من الشريك',
`status` ENUM('active','suspended','cancelled','expired')
NOT NULL DEFAULT 'active',
`started_at` DATE NOT NULL,
`ended_at` DATE DEFAULT NULL,
-- ‏لقطة الأهلية لحظة الاشتراك. بدونها لا يمكن الإجابة لاحقاً على
-- ‏«لماذا قُبل هذا السائق؟» حين تتغيّر شروط الخطة أو ينخفض تقييمه.
`rides_at_signup` INT NOT NULL DEFAULT 0,
`rating_at_signup` DECIMAL(3,2) NOT NULL DEFAULT 0,
-- ‏آخر يوم حُسب عنه قسط. هذا العمود — لا التاريخ الحالي — هو ما
-- ‏يمنع الاحتساب المزدوج لو عمل الكرون مرتين في اليوم نفسه.
`last_charged_on` DATE DEFAULT NULL,
`cancel_reason` VARCHAR(255) DEFAULT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
-- ‏وثيقة واحدة نشطة لكل سائق. المفتاح الفريد على (driver_id, status)
-- ‏لا يصلح — يمنع وثيقتين ملغيتين. نمنعه في الكود ونكشفه بفهرس.
KEY `idx_driver_status` (`driver_id`, `status`),
KEY `idx_charge_sweep` (`status`, `last_charged_on`),
CONSTRAINT `fk_policy_plan` FOREIGN KEY (`plan_id`)
REFERENCES `insurance_plans` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ── ٤) دفتر الأقساط ─────────────────────────────────────────
-- ‏دفتر لا خصم مباشر. رصيد السائق يعيش في payment_server لا هنا،
-- ‏فالكرون يقيّد استحقاقاً والتسوية تقرأه. الفصل مقصود أيضاً لسبب
-- ‏محاسبي: القيد سجلّ دائم قابل للمراجعة، بينما الخصم المباشر يترك
-- ‏رقماً متغيّراً بلا أثر يشرح كيف صار كذلك.
CREATE TABLE IF NOT EXISTS `insurance_premium_ledger` (
`id` INT NOT NULL AUTO_INCREMENT,
`policy_id` INT NOT NULL,
`driver_id` VARCHAR(100) NOT NULL,
`charge_date` DATE NOT NULL COMMENT 'اليوم أو أول الشهر المحتسَب',
`amount` DECIMAL(10,3) NOT NULL,
`currency` VARCHAR(10) NOT NULL DEFAULT 'EGP',
`status` ENUM('pending','settled','waived','failed')
NOT NULL DEFAULT 'pending',
`settled_at` DATETIME DEFAULT NULL,
`note` VARCHAR(255) DEFAULT NULL,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
-- ‏الحارس الحقيقي ضد الاحتساب المزدوج: قسط واحد لكل وثيقة في اليوم
-- ‏الواحد مهما تكرّر تشغيل الكرون أو تزامنت نسختان منه.
UNIQUE KEY `uq_policy_date` (`policy_id`, `charge_date`),
KEY `idx_driver_status` (`driver_id`, `status`),
CONSTRAINT `fk_ledger_policy` FOREIGN KEY (`policy_id`)
REFERENCES `driver_insurance_policies` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;