# دليل اختبار تكامل كابيتانو ويب ⇄ كابيتانو لوجستك

دليل بالعربية، خطوة بخطوة، لاختبار التكامل بالطريقة الصحيحة: من «هل الكود سليم؟» إلى «هل يسافر طلب حقيقي من المتجر إلى الزبون؟».
كل خطوة فيها ثلاثة أشياء: **ماذا تفعل** · **ماذا يجب أن ترى** · **ماذا يعني إن لم تره**.

---

## 0. المشاريع الثلاثة

| المشروع | المسار | دوره |
|---|---|---|
| **المتجر** (`kapitano_web`) | `C:\xampp\htdocs\kapitano_web` | متجر لارافيل: يسلّم الطلبات للوجستك ويتابع تقدمها. الفرع: `feat/kapitano-logistic-integration-2026-10-07` |
| **لوجستك** (`kapitano_logistic`) | `C:\xampp\htdocs\kapitano_logistic` | الـAPI للتوزيع والكباتن ودفتر المتجر. الفرع: `dev` |
| **لوحة التحكم** (`kapitano-admin`) | `C:\Users\DELL\Desktop\Kapitano\kapitano-admin` | Next.js: شاشات الإدارة **وبوابة صاحب المتجر** (`/portal`). الفرع: `dev` |

> التفاصيل والقرارات والأدلة الكاملة في السجل: `docs/kapitano-web-integration-implementation-log-ar.md`.

---

## 1. الفكرة في دقيقة

```
تأكيد الطلب في المتجر ──► صف في صندوق الإرسال ──► لوجستك ينشئ الطلب (معلّق)
                                                         │ الموزّع يُسند، الكابتن يستلم ويسلّم
حالة الطلب في المتجر ◄── إشعار موقَّع (webhook) من لوجستك ◄──┘
```

**القواعد التي ستختبرها:**

1. **لا يحدث شيء إلا إذا فُعِّل التكامل** (`LOGISTIC_ENABLED=true`) وكان البائع في قائمة المسموح لهم. والوضع الآمن يُخفي اسم الزبون ورقمه.
2. **تعطّل لوجستك لا يُفشل أي عملية في المتجر.** العمل ينتظر في صندوق الإرسال ويُعاد لاحقًا.
3. **قفل الإلغاء والتعديل:** بعد أن يستلم الكابتن البضاعة (`picked_up` أو `on_the_way`) لا يستطيع المتجر إلغاء الطلب ولا تغيير منتجاته. شاشات المتجر ترفض أولًا، ولوجستك يردّ `409` كخط دفاع ثانٍ.
4. **من يدفع رسم التوصيل:** الزبون في الحالة العادية. ويكون على **المتجر** عندما: (أ) شريحة قيمة تجعل التوصيل مجانيًا للزبون (مثل طلب 3000 فأكثر)، (ب) الطلب مدفوع مسبقًا، (ج) فشل التوصيل، (د) أُلغي الطلب **بعد** الاستلام. الإلغاء **قبل** الاستلام لا يكلّف شيئًا.
5. **الإجماليات:** لوجستك والبوابة يعرضان: *إجمالي المنتجات* · *رسم التوصيل* (في سطر مستقل) · *الإجمالي المحسوب* (منتجات + رسم) · *ما يدفعه الزبون عند الباب*.
6. **العملة:** الليرة السورية (SYP) فقط. المتجر يحوّل من الدولار إلى ليرات صحيحة قبل الإرسال، ولوجستك **يرفض بـ422** أي عملة أخرى عند الإنشاء أو التعديل.

---

## 2. التجهيز (مرة واحدة)

### 2.1 الخدمات التي يجب أن تكون شغّالة

| الخدمة | كيف تشغّلها | كيف تتأكد |
|---|---|---|
| MySQL | من XAMPP | `mysql -uroot -e "select 1"` |
| Redis | شغّله | `redis-cli ping` ← `PONG` |
| **لوجستك** | في مجلد لوجستك: `php artisan serve --port=8001` | افتح `http://127.0.0.1:8001/api/integration/v1/health` ← **401** (هذا صحيح، فهو يطلب توقيعًا) |
| **المتجر** | في مجلد المتجر: `php -S 127.0.0.1:8000 -t public public/index.php` | `http://127.0.0.1:8000/` ← 200 |
| **لوحة التحكم** | في مجلد اللوحة: `npm run dev` | `http://localhost:3000/portal/login` ← 200 |
| **المشغّل التجريبي** (للتجربة اليدوية فقط) | في مجلد المتجر: `php tests/Live/support/dev_runner.php` | يُبقي الإشعارات وصندوق الإرسال يتحركان دون `queue:work` |

> ⚠️ **المنفذ 8000 يجب أن يكون فارغًا عند تشغيل سكربتات الاختبار الحي (القسم 4)** لأنها تشغّل خادم متجرها بنفسها. أوقف الخادم التجريبي والمشغّل قبلها، وأعد تشغيلهما بعدها.

### 2.2 الإعدادات في `.env` الخاص بالمتجر

```env
LOGISTIC_ENABLED=true
LOGISTIC_SAFE_MODE=true            # اتركه true محليًا: بيانات الزبون تُخفى
LOGISTIC_BASE_URL=http://127.0.0.1:8001/api/integration/v1
LOGISTIC_TOKEN=...                 # رمز المتجر (من لوجستك: integration:issue-token أو من البوابة)
LOGISTIC_SIGNING_SECRET=...        # سر توقيع المتجر ← لوجستك
LOGISTIC_WEBHOOK_SECRET=...        # سر توقيع لوجستك ← المتجر
LOGISTIC_ALLOW_SELLERS=<رقم بائع>  # ابدأ ببائع تجريبي واحد، وLOGISTIC_ALLOW_ALL=false
LOGISTIC_APPLY_STATUS=true         # ليحرّك تقدّم لوجستك حالة طلب المتجر (انظر 7.3)
```

وفي `.env` الخاص بلوجستك (ليصل الإشعار إلى المتجر المحلي): `INTEGRATION_ALLOW_PRIVATE_WEBHOOK_URLS=true`.
ورابط الاستدعاء المسجَّل للمتجر في لوجستك يجب أن يكون: `http://127.0.0.1:8000/logistic/webhook`.

### 2.3 قواعد البيانات

```
# المتجر
php artisan migrate
mysql -uroot kapitano_web < sqlupdates/kapitano_logistic_integration_*.sql     # الملفات الستة، وآمن تكرارها
php artisan cache:clear

# لوجستك
php artisan migrate
```

### 2.4 فحص سريع للصحة (قبل أي اختبار)

شغّل في مجلد المتجر:

| الأمر | المتوقع |
|---|---|
| `php artisan logistic:health` | نجاح نداء موقَّع إلى لوجستك (HTTP 200) |
| `php artisan logistic:contract:check` | «مطابق»: عقد الـSwagger المثبَّت = عقد لوجستك الحالي. إن ظهر **انجراف** فقد تغيّر API لوجستك: راجع الفرق ثم `logistic:contract:pin` بعد قبوله |
| `php artisan logistic:status` | أعداد الصفوف حسب الحالة، ولا شيء عالق في `needs_attention` |

---

## 3. المستوى الأول: الاختبارات الآلية (لا تحتاج خوادم)

### 3.1 المتجر

```bash
cd C:\xampp\htdocs\kapitano_web
php artisan test tests/Feature/Logistic tests/Unit/Logistic
```

> إن توقف الأمر بصمت وخرج بـ0 فالسبب ذاكرة PHP (128M). استعمل ملف `php.ini` فيه `memory_limit=1G` عبر المتغير `PHPRC`.

**المتوقع: نحو 649 اختبارًا كلها ناجحة** (3–4 دقائق). أهم المجموعات:

| الملف | ماذا يثبت |
|---|---|
| `OutboxSenderTest` و`QueueOrderForLogisticTest` | الإنشاء يُصفّ مرة واحدة، ويُعاد عند 5xx/الشبكة، ويُركَن عند 422، ولا يتكرر أبدًا |
| `CancelOrderTest` و`CancelGuardTest` | الإلغاء يصل لوجستك؛ والمتجر يرفض الإلغاء/تغيير المنتجات بعد استلام الكابتن |
| `PaymentSyncTest` و`EditSyncTest` | حالة الدفع وتعديل السلة تُرسَل؛ وأقفال لوجستك تُسجَّل **ولا تُعاد** |
| `WebhookReceiverTest` و`StatusConvergerTest` و`StatusFlowTest` | التوقيع الخاطئ مرفوض، والمكرر والقديم يُتجاهلان، والحالة تُطبَّق بكود المتجر نفسه |
| `ReconcileCommandTest` | ما فات من أحداث يلتقطه `logistic:reconcile` |
| `Contract/*` | ما يرسله المتجر يطابق Swagger لوجستك |

**للتأكد أن بقية المتجر لم يتأثر:** شغّل المجموعة الكاملة وقارنها بما قبل التكامل: نتيجة الاختبارات القائمة يجب ألا تتغير (74 منها فاشلة أصلًا لأسباب لا علاقة لها بنا).

### 3.2 لوجستك

```bash
cd C:\xampp\htdocs\kapitano_logistic
php -d memory_limit=1G artisan test tests/Feature/Integration tests/Feature/Order tests/Feature/StorePortal tests/Feature/Pricing tests/Feature/Documentation
```

**المتوقع: نحو 467 اختبارًا كلها ناجحة.** أهمها: `StoreTokenLifetimeTest` (رمز المتجر لا يموت بعد 30 يومًا) · `StoreOrderLifecycleTest` (قفل الإلغاء) · `StoreOrderUpdateTest` (أقفال التعديل) · `DeliveryFeePricingTest` (الرسم رسم المنطقة كاملًا والشريحة تحدد حصة الزبون) · `StoreCancelFeeTest` (الإلغاء بعد الاستلام يحمّل المتجر الرسم) · `StorePortalOrderTotalsTest` و`OrderTotalTest` (الإجماليات ومن يدفع) · `StorePortalDisclosureTest`.

> المجموعة **الكاملة** في لوجستك فيها اليوم أخطاء **ليست من هذا العمل** (`DispatchSettingKeyTest`، `RoutePlanLifecycleE2ETest`، `PushManagementApiTest`، واختبارات `Parallel*`). إن رأيتها فليست تراجعًا في التكامل. وصنف `DriverDocumentResubmission` يعلق إن شُغّل كتلة واحدة: شغّله على نصفين.

### 3.3 لوحة التحكم

```bash
cd C:\Users\DELL\Desktop\Kapitano\kapitano-admin
npx tsc --noEmit
npx eslint src
```

**المتوقع:** لا مخرجات (نظيف).

---

## 4. المستوى الثاني: الاختبار الحي من البداية للنهاية (خوادم حقيقية)

هذه السكربتات تشغّل **المتجر الحقيقي ولوجستك الحقيقي** معًا، وتنظّف بعد نفسها.

**قبل أن تبدأ:** الخدمات في 2.1 تعمل · **الخادم التجريبي والمشغّل متوقفان** (المنفذ 8000 فارغ) · `LOGISTIC_SAFE_MODE=true` · قاعدة البيانات على هذا الجهاز (السكربتات ترفض غير ذلك).

```bash
cd C:\xampp\htdocs\kapitano_web
php tests/Live/logistic_real_flow_e2e.php
```

يستغرق نحو 8–10 دقائق. **المتوقع في آخر سطر:** `188 checks, 0 failed`.

ماذا يغطي، قسمًا قسمًا:

| القسم | ما يثبته |
|---|---|
| 0–8 | زبون يطلب عبر API المتجر ← البائع يؤكد ← الموظف يؤكد في الإدارة ← يظهر الطلب في لوجستك بالأصناف والعنوان والمبلغ الصحيحة؛ التأكيد مرتين ينشئ طلبًا **واحدًا**؛ لا يُمَسّ غيره؛ الإلغاء في المتجر يلغي في لوجستك |
| 9 | إشعارات لوجستك تحرّك طلب المتجر (أُسند ← استُلم ← في الطريق ← سُلّم) عبر كود المتجر نفسه |
| 10 | المحاسب يضع «مدفوع/غير مدفوع» فيصل لوجستك؛ الصف نفسه يُعاد استعماله؛ وما فات يلتقطه `logistic:reconcile` |
| 11 | بعد الاستلام: زر «إلغاء الطلب» وقائمة الحالة **يرفضان**؛ ومع معرفة متأخرة يردّ لوجستك **409** فيُركَن مع تحذير؛ والعمليات ما زالت تستطيع الإلغاء |
| 12 | تغيير الكمية يصل لوجستك (السلة والمبلغ)؛ بعد الاستلام الشاشة ترفض؛ ومع معرفة متأخرة يردّ **409** `order_already_collected` ويُسجَّل ولا يُعاد |
| 13–14 | **أشخاص حقيقيون:** موزّع وكابتن مؤقتان يقودان طلبًا عبر واجهات لوجستك الحقيقية؛ المتجر يتبع كل خطوة؛ دفتر المتجر يأخذ سطر النقد وسطر الرسم؛ والبوابة تعرض المنتجات وسطر الرسم والإجمالي المحسوب |
| 15 | فشل التوصيل: الرسم على المتجر، وطلب المتجر لا يتغير (يُنبَّه فقط) |
| 16 | إلغاء بعد الاستلام: الرسم على المتجر، وإشعار إلغاء الكابتن يُصَفّ، والكابتن يتحرر؛ وقبل الاستلام: لا رسم |
| 17 | شريحة التوصيل المجاني: يُفوتَر المتجر الرسم كاملًا، ثم تُزال الشريحة |
| 19 | **الطلبات المغلَّفة:** رفض بلا مكان تغليف ثم قبول بعد ضبطه من البوابة، رحلتا جمع وتوصيل، منع إسناد التوصيل قبل وصول البضاعة، إتمام الرحلتين، الدفتر مرة واحدة، وإلغاء يلغي الرحلتين |
| 18 | عزل البوابة (متجر آخر ← 404، بلا دخول ← 401)، وانتهاء رمز المتجر نحو سنة، وعدم انجراف العقد |

ولكل خطوة قديمة سكربتها (شغّلها واحدًا بعد الآخر، والمنفذ 8000 فارغ):

```bash
php tests/Live/logistic_step2_e2e.php   # 84 فحصًا: الإنشاء، إعادة المحاولة، 422/401، تعطّل لوجستك وعودته، فرض Swagger
php tests/Live/logistic_step3_e2e.php   # 33: تبنّي الطلب عند ضياع الرد، والمطابقة
php tests/Live/logistic_step4_e2e.php   # 40: مسارات الإلغاء
php tests/Live/logistic_step5_e2e.php   # 47: مستقبِل الإشعارات
```

**إن فشل سكربت:** اقرأ سطر `FAIL`، فهو يطبع الدليل بين قوسين.
**وإن أوقفته في منتصفه** (Ctrl-C) فسيترك مستخدمين وطلبات تجريبية (أسماء `E2E …`، وإيميلات `e2e-…@example.test`). نظّفها بإعادة تشغيل `logistic_step2_e2e.php` أو احذفها يدويًا، وتأكد أن `select count(*) from users where email like 'e2e-%'` يعطي 0.

---

## 5. المستوى الثالث: تجربة يدوية (أنت تقود)

لترى بعينك. تستعمل بيانات وهمية فقط (`demo-*@kapitano.test` وأسماء «Kapitano Demo …»).

### 5.1 التجهيز

```bash
cd C:\xampp\htdocs\kapitano_web
php tests/Live/support/demo.php seed      # ينشئ البائع والمتجر والمنتج والزبون والمدير التجريبيين ويطبع بيانات الدخول
php tests/Live/support/dev_runner.php     # اتركه شغّالًا في نافذة مستقلة
php tests/Live/support/demo.php status    # ماذا يوجد
```

ادخل إدارة المتجر بمدير العرض الذي طبعه `seed`.

### 5.2 السيناريوهات (بهذا الترتيب)

**أ) التسليم للوجستك**
1. نفّذ `php tests/Live/support/demo.php order --confirm` (أو اطلب طلبًا ثم «Confirm Orders» من الإدارة).
2. في صفحة الطلب بإدارة المتجر: كتلة **Kapitano Logistic** تُظهر الحالة *created* ورقم طلب لوجستك والحالة *pending*.
3. في لوجستك: يوجد الطلب بالأصناف و**المبلغ المطلوب تحصيله** الصحيحين.
✅ المتوقع: طلب واحد في لوجستك. والضغط على «تأكيد» مرة ثانية **لا** ينشئ آخر.

**ب) متابعة التوصيل**
في لوحة لوجستك: أسند كابتنًا ← (من تطبيق/واجهة الكابتن) قبول ← استلام ← في الطريق ← تسليم.
✅ المتوقع: بعد كل خطوة تتحدّث صفحة الطلب في المتجر خلال ثوانٍ (مع المشغّل). عند *التسليم* يصير طلب المتجر مسلَّمًا، والمخزون والسجل كما لو غُيّر يدويًا.

**ج) إلغاء قبل الاستلام**
طلب جديد ← ألغِه من إدارة المتجر.
✅ المتوقع: يُلغى في لوجستك؛ الكابتن (إن أُسند) يتحرر ويصله إشعار إلغاء؛ **لا يُحسب أي رسم**.

**د) إلغاء بعد الاستلام (القفل)**
طلب جديد ← في لوجستك: أسند، اقبل، استلام. ثم اضغط **Cancel Order** في إدارة المتجر.
✅ المتوقع: يرفض برسالة *«The captain has already collected this order … Contact Kapitano dispatch»* ويبقى الطلب كما هو ولا يتحرك مخزون. أما العمليات فتستطيع الإلغاء من لوجستك ← يُحمَّل المتجر **الرسم** ويرى في البوابة *«أُلغي بعد الاستلام»*.

**هـ) تعديل كمية**
طلب جديد وسلّمه للوجستك، ثم غيّر كمية سطر في إدارة المتجر **قبل** الاستلام.
✅ المتوقع: طلب لوجستك يحمل الكمية والمبلغ الجديدين. وبعد الاستلام يرفض المتجر العملية نفسها.

**و) الدفع**
علّم طلبًا «مدفوع» بصفتك المحاسب.
✅ المتوقع: يصير مدفوعًا في لوجستك (فلا يحصّل الكابتن). علّمه «غير مدفوع» فيتبع.

**ز) الرسم والإجماليات في البوابة**
افتح `http://localhost:3000/portal/login` بـ`demo-owner@kapitano.test` / `Demo-Passw0rd!` ← **Orders** ← افتح طلبًا.
✅ المتوقع: جدول المنتجات، *Products total*، *Delivery fee* (سطر مستقل وبجانبه وسم **«عليكم»** مع السبب حين يدفعه المتجر)، *Order total* (= منتجات + رسم)، *ما يدفعه الزبون عند الباب*.

**ح) إجمالي الإدارة**
في صفحة الطلب بلوحة الإدارة (بدخول مدير): بطاقة المال تُظهر الإجمالي **بضاعة + رسم**، وتحتها «المطلوب من الزبون عند الباب»، وجملة تقول من يدفع الرسم.

**ط) عزل الأعطال**
أوقف لوجستك ثم أكّد طلبًا في المتجر.
✅ المتوقع: **التأكيد ينجح**، والطلب ينتظر في صندوق الإرسال (`logistic:status` يُظهره معلّقًا). شغّل لوجستك ثم `php artisan logistic:send` (أو انتظر المجدول) ← يُنشأ الطلب. لا ضياع ولا تكرار.

**ي) مفتاح الإيقاف**
اجعل `LOGISTIC_ENABLED=false` وأعد تشغيل المتجر وأكّد طلبًا.
✅ المتوقع: لا يُصَفّ شيء، والمتجر يعمل كما قبل التكامل تمامًا.

**ك) طلب مغلَّف — الزبون هو من يقرّر**
1. بوابة المتجر ← **Settings** ← بطاقة **مكان التغليف**: اتركها فارغة. ثم أضف منتجًا لسلة الزبون وافتح صفحة الدفع.
   ✅ المتوقع: **لا يظهر** خيار «تغليف هذا الطلب قبل التوصيل» (والتطبيق: `GET /api/v2/wrapping/availability` يردّ `available: false`). وإن أرسل التطبيق `needs_wrapping=1` رغم ذلك يُرفض الطلب برسالة «التغليف غير متاح لهذا الطلب» ولا يُنشأ شيء (لا يُسقَط الطلب بصمت). الموظف لا يستطيع تغيير التغليف؛ صفحة الطلب تعرضه للقراءة فقط.
2. في البوابة: احفظ مكان التغليف (الاسم، العنوان، خط العرض والطول). بعد نحو 5 دقائق (أو بعد `php artisan cache:clear`) يظهر الخيار للزبون. ضع العلامة وأتمّ الطلب وأكّده.
   ✅ المتوقع: ينشئ لوجستك **طلبين مترابطين**: رحلة **جمع** (من المورّد إلى مكان التغليف) ورحلة **توصيل** (من مكان التغليف إلى الزبون). المتجر يعرف رحلة التوصيل فقط.
3. حاول إسناد رحلة التوصيل لكابتن.
   ✅ المتوقع: **409** «البضاعة لم تصل مكان التغليف بعد».
4. أسند رحلة الجمع لكابتن وأتمّها (قبول ← استلام ← في الطريق ← تسليم). ثم أسند رحلة التوصيل لكابتن آخر (أو الأول بعد تحرره) وأتمّها بنقد.
   ✅ المتوقع: المتجر **لا يسمع شيئًا** عن رحلة الجمع، ويتبع رحلة التوصيل حتى التسليم؛ دفتر المتجر: سطر نقد + سطر رسم **مرة واحدة** ولا شيء لرحلة الجمع.
5. ألغِ طلبًا مغلَّفًا من المتجر. ✅ تُلغى **الرحلتان** معًا.
6. حاول إضافة التغليف لطلب سُلِّم للوجستك أصلًا. ✅ يرفض المتجر (لا يتحول طلب واحد إلى اثنين).

### 5.3 تنظيف العرض

```bash
php tests/Live/support/demo.php remove     # يلغي طلبات العرض في لوجستك ويحذف كل بيانات العرض
```

---

## 6. فحوص تتحقق منها بعينك

### 6.1 قواعد الرسم: الحالات الخمس

| الحالة | كيف تصنعها | ما يقوله الدفتر والبوابة |
|---|---|---|
| طلب عادي (دفع عند الاستلام) سُلِّم | السيناريو ب | الرسم على **الزبون** (`normal`) |
| شريحة توصيل مجاني | أعطِ المتجر سلّم أسعار خاصًّا به في لوجستك بشريحة «من 1000 بحصة 0» ثم اطلب بقيمة ≥ 1000 | الرسم على **المتجر** («شريحة القيمة»)، والرسم رسم المنطقة كاملًا، وحصة الزبون 0 |
| طلب مدفوع مسبقًا | ادفع أونلاين | الرسم على **المتجر** («مدفوع مسبقًا») |
| فشل التوصيل | الكابتن يبلّغ الفشل | الرسم على **المتجر** والسبب على سطر الدفتر |
| إلغاء بعد/قبل الاستلام | السيناريو د / ج | يُحمَّل المتجر / **لا أحد يُحمَّل** |

وتحقّق أيضًا من **دفتر المتجر** (البوابة ← Payments ← Ledger): التسليم بالدفع عند الاستلام = سطر نقد + سطر *delivery fee* سالب؛ والفشل أو الإلغاء بعد الاستلام = سطر الرسم فقط.

### 6.2 الأمان

| الفحص | المتوقع |
|---|---|
| POST على `/logistic/webhook` في المتجر بتوقيع خاطئ أو بلا توقيع | يُرفض ولا يتغير شيء |
| إرسال الإشعار نفسه مرتين، أو حدث أقدم بعد أحدث | يُتجاهل |
| البوابة: فتح طلب متجر آخر | **404** (ليس 403) |
| البوابة: بلا رمز دخول | **401** |
| رمز متجر على واجهة الموزّع (`/api/dashboard/…`) | 401 أو 403 |
| انتهاء رمز المتجر (`personal_access_tokens.expires_at`) | بعد نحو سنة |

### 6.3 مفتاح «تطبيق الحالة»

`LOGISTIC_APPLY_STATUS=false` ← المتجر **يعرض** حالة لوجستك فقط (لا يغيّر الطلب). `true` ← يتحرك الطلب فعلًا (مخزون وسجل وإشعارات). **جرّب false أولًا** (السيناريو ب يُظهر الحالة على الصفحة دون تغيير حالة الطلب نفسه)، ثم فعّله للبائع التجريبي.

---

## 7. المستوى الرابع: التشغيل الفعلي

1. **بيئة تجريبية (staging) أولًا** برابط لوجستك الحقيقي، ورمز المتجر وأسراره الحقيقية، ورابط استدعاء **عام** مسجَّل للمتجر في لوجستك.
2. `LOGISTIC_ENABLED=true` و`LOGISTIC_ALLOW_SELLERS=<بائع واحد>` و`LOGISTIC_SAFE_MODE=true`. اطلب طلبات وكرّر السيناريوهات أ–ز.
3. **حدّد إحداثيات الاستلام لكل متجر حقيقي** (`php artisan logistic:branches` يعرضها، و`logistic:branch:set` يضبطها). **المتجر بلا إحداثيات يُركَن ولا يُخمَّن.**
4. خدمات الإنتاج: `queue:work` شغّال في لوجستك (يرسل **إشعار Firebase للكابتن** والإشعارات للمتجر)، ومجدول لارافيل (scheduler) شغّال في المتجر (يرسل الصندوق ويعيد المحاولة كل دقيقة)، وRedis وReverb في لوجستك.
5. لا تجعل `LOGISTIC_SAFE_MODE=false` إلا حين تكون جاهزًا لمراسلة زبائن حقيقيين. وافحص **أول الطلبات الحقيقية بيدك** (الأصناف، العنوان، المبلغ، الهاتف).
6. وسّع قائمة المسموح لهم تدريجيًا. **الإيقاف الفوري:** `LOGISTIC_ENABLED=false` (الصفوف المنتظرة تبقى وتستأنف عند العودة).
7. شغّل ملفات SQL للترجمة على قاعدة المتجر الحية وامسح الكاش.

---

## 8. حلّ المشاكل

| العَرَض | السبب المرجَّح / ما تفعله |
|---|---|
| الطلب مؤكَّد ولا شيء في لوجستك | `logistic:status`: صف معلّق ← `logistic:send`؛ `needs_attention` ← اقرأ `last_error` في صفحة الطلب؛ وتأكد أن البائع في القائمة وأن `LOGISTIC_ENABLED` مفعّل |
| `needs_attention` بسبب `cancel_refused:in_transit` أو `edit_refused:order_already_collected` | قفل متوقع: الكابتن استلم البضاعة. تواصل مع العمليات؛ والتحذير يزول وحده حين يقبل لوجستك تعديلًا لاحقًا أو تلغي العمليات |
| طلب المتجر لا يتبع لوجستك | `LOGISTIC_APPLY_STATUS` مطفأ، أو رابط الاستدعاء لا يصل، أو لا يوجد `queue:work`/المشغّل في لوجستك (الإشعارات مهام في الطابور). `logistic:status:sync` يستعلم عن الساكتة |
| `401` في كل نداء | عدم تطابق الرمز/الأسرار، أو انتهاء الرمز؛ أعد إصدار رمز المتجر |
| ظهر «انجراف في العقد» | تغيّر API لوجستك: راجعه ثم `logistic:contract:pin` |
| السكربت الحي يقول «المنفذ 8000 مشغول» | أوقف الخادم التجريبي والمشغّل أولًا |
| الاختبار ينتهي بـ0 ولا يعرض شيئًا | ذاكرة PHP؛ استعمل `php.ini` فيه `memory_limit=1G` |
| بقايا `E2E` بعد سكربت أُوقف | `select count(*) from users where email like 'e2e-%'` (المتجر)، وجدولا `admins`/`drivers` بأسماء `E2E …` (لوجستك)؛ احذفها أو أعد `logistic_step2_e2e.php` |

---

## 9. ما **لم** يُغطَّ (حتى لا تفترض العكس)

- **إرسال Firebase فعليًا إلى هاتف**: الاختبارات تثبت فقط أن مهمة الإشعار **صُفَّت**. تحتاج `queue:work` ورمز جهاز كابتن حقيقيًا.
- **تطبيق الكابتن** و**شاشات لوحة الموزّع**: اختُبرت عبر واجهاتها البرمجية لا بالنقر.
- **بوابات الدفع الحقيقية (Paymera)** والإنتاج الحقيقي (الشبكة وRedis وReverb).
- **رحلة طلب مدفوع مسبقًا كاملة حيًّا** (كون الرسم على المتجر تغطيه الاختبارات الآلية فقط).
- حدّ معروف: إعادة توزيع الكوبون على طلب **شقيق** بعد تعديل لا تُلحَظ.
- قرار مفتوح: المتجر لا يضيف رسم التوصيل إلى المبلغ الذي يطلبه من الزبون عند الباب بعد؛ والبوابة تُظهر الفرق كتنبيه.
