أضافت سلة في 14 أكتوبر 2026 الحقل النصي actual_picked_up_at إلى Update Shipment Details، ليصبح للتكاملات مسار موثق لتسجيل الوقت الفعلي الذي استلم فيه الناقل الشحنة. يبدو التغيير صغيرًا، لكنه يسد فجوة تشغيلية مهمة: «جاهزة للاستلام» و«تم تعيين الناقل» و«استلمها الناقل فعليًا» حقائق مختلفة. يحتاج التاجر والمستودع والناقل وخدمة العملاء إلى الحقيقة الأخيرة لقياس تأخر التسليم للناقل والتحقيق في الطرود المفقودة.
هذا شرح عملي للتوثيق، وليس ادعاءً بأن سلة أطلقت منتجًا كبيرًا اليوم. الحقل وعقد Endpoint مستندان إلى Changelog وتوثيق الشحنات الرسميين لدى سلة، وتم التحقق منهما في 25 أكتوبر 2026. أما Event Ledger وقواعد التحقق ومسار المطابقة أدناه فهي توصيات هندسية.
الخلاصة أولًا
تعامل مع actual_picked_up_at كحدث أعمال شاهده الناقل، لا كوقت إرسال Worker لطلب API. احفظ ملاحظة الاستلام قبل استدعاء سلة، ووحّد منطقتها الزمنية، وأرسلها مع status المطلوب، ثم اقرأ الشحنة مجددًا قبل اعتبار المزامنة مكتملة. لا تصنع الوقت من إنشاء البوليصة أو موعد الاستلام المخطط أو انتقال حالة محلي.
| الوقت | ما يجب أن يعنيه | ما يجب ألا يعنيه |
|---|---|---|
label_created_at | إنشاء Label أوAWB | مغادرة الطرد للمستودع |
pickup_scheduled_at | التخطيط لزيارة الناقل | وصول الناقل أوقبوله العهدة |
actual_picked_up_at | رصد استلام الناقل الفعلي | نجاح Sync Job فقط |
actual_delivered_at | رصد التسليم الفعلي | مجرد تحويل الطلب إلى مكتمل |
يتضمن مثال Update Shipment Details في توثيق سلة كلا من actual_picked_up_at وactual_delivered_at. كما يوثق أن status مطلوب وأن Scope هو shipping.read_write. هذه حقائق من المورد؛ أما جمع الدليل ومنع الكتابات المتعارضة فمسؤولية التكامل.
مكان الحقل في التصميم
قسّم الشحنة إلى ثلاث طبقات:
- Observations: حقائق ثابتة تصل من Webhook للناقل أومسح المستودع أوتطبيق السائق أوإجراء Operator معتمد.
- Projection: أفضل حالة حالية مشتقة من Observations المقبولة.
- Commands: محاولات تحديث سلة أوأي نظام بعيد.
وقت الاستلام يدخل أولًا في Observation. إذا أفاد Webhook للناقل أن الاستلام حدث 14:08، فاحفظ الحدث الخام ومعرف شحنة المزود ووقت الحدوث ووقت الاستلام والمصدر وPayload Hash ونتيجة التحقق. بعد ذلك اشتق Projection محلية وضع تحديث سلة في Queue. يبقى الدليل محفوظًا لو انتهت مهلة الاتصال بالنظام البعيد أوتكرر الطلب.
يمكن أن يبدو السجل الأدنى هكذا:
create table shipment_observations (
merchant_id bigint not null,
shipment_id bigint not null,
source text not null,
source_event_id text not null,
event_type text not null,
occurred_at timestamptz not null,
received_at timestamptz not null default now(),
payload_hash text not null,
verification_state text not null,
primary key (merchant_id, source, source_event_id)
);يجب أن يكون Unique Boundary مرتبطًا بالتاجر والمصدر؛ فقد يكون معرف حدث الناقل فريدًا داخل حساب ناقل واحد فقط. إن لم يقدم المزود Event ID ثابتًا، فأنشئ Fingerprint مدروسًا من التاجر ومعرف شحنة المزود ونوع الحدث ووقت الحدوث الموحد وPayload Hash، واحتفظ بالملاحظة الخام للتدقيق.
حدد ترتيب مصادر الحقيقة
ليست كل الأوقات متساوية في الثقة. استخدم سياسة أولوية صريحة:
| المصدر | الدليل المعتاد | الثقة الافتراضية |
|---|---|---|
| Carrier Webhook موقّع أوAPI | Provider Event ID ووقت الناقل | أعلى دليل آلي |
| مسح المستودع | Device وOperator وDock ومسح الطرد | دليل عهدة قوي عند ضبط العملية |
| تطبيق السائق | هوية السائق والمسار ووقت الجهاز | مفيد مع فحص الساعة والتعيين |
| إجراء التاجر يدويًا | المستخدم والسبب وAudit Trail | استثناء مسموح لا Overwrite صامت |
| ساعة Integration Job | وقت المعالجة فقط | ليست حقيقة استلام أبدًا |
إذا تعارض مصدران مقبولان، فلا تحتفظ بالأحدث بصمت. سجل Conflict يضم الملاحظتين وسبب الحل. قد يصل حدث متأخر ليصف استلامًا أقدم؛ Arrival Order ليس Business Order.
وحّد الوقت قبل الكتابة
توثق سلة الحقل كـString وتعرض مثالًا بشكل تاريخ ووقت. لا تنص الصفحة على وجود Timezone Offset داخل قيمة الطلب. لذلك احتفظ داخليًا بالقيمة الموثوقة كـtimestamptz أوUTC Instant مكافئ مع التمثيل الأصلي للمزود. نسّق القيمة المرسلة تمامًا كما يقبل عقد سلة الحالي ومتجر الاختبار الذي تحققت منه؛ لا تفترض تعاملًا غير موثق مع Offset.
طبّق هذه القواعد قبل Dispatch:
- ألا يكون وقت الاستلام بعد وقت تسليم مؤكد؛
- ألا يسبق إنشاء الشحنة بشكل غير منطقي؛
- عزل قيمة مستقبلية تتجاوز هامش Clock Skew صغيرًا؛
- تطابق هوية الناقل أوالمستودع مع Mapping الشحنة؛
- عدم استبدال مصدر أعلى ثقة بمصدر أدنى دون مراجعة؛
- بقاء المنطقة الزمنية الأصلية والقيمة الخام متاحتين للتحقيق.
تؤثر Daylight Saving والغموض المحلي مع النواقل العابرة للحدود. السعودية UTC+3 طوال العام، لكن نظام المزود الذي أصدر الحدث قد لا يكون كذلك. وحّد الوقت من Timezone المعلن للمصدر، لا من Timezone المتجر افتراضًا.
استخدم Update Command آمنة عند التكرار
أنشئ Command Record قبل PUT /shipments/{shipment_id}. يمكن أن يتكون Business Key من التاجر ومعرف شحنة سلة ونوع العملية ومعرف Pickup Observation المقبولة. تنتقل Command عبر pending وdispatching وobserved_succeeded وobserved_failed وoutcome_unknown.
Pickup Observation موثقة
-> اشتق Shipment Projection
-> أنشئ Update Command واحدة
-> PUT مع status المطلوب + actual_picked_up_at
-> اقرأ Shipment Details
-> أغلق Command بعد تطابق مرصود فقطحتى لو أعاد PUT نجاحًا موثقًا، احتفظ بـCommand وResponse Correlation. وإذا انقطع الاتصال بعد إرسال الطلب، فلا تنشئ عملية أعمال ثانية فورًا. اقرأ Shipment Details أولًا. أعد محاولة Command نفسها فقط عندما تثبت الحالة البعيدة أن القيمة المطلوبة لم تقبل، ويسمح عقد API بالتكرار.
يتطلب Endpoint قيمة status. لا تدع مزامنة Pickup Timestamp تخترع حالة الشحنة أوتعيدها للخلف. ابن Request من Shipment Projection حديثة ومصرح بها وانتقال مسموح. وإذا كان التكامل لا يملك الحالة، فحدد الملكية صراحة بدل نسخ قيمة قديمة من Cache.
افصل الاستلام عن التجهيز ووعد العميل
يجيب دليل الاستلام عن «متى انتقلت العهدة إلى الناقل؟». لكنه لا يثبت:
- دخول الطرد أول Hub للناقل؛
- توافر Tracking عامًا؛
- الالتزام بموعد Checkout؛
- تحصيل Cash on Delivery؛
- اكتمال مطابقة المخزون أوالمحاسبة.
استخدم الوقت لقياس تسليم المستودع للناقل وبدء المؤقتات التشغيلية الصحيحة. مثال: أرسل تنبيهًا عندما تبقى الشحنة Ready دون Pickup Observation موثقة بعد سياسة التاجر. وبعد الاستلام استخدم Tracking وحالة الشحنة لمراقبة In Transit. لا ترسل «تم شحن طلبك» لمجرد إنشاء Label.
Reconciliation تكتشف الأحداث المفقودة
قد تتأخر Webhooks والمسحات أوتتكرر أوتغيب. شغّل Reconciliation محدودة تقارن:
- Pickup Observations المحلية المقبولة؛
- Commands المحلية والنتائج المجهولة؛
- Shipment Details في سلة للشحنة المطابقة؛
- دليل Tracking أوPickup لدى الناقل؛
- Warehouse Dispatch Ledger.
صنّف الاختلاف بدل الكتابة فوقه:
| الاختلاف | التصرف الآمن |
|---|---|
| Pickup محلية وسلة بلا قيمة | اقرأ ثم أعد Command نفسها إن كان ذلك آمنًا |
| سلة تحتوي Pickup والمحلي يفتقدها | استوردها كـExternal Observation وحقق في الملكية |
| القيمتان متطابقتان | علّمها Converged |
| القيمتان مختلفتان | اعزلها لمراجعة الأولوية والدليل |
| Delivery موجود وPickup مفقود | Backfill من دليل حقيقي فقط، ولا تصنع وقتًا |
تؤثر Pagination وRate Limits وعدالة المستأجرين عند مطابقة متاجر كثيرة. أعط كل تاجر Budget محدودًا، واحفظ Checkpoint للتقدم، وقدّم Unknown Outcomes القديمة على الشحنات الحديثة السليمة.
Observability تفيد المشغل
اعرض Shipment ID وOrder Reference وCarrier Reference وSource Event ID وPickup Instant وSource Timezone وحالة Command وعدد المحاولات وآخر Read-back. راقب:
- عمر Ready-to-pickup؛
- تأخر Pickup الموثقة عن وقت جاهزية المستودع؛
- تحديثات Pickup التي تنتظر Read-back؛
- النتائج البعيدة المجهولة؛
- تعارضات الوقت حسب المصدر؛
- شحنات Delivered بلا Pickup Evidence؛
- عمر Reconciliation Backlog.
لا تسجل أرقام هواتف العملاء أوالعناوين الكاملة أوBearer Tokens أوLabels أوPayloads الخام في Logs مفتوحة. اربط المشغل بدليل محمي بالصلاحيات.
أفضل الممارسات وAnti-patterns
أفضل الممارسات
- التقط الاستلام عند حد العهدة الفعلي بين المستودع والناقل.
- احتفظ بالحدث الأصلي وTimezone ونتيجة التحقق.
- استخدم Durable Command واحدة لكل Pickup Observation مقبولة.
- أرسل
statusمن انتقال حديث تملكه الخدمة. - اقرأ الشحنة بعد الكتابات وبعد Unknown Outcomes.
- طابق أدلة سلة والناقل والمستودع دوريًا.
- سجل التصحيحات اليدوية مع Actor والسبب والقيمة السابقة.
Anti-patterns
- وضع
now()كوقت استلام عند تشغيل Sync Job. - اعتبار إنشاء Label أوموعد الاستلام عهدة فعلية.
- جعل Webhook مكرر ينشئ Remote Mutation جديدة.
- استبدال وقت ناقل موثوق بوقت يدوي أحدث.
- إعادة PUT انتهت مهلته بشكل أعمى.
- افتراض أن كل Datetime String تحمل Offset دون نص في العقد.
- استخدام Pickup كدليل تسليم أوSettlement أوإكمال مخزون.
خلاصة التنفيذ
- أضف نوع Pickup Observation ثابتًا وسياسة أولوية للمصادر.
- وحّد وقت المزود إلى UTC مع الاحتفاظ بالقيمة الخام والمنطقة الزمنية.
- تحقق من Mapping الشحنة وTemporal Invariants.
- أنشئ Salla Update Command آمنة عند التكرار.
- أرسل
actual_picked_up_atمعstatusالمطلوب تحتshipping.read_write. - اقرأ Shipment Details ولا تغلق إلا بعد تطابق مرصود.
- طابق النتائج المفقودة والمتعارضة والمجهولة.
- راقب Handoff Lag دون كشف بيانات العميل أوالاعتماد.
اقرأ أيضًا: State Machine قابلة للتعافي لشحنات سلة، ووعود توصيل سلة الموثوقة، واستعادة Webhooks في سلة وزد، ومركز هندسة التجارة الإلكترونية.
المراجع الأساسية
- Salla Merchant API changelog
- سلة — Update Shipment Details
- سلة — Shipment Details
- سلة — List Shipments
- Wikimedia Commons — Loading palletized cargo inside a shipping container
- Creative Commons Attribution 4.0
المراجع الرسمية
تدعم هذه المراجع سلوك الأدوات المذكورة. الأمثلة وقرارات التصميم توضيحية، ويجب تكييفها مع متطلبات المشروع وإصداراته.
إعداد: Noor Yasser
تعمل على تحدٍ تقني مشابه؟
أساعد الفرق على تحويل القرار المعماري إلى نطاق واضح وتنفيذ يمكن تشغيله ومراجعته بثقة.




