-- 2026_08_07_courier_settlement.sql — دورة تسوية أرباح سائقي التوصيل -- -- ‏قرار المالك: الأجرة **تتراكم وتُصرف دورياً مع مقاصّة دَين النقد**، لا -- ‏تُصرف فوراً عند كل تسليم. -- -- ‏لماذا المقاصّة ضرورية: في الطلب النقدي يحصّل السائق grand_total كاملاً -- ‏من الزبون، فيصير مديناً للمنصة بحصة المطعم والعمولة. صرف أجرته منفصلاً -- ‏عن هذا الدَين يعني أن تدفع له بينما هو يحمل مالك. -- -- الصافي = مجموع أجور التوصيل − مجموع ديون النقد -- -- ‏موجب → يُصرف لمحفظة السائق -- ‏سالب → يبقى ديناً يُرحَّل للدورة التالية (لا نخصم من محفظته آلياً: -- ‏قد تكون فارغة، والخصم القسري يفاجئه ويوقفه عن العمل) -- -- ⚠️ ‏يُنفَّذ على قاعدة الطعام (siro_food) لا primary. -- -- sirodb siro_food < backend/food/migrations/2026_08_07_courier_settlement.sql CREATE TABLE IF NOT EXISTS `food_courier_settlements` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `courier_id` VARCHAR(100) NOT NULL COMMENT 'معرّف السائق (نفس driver.id)', `period_start` DATETIME NOT NULL, `period_end` DATETIME NOT NULL, `orders_count` INT UNSIGNED NOT NULL DEFAULT 0, `payout_total` BIGINT NOT NULL DEFAULT 0 COMMENT 'مجموع أجور التوصيل المستحقة (أصغر وحدة)', `cash_debt_total` BIGINT NOT NULL DEFAULT 0 COMMENT 'مجموع ما حصّله نقداً ويخص المنصة', `carried_over` BIGINT NOT NULL DEFAULT 0 COMMENT 'دَين مُرحَّل من دورة سابقة (سالب الصافي)', `net_amount` BIGINT NOT NULL DEFAULT 0 COMMENT 'الصافي = payout − debt − carried_over', `currency` VARCHAR(5) NOT NULL DEFAULT 'JOD', `status` VARCHAR(20) NOT NULL DEFAULT 'draft' COMMENT 'paid = صُرفت | failed = تعذّر التحويل | carried = سالبة تُرحَّل للدورة القادمة | settled_forward = رُحّلت واستُهلكت في دورة لاحقة | draft', `transfer_code` SMALLINT NULL DEFAULT NULL COMMENT 'رمز HTTP من خادم المحفظة', `executed_by` VARCHAR(100) NULL DEFAULT NULL, `executed_at` DATETIME NULL DEFAULT NULL, `note` VARCHAR(500) NULL DEFAULT NULL, `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), -- ‏يمنع توليد دورتين لنفس السائق ونفس الفترة — الازدواج هنا يعني صرفاً مضاعفاً UNIQUE KEY `uniq_courier_period` (`courier_id`, `period_start`, `period_end`), KEY `idx_status` (`status`, `created_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='دورات تسوية سائقي التوصيل — أجور مقاصّةً مع ديون النقد'; -- ‏ربط قيود الدفع بدورة التسوية التي ضمّتها: بدونه لا نعرف ما سُوّي وما لم -- ‏يُسوَّ، فتُحتسب نفس الأجرة مرتين في دورتين متتاليتين. ALTER TABLE `food_order_payments` ADD COLUMN `settlement_id` INT UNSIGNED NULL DEFAULT NULL COMMENT 'دورة التسوية التي ضمّت هذا القيد. NULL = لم يُسوَّ بعد', ADD KEY `idx_settlement` (`settlement_id`, `type`, `status`); -- ‏للتراجع: -- DROP TABLE `food_courier_settlements`; -- ALTER TABLE `food_order_payments` DROP COLUMN `settlement_id`, DROP KEY `idx_settlement`;