290 lines
16 KiB
SQL
290 lines
16 KiB
SQL
-- =============================================================
|
||
-- schema_food.sql — قاعدة بيانات وحدة طلبات الطعام (siro_food)
|
||
-- عزل كامل عن main/ride/transit — ممنوع أي JOIN خارجي
|
||
-- الربط بالنظام الرئيسي عبر passenger_id / courier_id (main driver id) فقط
|
||
-- =============================================================
|
||
|
||
SET FOREIGN_KEY_CHECKS = 0;
|
||
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
|
||
SET time_zone = "+00:00";
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 1. food_merchants — المطاعم/المتاجر
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_merchants` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`name_ar` VARCHAR(150) NOT NULL,
|
||
`name_en` VARCHAR(150) DEFAULT NULL,
|
||
`logo_url` VARCHAR(500) DEFAULT NULL,
|
||
`cover_url` VARCHAR(500) DEFAULT NULL,
|
||
`description_ar` VARCHAR(500) DEFAULT NULL,
|
||
`city` VARCHAR(80) NOT NULL,
|
||
`address` VARCHAR(300) DEFAULT NULL,
|
||
`latitude` DECIMAL(10,7) NOT NULL,
|
||
`longitude` DECIMAL(10,7) NOT NULL,
|
||
`category` VARCHAR(60) DEFAULT NULL COMMENT 'مطبخ عربي، بيتزا، حلويات...',
|
||
`commission_percent` DECIMAL(5,2) NOT NULL DEFAULT 15.00,
|
||
`min_order_amount` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'أصغر وحدة نقدية',
|
||
`avg_prep_minutes` SMALLINT UNSIGNED NOT NULL DEFAULT 20,
|
||
`rating_avg` DECIMAL(3,2) NOT NULL DEFAULT 0.00,
|
||
`rating_count` INT UNSIGNED NOT NULL DEFAULT 0,
|
||
`status` ENUM('pending_approval','active','paused','suspended','rejected') NOT NULL DEFAULT 'pending_approval',
|
||
`is_open_override` TINYINT(1) DEFAULT NULL COMMENT 'NULL=يتبع working_hours، 0/1=إغلاق/فتح يدوي فوري',
|
||
`working_hours` JSON DEFAULT NULL COMMENT '{"sun":[["09:00","23:00"]], ...}',
|
||
`approved_by` INT UNSIGNED DEFAULT NULL COMMENT 'admin id من النظام الرئيسي',
|
||
`approved_at` TIMESTAMP 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`),
|
||
KEY `idx_city_status` (`city`, `status`),
|
||
KEY `idx_location` (`latitude`, `longitude`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 2. food_merchant_users — حسابات دخول أصحاب المطاعم (دور merchant، هوية منفصلة عن الراكب)
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_merchant_users` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`merchant_id` INT UNSIGNED NOT NULL,
|
||
`name` VARCHAR(120) NOT NULL,
|
||
`phone` VARCHAR(25) NOT NULL COMMENT 'مشفّر بنفس EncryptionHelper',
|
||
`role` ENUM('owner','staff') NOT NULL DEFAULT 'owner',
|
||
`password_hash` VARCHAR(255) NOT NULL,
|
||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (`id`),
|
||
UNIQUE KEY `uq_phone` (`phone`),
|
||
KEY `idx_merchant` (`merchant_id`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 3. food_menu_categories — أقسام قائمة المطعم
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_menu_categories` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`merchant_id` INT UNSIGNED NOT NULL,
|
||
`name_ar` VARCHAR(100) NOT NULL,
|
||
`name_en` VARCHAR(100) DEFAULT NULL,
|
||
`sort_order` SMALLINT NOT NULL DEFAULT 0,
|
||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_merchant_sort` (`merchant_id`, `sort_order`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 4. food_menu_items — أصناف القائمة
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_menu_items` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`merchant_id` INT UNSIGNED NOT NULL,
|
||
`category_id` INT UNSIGNED NOT NULL,
|
||
`name_ar` VARCHAR(150) NOT NULL,
|
||
`name_en` VARCHAR(150) DEFAULT NULL,
|
||
`description_ar` VARCHAR(500) DEFAULT NULL,
|
||
`image_url` VARCHAR(500) DEFAULT NULL,
|
||
`price` BIGINT UNSIGNED NOT NULL COMMENT 'أصغر وحدة نقدية',
|
||
`is_available` TINYINT(1) NOT NULL DEFAULT 1,
|
||
`prep_minutes` SMALLINT UNSIGNED DEFAULT NULL COMMENT 'NULL = يستخدم avg_prep_minutes للمطعم',
|
||
`sort_order` SMALLINT NOT NULL DEFAULT 0,
|
||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_merchant_available` (`merchant_id`, `is_available`),
|
||
KEY `idx_category` (`category_id`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 5. food_item_options — مجموعات خيارات الصنف (حجم، إضافات...)
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_item_options` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`item_id` INT UNSIGNED NOT NULL,
|
||
`group_name_ar` VARCHAR(100) NOT NULL COMMENT 'مثال: الحجم، الإضافات',
|
||
`is_required` TINYINT(1) NOT NULL DEFAULT 0,
|
||
`max_select` TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '1=اختيار واحد، أكثر=متعدد',
|
||
`choices` JSON NOT NULL COMMENT '[{"id":"lg","label_ar":"كبير","price":500}]',
|
||
`sort_order` SMALLINT NOT NULL DEFAULT 0,
|
||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_item` (`item_id`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 6. food_orders — الطلب
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_orders` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`client_order_uuid` CHAR(36) NOT NULL COMMENT 'idempotency — يمنع الضغط المزدوج من إنشاء طلبين',
|
||
`passenger_id` VARCHAR(100) NOT NULL COMMENT 'مرجع منطقي فقط — لا FK خارجي',
|
||
`merchant_id` INT UNSIGNED NOT NULL,
|
||
`courier_id` VARCHAR(100) DEFAULT NULL COMMENT 'main driver id بعد الإسناد',
|
||
`status` ENUM(
|
||
'pending','merchant_accepted','preparing','ready',
|
||
'courier_assigned','picked_up','delivered',
|
||
'rejected','cancelled_by_customer','cancelled_by_merchant','cancelled_system'
|
||
) NOT NULL DEFAULT 'pending',
|
||
`items_total` BIGINT UNSIGNED NOT NULL COMMENT 'مجموع أصناف الطلب — أصغر وحدة نقدية',
|
||
`delivery_fee` BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
`service_fee` BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
`discount` BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
`grand_total` BIGINT UNSIGNED NOT NULL COMMENT 'items_total+delivery_fee+service_fee-discount',
|
||
`commission_amount` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'نصيب المنصة من items_total',
|
||
`payment_method` ENUM('wallet','cash') NOT NULL DEFAULT 'wallet',
|
||
`payment_hold_ref` VARCHAR(100) DEFAULT NULL COMMENT 'مرجع حجز المحفظة في payment_server/v2',
|
||
`delivery_address` VARCHAR(300) NOT NULL,
|
||
`delivery_lat` DECIMAL(10,7) NOT NULL,
|
||
`delivery_lng` DECIMAL(10,7) NOT NULL,
|
||
`customer_note` VARCHAR(300) DEFAULT NULL,
|
||
`promo_code` VARCHAR(40) DEFAULT NULL,
|
||
`rating` TINYINT UNSIGNED DEFAULT NULL,
|
||
`rating_comment` VARCHAR(300) DEFAULT NULL,
|
||
`merchant_accepted_at` TIMESTAMP DEFAULT NULL,
|
||
`ready_at` TIMESTAMP DEFAULT NULL,
|
||
`courier_assigned_at` TIMESTAMP DEFAULT NULL,
|
||
`picked_up_at` TIMESTAMP DEFAULT NULL,
|
||
`delivered_at` TIMESTAMP DEFAULT NULL,
|
||
`cancelled_at` TIMESTAMP DEFAULT NULL,
|
||
`cancel_reason` VARCHAR(300) 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`),
|
||
UNIQUE KEY `uq_client_uuid` (`client_order_uuid`),
|
||
KEY `idx_passenger_created` (`passenger_id`, `created_at`),
|
||
KEY `idx_merchant_status` (`merchant_id`, `status`),
|
||
KEY `idx_courier_status` (`courier_id`, `status`),
|
||
KEY `idx_status` (`status`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 7. food_order_items — أصناف الطلب بسعر مجمّد وقت الطلب
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_order_items` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`order_id` INT UNSIGNED NOT NULL,
|
||
`item_id` INT UNSIGNED NOT NULL COMMENT 'مرجع فقط — لا JOIN للسعر',
|
||
`name_ar_snapshot` VARCHAR(150) NOT NULL,
|
||
`unit_price` BIGINT UNSIGNED NOT NULL COMMENT 'سعر الوحدة وقت الطلب — مجمّد',
|
||
`quantity` SMALLINT UNSIGNED NOT NULL DEFAULT 1,
|
||
`option_price_json` JSON DEFAULT NULL COMMENT 'الخيارات المختارة وأسعارها وقت الطلب',
|
||
`line_total` BIGINT UNSIGNED NOT NULL COMMENT '(unit_price+مجموع الخيارات)×quantity',
|
||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_order` (`order_id`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 8. food_order_status_log — كل انتقال حالة — مصدر الحقيقة للنزاعات
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_order_status_log` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`order_id` INT UNSIGNED NOT NULL,
|
||
`from_status` VARCHAR(30) DEFAULT NULL,
|
||
`to_status` VARCHAR(30) NOT NULL,
|
||
`actor_type` ENUM('customer','merchant','courier','admin','system') NOT NULL,
|
||
`actor_id` VARCHAR(100) DEFAULT NULL,
|
||
`note` VARCHAR(300) DEFAULT NULL,
|
||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_order` (`order_id`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 9. food_order_payments — مرجع معاملة المحفظة/الدفع + التسوية
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_order_payments` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`order_id` INT UNSIGNED NOT NULL,
|
||
`type` ENUM('hold','capture','release','cash_settlement','courier_payout') NOT NULL,
|
||
`amount` BIGINT UNSIGNED NOT NULL,
|
||
`wallet_ref` VARCHAR(100) DEFAULT NULL COMMENT 'مرجع من payment_server/v2',
|
||
`status` ENUM('pending','success','failed') NOT NULL DEFAULT 'pending',
|
||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_order` (`order_id`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 10. food_courier_assignments — محاولات إسناد الطلب لسائق
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_courier_assignments` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`order_id` INT UNSIGNED NOT NULL,
|
||
`courier_id` VARCHAR(100) NOT NULL COMMENT 'main driver id',
|
||
`status` ENUM('offered','accepted','rejected','timed_out') NOT NULL DEFAULT 'offered',
|
||
`offered_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
`responded_at` TIMESTAMP DEFAULT NULL,
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_order` (`order_id`),
|
||
KEY `idx_courier` (`courier_id`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 11. food_merchant_payouts — مستحقات المطاعم ودورات التسوية
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_merchant_payouts` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`merchant_id` INT UNSIGNED NOT NULL,
|
||
`period_start` DATE NOT NULL,
|
||
`period_end` DATE NOT NULL,
|
||
`orders_count` INT UNSIGNED NOT NULL DEFAULT 0,
|
||
`gross_amount` BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
`commission_amount` BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
`net_payout` BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
`status` ENUM('pending','paid') NOT NULL DEFAULT 'pending',
|
||
`paid_at` TIMESTAMP DEFAULT NULL,
|
||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_merchant_period` (`merchant_id`, `period_start`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 12. food_promo_codes — أكواد خصم خاصة بالطعام (منفصلة عن أكواد الرحلات)
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_promo_codes` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`code` VARCHAR(40) NOT NULL,
|
||
`discount_type` ENUM('percent','fixed') NOT NULL DEFAULT 'fixed',
|
||
`discount_value` INT UNSIGNED NOT NULL,
|
||
`max_discount` BIGINT UNSIGNED DEFAULT NULL,
|
||
`min_order_amount` BIGINT UNSIGNED NOT NULL DEFAULT 0,
|
||
`usage_limit` INT UNSIGNED DEFAULT NULL,
|
||
`usage_count` INT UNSIGNED NOT NULL DEFAULT 0,
|
||
`valid_from` TIMESTAMP DEFAULT NULL,
|
||
`valid_until` TIMESTAMP DEFAULT NULL,
|
||
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
|
||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (`id`),
|
||
UNIQUE KEY `uq_code` (`code`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- 13. food_merchant_sessions — جلسات دخول لوحة المطعم (هاتف+كلمة مرور،
|
||
-- session token مستقل عن JWT — نفس نمط transit_sessions، لأن لوحة
|
||
-- المطعم ويب متجاوب لا يملك device fingerprint كتطبيق الجوال)
|
||
-- -----------------------------------------------------------------
|
||
CREATE TABLE IF NOT EXISTS `food_merchant_sessions` (
|
||
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||
`merchant_user_id` INT UNSIGNED NOT NULL,
|
||
`merchant_id` INT UNSIGNED NOT NULL,
|
||
`token_hash` VARCHAR(64) NOT NULL COMMENT 'sha256 للـ session token',
|
||
`ip` VARCHAR(45) DEFAULT NULL,
|
||
`user_agent` VARCHAR(300) DEFAULT NULL,
|
||
`expires_at` TIMESTAMP NOT NULL,
|
||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
PRIMARY KEY (`id`),
|
||
UNIQUE KEY `uq_token` (`token_hash`),
|
||
KEY `idx_merchant_user` (`merchant_user_id`),
|
||
KEY `idx_expires` (`expires_at`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||
|
||
SET FOREIGN_KEY_CHECKS = 1;
|
||
|
||
-- -----------------------------------------------------------------
|
||
-- ملاحظات Redis (مفاتيح تُكتب من PHP — ليست في SQL):
|
||
-- food:order:{id}:lock → SET NX EX 20 عند قبول سائق (يمنع سباق القبول)
|
||
-- geo:couriers:available → مجموعة جغرافية للسائقين can_deliver=1 المتفرغين
|
||
-- food:merchant:{id}:cache → كاش بيانات مطعم للقراءة السريعة (اختياري لاحقاً)
|
||
-- Redis channels للسوكيت: food:order:{id} / food:merchant:{id} / food:courier:{id}
|
||
-- -----------------------------------------------------------------
|