Saudi commerce · Salla · Inventory architecture

نقل مخزون طلبات Salla: غيّر الفرع دون بيع زائد

دليل إنتاج للتعامل مع نقل مخزون Salla كأمر قابل للتدقيق، والتعافي من النتائج المجهولة، ومطابقة كل Inventory Projection لاحقة.

المسار المرتبطهندسة التجارة الإلكترونية
عامل مستودع يستخدم قارئ باركود لجرد مخزون على رفوف معنونة داخل مركز لوجستي.
i

نقل مخزون طلب من فرع إلى آخر في Salla هو انتقال في حالة العمل، وليس تعديلًا شكليًا لاسم الفرع. فالعملية تغيّر موقع المخزون المرتبط بالطلب، وقد ينحرف ERP أوOMS أوقائمة الالتقاط أوتوافر الفروع إذا اعتبر التكامل أن نجاح HTTP هو نهاية المسار.

هذا شرح هندسي عملي مبني على الوثائق، وليس خبرًا أوإعلان منتج من Salla. الـEndpoint والـScopes وحقول الطلب وأكواد الاستجابة أدناه حقائق من وثائق Salla Merchant API الرسمية، وتم التحقق منها في 31 أكتوبر 2026. أما القفل وIdempotency والقراءة بعد الكتابة وIntegration Ledger وReconciliation فهي توصيات هندسية لتكاملات الإنتاج، وليست ادعاءات عن سلوك غير موثق لدى Salla.

الخلاصة أولًا

استخدم POST /admin/v2/orders/{order_id}/inventory/relocate بعد حل Branch IDs الفعلية والتحقق من Order Item IDs والكميات المطلوبة. نفّذ Serialization بقفل خاص بكل طلب، وأنشئ Operation Key داخليًا، واستدعِ الـEndpoint مرة واحدة، ثم اقرأ كميات الفرعين من جديد. إذا انتهت المهلة قبل وصول الاستجابة، فاعتبر النتيجة مجهولة: اقرأ الحالة الموثوقة قبل تقرير ما إذا كانت إعادة المحاولة آمنة.

اجعل Salla مصدر السلطة لتخصيص الطلب داخل Salla، بينما يحتفظ ERP أوOMS بسجل تكامل منفصل. تقارن Reconciliation الأدلة في النظامين وتفتح Exception عندما لا يعكس الفرع الوجهة الحركة المتوقعة. استجابة 200 دليل على قبول Salla للعملية الموثقة، وليست دليلًا على أن كل نظام لاحق حدّث نفسه.

المجالالسلطة الآمنةالدليل الواجب حفظه
نقل تخصيص الطلبSalla Relocation EndpointOrder ID والفرعان وItem IDs والكميات والوقت والاستجابة
صلاحية الفرعSalla Branches Read مع سياسة المتجرBranch ID والحالة وقدرة التخزين ونسخة السياسة
كمية Salla الحاليةProduct Quantities ReadBranch Filter وهوية العنصر والكمية ووقت الملاحظة
إسقاط ERP/OMSLedger النظام المستقبلExternal Movement ID والحالة وApplied Digest
قرار التعافيReconciliation WorkerBefore/After Snapshots وسبب الغموض وقرار المراجع

ابدأ بالعقد الموثق

توثق Salla عملية النقل بالشكل الآتي:

POST https://api.salla.dev/admin/v2/orders/{order_id}/inventory/relocate
Authorization: Bearer <token>
Content-Type: application/json

الـScope الموثق هو orders.read_write. ويحتوي المثال الرسمي على Source Branch ID وDestination Branch ID ومصفوفة items، وفي كل عنصر id وquantity:

{
  "source": 1923546554,
  "destination": 495787195,
  "items": [
    { "id": 123413414, "quantity": 2 }
  ]
}

تعرض الصفحة استجابة نجاح 200 وتوثق أيضًا 403 Forbidden و422 Parameter Error. لكنها لا توثق Idempotency-Key Header ولا Transaction تربط العملية مع ERP خارجي ولا طريقة تعافٍ محددة بعد Client Timeout. لذلك لا تفترض هذه الضمانات؛ ابنِ طبقة الأمان الناقصة داخل تكاملك.

لأغراض التحقق، توثق Salla GET /admin/v2/products/quantities مع products.read وBranch Query Parameter. يتضمن مثال الاستجابة هوية المنتج أوالعنصر وsku_id وsku وquantity وsold_quantity وunlimited_quantity وبيانات Variant. كما توثق GET /admin/v2/branches مع branches.read، ويعرض المثال هوية الفرع وحالته وبعض خصائص المخزون والتنفيذ.

هذه القراءات أساس Preflight محافظ وRead-back بعد الكتابة، لكنها لا تثبت أن Relocation Endpoint يستخدم Ledger داخلية بعينها.

مثّل النقل كأمر له أدلة

أنشئ Command Record داخليًا قبل أي كتابة. اجعله Immutable ما عدا Lifecycle Fields:

{
  "operation_key": "merchant-42:order-3155923424:relocate:v3",
  "merchant_key": "merchant-42",
  "order_id": "3155923424",
  "source_branch_id": "1923546554",
  "destination_branch_id": "495787195",
  "items": [
    { "order_item_id": "123413414", "quantity": 2 }
  ],
  "requested_by": "allocation-rule-7",
  "requested_at": "2026-10-31T17:10:00Z",
  "state": "prepared",
  "source_snapshot_digest": "sha256:...",
  "destination_snapshot_digest": "sha256:..."
}

هذا تصميم للتطبيق وليس Salla Payload. يمنع Operation Key إنشاء أمرين محليين لنفس Business Intent، لكنه لا يجعل الـEndpoint البعيد Idempotent. احفظ Exact Request Digest ولا تعِد استخدام المفتاح نفسه مع فروع أوعناصر أوكميات مختلفة.

استخدم Order Item IDs لأن Body الموثق يستخدم items[].id. لا تستبدلها تلقائيًا بنص SKU؛ فقد يكون SKU فارغًا أومتكررًا بين الأنظمة أومعاد الصياغة أومرتبطًا بـVariant بصورة مختلفة. احتفظ بـSKU كصفة للمطابقة، لا كهوية للأمر البعيد ما لم توثق العملية ذلك صراحة.

مخطط هندسي أصلي: يُجهز نقل مخزون Salla ويُقفل لكل طلب ويُرسل مرة ثم يُقرأ ويُطابق ويُنشر عبر Outbox. صورة الغلاف للمصورة Liz Roll/FEMA، ضمن الملكية العامة في الولايات المتحدة عبر Wikimedia Commons؛ قد تُغيّر أبعادها للعرض المتجاوب.
مخطط هندسي أصلي: يُجهز نقل مخزون Salla ويُقفل لكل طلب ويُرسل مرة ثم يُقرأ ويُطابق ويُنشر عبر Outbox. صورة الغلاف للمصورة Liz Roll/FEMA، ضمن الملكية العامة في الولايات المتحدة عبر Wikimedia Commons؛ قد تُغيّر أبعادها للعرض المتجاوب. اضغط لعرض أكبر

Preflight قبل أي كتابة

يجب أن يجيب Preflight عن خمسة أسئلة:

  1. هل هذا هو الطلب الصحيح والنية الحالية؟ ارفض الأمر القديم إذا تغير Allocation Rule أوOrder Status أوقرار الموظف بعد تجهيز الأمر.
  2. هل Source وDestination مختلفان ونشطان وقابلان لتخزين المخزون؟ اقرأ الفروع وطبّق سياسة التاجر؛ وجود الفرع لا يجعله مناسبًا لكل طلب.
  3. هل تنتمي كل Item IDs إلى الطلب؟ استخرجها من Order Read موثوقة، لا من SKU يكتبه مستخدم.
  4. هل الكميات موجبة ومحدودة بالحركة المطلوبة؟ ارفض الصفر والسالب والتكرار والقيم الكبيرة غير المتوقعة قبل الاتصال.
  5. هل يستطيع التكامل تفسير الحالة الحالية للفرعين؟ التقط Quantity Snapshots مع الوقت. إذا كانت Baseline غير متسقة أصلًا، اعزل الحركة بدل زيادة صعوبة التشخيص.

يعرض مثال List Branches حقولًا مثل status وis_stock وpickable وshippable وsafety_stock. تعامل معها كمدخلات للسياسة لا كمعادلة عامة. فقد يكون الفرع Pickable لكنه غير مسموح لهذا الطلب بسبب شركة الشحن أوحالة الحجز أوسياسة التشغيل.

تحتاج منتجات unlimited_quantity إلى سياسة صريحة. المقارنة الرقمية المصممة لمخزون محدود قد لا تعني شيئًا لهذه العناصر. ضع علامة Unlimited وتجنب اختراع معادلة خصم وإضافة لا يعد بها المصدر.

اقفل لكل طلب لا لكل متجر

قد يحاول عاملان نقل الطلب نفسه في الوقت نفسه: Allocation Rule يتفاعل مع المخزون، بينما يغير موظف فرع التنفيذ. Global Lock يحافظ على الصحة لكنه يقتل Throughput، وغياب القفل يسمح بأوامر متعارضة.

استخدم Distributed Lock أوCompare-and-Set Lease بمفتاح يجمع Merchant وOrder ID:

lock key = merchant_key + ":order:" + order_id
acquire a short lease
reload command and order intent
run preflight
send at most one relocation request
persist response or ambiguity
enqueue read-back
release lease

يجب أن يحتوي Lease على Owner Token وتجديد آمن. لا يجوز لعامل تحرير Lease لعامل آخر بعد انتهاء مدة قفله. اجعل Remote Call Timeout أقصر من مدة Lease، وسجل Owner في Diagnostics.

لا تستخدم Mutex واحدًا لكل المتجر. نقل طلبات مختلفة مستقل ويمكن تنفيذه بالتوازي ضمن حدود الـAPI. Rate Limiting وConcurrency Control وظيفتان مختلفتان: Token Bucket يضبط حركة الشبكة، بينما Order Lock يمنع انتقالين تجاريين متعارضين.

Timeout يعني نتيجة مجهولة

يمكن تقسيم النتائج إلى ثلاث فئات:

النتيجةما نعرفهالإجراء التالي
نجاح 200أعادت Salla استجابة النجاح الموثقةاحفظ Receipt ثم اقرأ وطبّق Reconciliation
403 أو422رُفض الطلبلا تعِد الطلب نفسه؛ افحص الصلاحيات والوصول وValidation Data
Timeout أوConnection Reset أوضياع الاستجابةقد يكون الخادم نفذ الحركة أو لم ينفذهاعلّم Unknown واقرأ الحالة ثم قرر

الاختصار الخطير هو Blind Retry فور Timeout. إذا نُفذ الطلب الأول وضاعت استجابته، فقد تطبق المحاولة الثانية حركة إضافية أوتعيد Validation Error مربكًا. ولأن الصفحة العامة التي راجعناها لا توثق Idempotency Key، لا يستطيع العميل افتراض أن تكرار Body آمن.

انقل الأمر إلى unknown وشغّل Recovery Read. قارن Source وDestination Evidence مع Preflight Snapshot وExpected Post-state. إذا طابقت الأدلة الحركة المتوقعة بوضوح ولم يظهر تغيير منافس، أغلق الأمر كـconfirmed_after_read. وإذا طابقت Baseline بوضوح، فقد تسمح السياسة بمحاولة مضبوطة بعد إعادة التحقق من الطلب. أما إذا كانت الأدلة مختلطة أوغيّر Actor آخر المخزون، فحوّل الحالة إلى Reconciliation يدوية أومحكومة بقواعد؛ لا تخمّن.

قد لا تكفي Branch-level Product Quantities لنسب Delta إلى طلب واحد عندما تحدث مبيعات أوتعديلات أخرى بالتزامن. لذلك يجب أن يجمع Recovery Record بين تخصيص الطلب الحالي وCommand Ledger والأوقات وDownstream Movement IDs، لا مجرد رقمين للكميات.

اقرأ بعد الكتابة وطابق الأنظمة اللاحقة

بعد نجاح موثق، أرسل Job للمطابقة بدل تحديث كل نظام خارجي داخل Request Handler. يقوم العامل بالآتي:

  1. يقرأ Product Quantities المطلوبة للفرعين المصدر والوجهة؛
  2. يحدّث Order أوAllocation View التي يستخدمها التكامل؛
  3. يقارن النتيجة مع Prepared Command وPreflight Snapshots؛
  4. يضيف Append-only Integration Ledger Entry؛
  5. ينشر Outbox Event إلى ERP وOMS وWMS وPicking Consumers؛
  6. يتحقق من كل Downstream Projection بصورة مستقلة؛
  7. يغلق العملية عندما تستوفي الأدلة السياسة.

يمكن أن تحمل Outbox Message رقم العملية وOrder ID وBranch IDs وItem IDs والكميات وSource Receipt. ينفذ كل Consumer Deduplication بمفتاح يجمع Operation Key وDestination System. وإذا انتهت مهلة Downstream Write، فهذه أيضًا نتيجة مجهولة: ابحث بالـExternal Reference قبل إنشاء Stock Movement ثانية.

افصل Accounting عن Observation. قراءة كمية Salla هي Provider State حالية. Integration Ledger دليل على الأوامر والقرارات. وERP Stock Ledger هو النموذج المحاسبي لـERP. إجبار رقم على الكتابة فوق الآخر دون تصنيف الفرق قد يخفي Shrinkage أوطلبات متأخرة أوManual Adjustments أوMapping Bugs.

State Machine عملية للمطابقة

استخدم حالات صريحة بدل Boolean:

prepared
  -> preflight_failed
  -> sending
sending
  -> accepted
  -> rejected
  -> unknown
accepted
  -> reconciling
unknown
  -> reconciling
reconciling
  -> confirmed
  -> exception
exception
  -> reviewed
  -> compensated

لا تنقل unknown مباشرة إلى failed؛ فـUnknown تعني نقص الأدلة لا الفشل. وكذلك لا تعتبر accepted مكتملة قبل مطابقة الأنظمة المهمة للعمل.

Compensation هي Business Command جديدة وليست Database Rollback. إذا قرر الموظف إعادة المخزون، أنشئ عملية مراجعة جديدة بعكس الفرعين وبأدلتها الخاصة. احتفظ بالأمر الأصلي وسبب التعويض.

أفضل الممارسات

  • امنح كل Component أقل Scope يحتاجه: الكاتب orders.read_write، وقراءة المطابقة products.read، واكتشاف الفروع branches.read.
  • ضع هوية Merchant داخل كل Lock وOperation Key وLedger Row وMetric.
  • استخرج Branch وOrder Item IDs من قراءات موثوقة، ولا تثق في Free-form Input.
  • اقفل لكل Order وأعد التحقق من Intent بعد الحصول على القفل.
  • احفظ Before Snapshots وExact Request Digest والاستجابة وAfter Snapshots.
  • افصل Remote Acceptance عن End-to-end Confirmation.
  • وجّه Ambiguous Outcomes إلى Read-before-retry Recovery.
  • استخدم Transactional Outbox لتحديث ERP/OMS/WMS وStable External References.
  • أنشئ Alert للأوامر العالقة في unknown أوreconciling.
  • قِس Relocation Age وUnknown Outcome Rate وReconciliation Lag وException Rate وDuplicate Suppression.
  • احجب Bearer Tokens وCustomer Data عن Logs، واحتفظ بأقل دليل تشخيصي.

Anti-patterns والقيود

  • إعادة Relocation فور Timeout وافتراض أن الطلب الأول فشل.
  • اعتبار 200 إثباتًا على تحديث ERP وOMS وقوائم المستودع.
  • إرسال SKU حيث يتوقع Body الموثق Item IDs.
  • النقل من الفرع نفسه إلى نفسه أوالسماح بـDuplicate Item Lines.
  • تطبيق معادلة Finite Stock على unlimited_quantity بلا سياسة.
  • تشغيل قاعدتي Allocation على الطلب نفسه دون Serialization.
  • الكتابة فوق ERP Stock بقراءة Salla Quantity دون تفسير Delta.
  • اعتبار قراءة Quantity ناقصة واحدة دليلًا على فشل النقل.
  • حذف Command Evidence بعد Compensation.

لا توثق الصفحات العامة التي راجعناها Idempotency Header ولا Change Event محددًا لهذه العملية ولا Transaction تمتد بين Salla والأنظمة الخارجية. يستطيع التكامل خفض المخاطر وجعل النتيجة قابلة للتدقيق، لكنه لا يستطيع اختراع Cross-system Atomicity لا تعرضها الـAPIs.

قائمة تنفيذ

  1. امنح الكاتب orders.read_write وافصل Read Credentials حيثما أمكن.
  2. استخرج Order Item وBranch IDs من قراءات حالية موثوقة.
  3. أنشئ Immutable Command Record مع Operation Key فريد.
  4. احصل على Merchant-and-order Lock وأعد التحقق من النية.
  5. التقط Source وDestination Snapshots.
  6. استدعِ Relocation Endpoint مرة واحفظ النتيجة كاملة.
  7. أرسل Timeout إلى unknown واقرأ قبل إعادة المحاولة.
  8. طابق Salla State وأضف Integration Ledger Entry.
  9. انشر التغييرات اللاحقة عبر Idempotent Outbox.
  10. اختبر Concurrent Commands وPartial Lines و403 و422 وTimeout وUnlimited Stock وCompensating Moves.

اقرأ أيضًا: مطابقة حجوزات طلبات Salla مع التقويم، وConditional Webhooks وضوابط المطابقة، وقواعد الإسناد التلقائي لطلبات Salla، ومركز هندسة التجارة الإلكترونية.

المراجع الأساسية

إعداد: Noor Yasser

المراجع الرسمية

تدعم هذه المراجع سلوك الأدوات المذكورة. الأمثلة وقرارات التصميم توضيحية، ويجب تكييفها مع متطلبات المشروع وإصداراته.

إعداد: Noor Yasser

من القرار إلى التنفيذ

تعمل على تحدٍ تقني مشابه؟

أساعد الفرق على تحويل القرار المعماري إلى نطاق واضح وتنفيذ يمكن تشغيله ومراجعته بثقة.

احجز لقاءً لمدة ٣٠ دقيقةالخدمة المرتبطةهندسة الأنظمة الخلفية وتكاملات APIمشروع من الأعمالمنصة اللوجستيات