تخطَّ إلى المحتوى

حركات المخزون

نموذج الحركات الملحَقة فقط، وكتابة حركة، وحدث الحركة، ولماذا الكتابة المطلقة ممنوعة.

آخر تحديث 2 أيلول 2026قراءة 1 د
في هذه الصفحة

هذه الصفحة لمن يزامن مخزوناً أو يسجّل تلفاً أو مرتجعات. المخزون في دكان دفتر حركات ملحَق فقط؛ لا يوجد رقم مخزون تكتبه، بل حركات تضيفها ويحتسب الخادم الرصيد منها.

النموذج#

movement-object.jsonJSON
{
  "id": "0a1b2c3d-0001-4e8f-9b70-2d1c3e4f5a6b",
  "sequence": 418,
  "variant_id": "c0ffee00-0001-4e8f-9b70-2d1c3e4f5a6b",
  "location_id": "10c00000-0001-4e8f-9b70-2d1c3e4f5a6b",
  "delta": -2,
  "stock_after": 23,
  "reason": "damage",
  "occurred_at": "2026-08-18T16:10:00.000Z"
}
الحقل المعنى
sequence تسلسل رتيب لكل متجر؛ رتّب به الحركات
variant_id المتغير؛ قد يكون null لحركات مرتبطة بمتغير محذوف
location_id الموقع (لكل متجر موقع افتراضي وربما مستودعات)
delta التغيير الموقّع؛ لا يكون صفراً أبداً
stock_after الرصيد في هذا الموقع بعد الحركة، كما احتسبه الخادم
reason سبب الحركة
occurred_at وقت الحركة بصيغة RFC 3339

أسباب الحركات التي يكتبها التطبيق: correction وinitial وreturn وdamage. تظهر في القراءة أسباب أخرى تكتبها المنصّة (بيع، إلغاء، تحويل)؛ عامل reason كنص مفتوح عند القراءة.

لماذا الكتابة المطلقة ممنوعة#

كتابة «الرصيد = 40» تمحو ما حدث بين قراءتك وكتابتك: بيع من واجهة المتجر، أو نقطة بيع، أو تطبيق آخر. الحركة delta: +5 بسبب correction تُجمع بأمان مع كل ما سبقها، وتترك أثراً يراجعه التاجر. لذلك لا تقبل الواجهة رقماً مطلقاً أبداً.

اكتب حركة#

يتطلب inventory:write وIdempotency-Key:

Shell
curl -X POST https://dukkan.one/platform-api/v1/inventory/movements \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Idempotency-Key: damage-SHIPMENT_ID-1" \
  -H "Content-Type: application/json" \
  -d @movement.json
inventory-movement.jsonJSON
{
  "variant_id": "c0ffee00-0001-4e8f-9b70-2d1c3e4f5a6b",
  "location_id": "10c00000-0001-4e8f-9b70-2d1c3e4f5a6b",
  "delta": -2,
  "reason": "damage",
  "note": "Broken in transit"
}
  • delta بين −1,000,000 و1,000,000 وليس صفراً.
  • reason من correction أو initial أو return أو damage.
  • note اختياري حتى 500 حرف.
  • الاستجابة 201 تحمل الحركة المسجّلة؛ يظهر stock_after فيها فقط عندما يحمل التثبيت inventory:read أيضاً.
  • حركة تُنزل الرصيد المتاح تحت الكمية المحجوزة تعيد 409، وكذلك حركة على منتج غير مُدار مخزونياً.

اقرأ الحركات#

Shell
curl "https://dukkan.one/platform-api/v1/inventory/movements?limit=100" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

يتطلب inventory:read. تُصفَّح القائمة بمؤشر مبهم؛ للمزامنة التزايدية احفظ آخر sequence عالجته وتجاهل ما دونه.

حدث inventory.movement_created#

يصل لكل حركة، من أي مصدر، إلى الاشتراكات التي تحمل inventory:read:

event-inventory-movement.jsonJSON
{
  "movement_id": "0a1b2c3d-0001-4e8f-9b70-2d1c3e4f5a6b",
  "variant_id": "c0ffee00-0001-4e8f-9b70-2d1c3e4f5a6b",
  "location_id": "10c00000-0001-4e8f-9b70-2d1c3e4f5a6b",
  "delta": -2,
  "stock_after": 23,
  "reason": "damage"
}

يحمل الحدث stock_after مباشرة، فلا تحتاج إلى استدعاء إضافي للرصيد في هذا الموقع. رتّب الأحداث بـ sequence الغلاف كما في Webhooks.

الإرجاع مع الاسترداد#

عند استرداد مبلغ لأسطر محدّدة، يمكنك إرجاع الكميات إلى المخزون في العملية نفسها بخيار restock: { "location_id": "…" } في POST /orders/{id}/refunds. يتطلب ذلك lines في الاسترداد ونطاق inventory:write؛ تُتجاوز المنتجات غير المُدارة مخزونياً بصمت. التفاصيل في المال بالوحدات الصغرى.