feat(phase-1): complete backend core, savings ledger, multi-channel auth, and dynamic QR verification

This commit is contained in:
Hamza-Ayed
2026-09-18 17:54:37 +03:00
parent 4fe451ab5e
commit e044123c9b
8 changed files with 295 additions and 30 deletions
+50
View File
@@ -210,5 +210,55 @@ CREATE TABLE IF NOT EXISTS `gateway_tasks` (
INDEX `idx_assigned_device` (`assigned_device_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 12. جدول محفظة التوفير المالي التراكمي للمشترك (Member Savings Ledger)
CREATE TABLE IF NOT EXISTS `savings_ledger` (
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`subscription_id` BIGINT UNSIGNED NOT NULL,
`user_id` BIGINT UNSIGNED NOT NULL,
`partner_id` BIGINT UNSIGNED NOT NULL,
`service_name` VARCHAR(191) NOT NULL COMMENT 'e.g. تحاليل وفحوصات شاملة، إقامة فندقية ليلتين، دورة تدريبية',
`original_amount` DECIMAL(14, 2) NOT NULL COMMENT 'Original bill before discount in IQD',
`discount_percentage` DECIMAL(5, 2) NOT NULL COMMENT 'e.g. 25.00',
`saved_amount` DECIMAL(14, 2) NOT NULL COMMENT 'Actual cash saved by member in IQD',
`paid_amount` DECIMAL(14, 2) NOT NULL COMMENT 'Amount actually paid by member in IQD',
`currency` VARCHAR(8) NOT NULL DEFAULT 'IQD',
`verified_by_staff` VARCHAR(128) NULL,
`notes` TEXT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT `fk_savings_sub` FOREIGN KEY (`subscription_id`) REFERENCES `subscriptions` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_savings_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_savings_partner` FOREIGN KEY (`partner_id`) REFERENCES `partners` (`id`) ON DELETE CASCADE,
INDEX `idx_savings_user` (`user_id`),
INDEX `idx_savings_sub` (`subscription_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 13. جدول إرساليات المصادقة وتتبع القنوات (OTP Dispatches & Multi-Channel Routing)
CREATE TABLE IF NOT EXISTS `otp_dispatches` (
`id` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`phone` VARCHAR(32) NOT NULL,
`user_id` BIGINT UNSIGNED NULL,
`channel` ENUM('SILENT_CALL', 'TELEGRAM', 'WHATSAPP_CAPTCHA', 'SMS_OTPIQ') NOT NULL,
`otp_code_hash` VARCHAR(64) NOT NULL,
`status` ENUM('QUEUED', 'DISPATCHED', 'DELIVERED', 'VERIFIED', 'EXPIRED', 'FAILED') NOT NULL DEFAULT 'QUEUED',
`gateway_device_id` VARCHAR(64) NULL,
`provider_message_id` VARCHAR(128) NULL,
`cost_iqd` DECIMAL(8, 2) NOT NULL DEFAULT 0.00,
`expires_at` TIMESTAMP NOT NULL,
`verified_at` TIMESTAMP NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_otp_phone_status` (`phone`, `status`),
INDEX `idx_otp_expires` (`expires_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 14. بيانات أولية للشركاء المعتمدين في العراق (Seed Partners)
INSERT INTO `partners` (`id`, `type`, `name_ar`, `name_en`, `category`, `country`, `city`, `discount_percentage`, `address`, `phone`, `is_active`) VALUES
(1, 'HOSPITAL', 'مستشفى الكفيل التخصصي', 'Al-Kafeel Super Speciality Hospital', 'مستشفى جراحي وتخصصي متقدم', 'Iraq', 'كربلاء المقدسة', 25.00, 'طريق كربلاء - النجف', '+9647801234001', 1),
(2, 'HOSPITAL', 'مستشفى الفاروق التخصصي', 'Al-Farouk Hospital', 'جراحة عامة وباطنية ومختبرات', 'Iraq', 'بغداد', 30.00, 'المنصور - شارع 14 رمضان', '+9647801234002', 1),
(3, 'HOTEL', 'فندق بابل روتانا', 'Babylon Rotana Hotel', 'فندق 5 نجوم وضيافة فاخرة', 'Iraq', 'بغداد', 30.00, 'الجادرية - شارع الكرادة', '+9647801234003', 1),
(4, 'HOTEL', 'فندق أربيل الدولي', 'Erbil International Hotel', 'فندق 5 نجوم ومركز مؤتمرات', 'Iraq', 'أربيل', 35.00, 'شارع 30 متري - قرب القلعة', '+9647801234004', 1),
(5, 'TRAINING_CENTER', 'أكاديمية أوروك الدولية للتدريب والتطوير', 'Uruk International Training Academy', 'إدارة وقيادة وتقنيات حديثة', 'Iraq', 'بغداد', 50.00, 'العرصات - مجمع أوروك الأكاديمي', '+9647801234005', 1)
ON DUPLICATE KEY UPDATE `name_ar` = VALUES(`name_ar`);
SET FOREIGN_KEY_CHECKS = 1;