Files
Siro/backend/food/schema_food.sql
T

290 lines
16 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =============================================================
-- 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}
-- -----------------------------------------------------------------