تخط وانتقل إلى المحتوى الرئيسي

DZBuild POS

كيف يرتبط برنامج الصندوق المجاني DZBuild POS على ويندوز بالمتجر، والنداءات التي يرسلها للمنتجات والصور والمخزون ووثائق البيع والطلبات والزبائن وتدفق الأحداث.

بقلم: Support

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

لا تجيب هذه النقاط إلا الرموز الصادرة للصندوق. مفتاح API الشخصي أو رمز التطبيق يتلقى 403 على المسارات الخاصة بالصندوق، ورمز الصندوق يتلقى 403 على كل مسار خارج قائمته.

لمن هو

  • لأصحاب المتاجر الذين يبيعون في محل وفي متجرهم على DZBuild. صاحب المتجر وحده يستطيع ربط صندوق؛ أعضاء الفريق لا يستطيعون.

  • لكل الخطط. الصندوق ليس مفتاح API، فلا يحتاج خطة Enterprise ولا يأخذ مكان مفتاح.

  • بعد تسجيل أول صندوق تظهر إضافة DZBuild POS في لوحة التحكم مع الصناديق المرتبطة وزر الفصل وآخر المبيعات والمرتجعات وإغلاقات Z. الرابط https://dzbuild.com/dashboard/connected-devices يفتح هذه الصفحة.

كيف يرتبط الصندوق

  • الاكتشاف: GET https://dzbuild.com/.well-known/oauth-authorization-server (RFC 8414).

  • الصندوق عميل OAuth 2.0 عام اسمه dzbuild-pos-windows، بلا سرّ. يُقبل S256 وحده في PKCE، والتحويل يكون إلى http://127.0.0.1:PORT/oauth/callback على أي منفذ.

  • يدخل صاحب المتجر من متصفح النظام ويختار المتاجر التي يستعملها الصندوق، حتى 10 متاجر. ويمكن ربط الصندوق برمز أيضاً: يعرض الصندوق رمزاً، ويكتبه صاحب المتجر في https://dzbuild.com/device من هاتفه.

  • رمز الوصول يبدأ بـ dzpos_ ويدوم 15 دقيقة. رمز التحديث يُستبدل عند كل استعمال وينتهي بعد 30 يوماً دون استعمال أو 180 يوماً في المجموع. إرسال رمز تحديث قديم من جديد ينهي الربط.

  • كل نداء يحمل X-DZ-Store مع رقم المتجر، ما عدا GET /v1/me. المتجر الذي لم يختره صاحبه يُرجع 403.

  • كل POST وPATCH وDELETE يحمل Idempotency-Key، بالقواعد المذكورة في التكرار الآمن.

  • الحدود: 120 طلباً في الدقيقة لكل صندوق و600 لكل متجر. حصة الواجهة البرمجية الشهرية لا تنطبق على الصناديق.

  • فصل الصندوق من لوحة التحكم ينهي الربط: التحديث التالي يُرجع 400 invalid_grant ونبضة الاتصال التالية 410 device_revoked.

الصلاحيات الـ 19

يطلب الصندوق الصلاحيات الـ 19 دائماً، وتمنحها DZBuild كلها دائماً.

الصلاحيات

ما يستطيعه الصندوق

openid وprofile وoffline_access

معرفة من ربطه والبقاء مرتبطاً

store:read

قراءة متاجر الربط ولغتها وخطتها وحدّ منتجاتها

products:read وproducts:write

قراءة المنتجات وإنشاؤها وتعديلها على دفعات وإضافة الصور

inventory:read وinventory:write

قراءة مخزون المنتجات وتعديله

orders:read وorders:write

استقبال طلبات المتجر وأخذ طلب وتحريكه وإلغاؤه

customers:read

التحقق من رقم هاتف قبل البيع

pos:sales:read وpos:sales:write

تسجيل المبيعات والمرتجعات وإغلاقات Z

locations:read وlocations:write

تسجيل المحل الذي يوجد فيه الصندوق

backups:read وbackups:write

محجوزة: النسخ الاحتياطية غير متاحة

devices:self

تسجيل الصندوق وإرسال نبضات الاتصال وفك الربط

events:read

قراءة تدفق التغييرات

النقاط

الطريقة والمسار

ما تفعله

GET /v1/me

صاحب المتجر ومتاجر الربط

GET /v1/store

المتجر المختار: الاسم واللغة والعملة DZD وتوقيت خصم المخزون والخطة وحدّ المنتجات

POST /v1/devices وGET /v1/devices

تسجيل الصندوق (سطر واحد لكل صندوق ومتجر) وعرض الصناديق

POST /v1/devices/{id}/heartbeat

كل 15 دقيقة: الإصدار والإرسالات المنتظرة والفاشلة

DELETE /v1/devices/{id}

فك ربط هذا الصندوق

GET /v1/locations وPOST /v1/locations

المحل الذي يوجد فيه الصندوق

POST /v1/products/batch

إنشاء أو تعديل حتى 100 منتج

GET /v1/products وGET /v1/products/{id}

المنتجات المعدّلة منذ تاريخ معيّن، ومنتج واحد

POST /v1/media/uploads وPOST /v1/products/{id}/images

تذكرة الصورة، ثم ربط الصورة المرفوعة

POST /v1/inventory/adjustments/batch

حتى 500 تثبيت أو تغيير للمخزون

POST /v1/pos/sales وPOST /v1/pos/sales/{sale_id}/refunds وPOST /v1/pos/closures

المبيعات والمرتجعات وإغلاقات Z

GET /v1/orders وGET /v1/orders/{id}

طلبات المتجر بصيغة الصندوق

POST /v1/orders/{id}/claim وPATCH /v1/orders/{id} وPOST /v1/orders/{id}/cancel

أخذ طلب وتحريكه وإلغاؤه

GET /v1/customers?phone=

مؤشرات رقم هاتف واحد

GET /v1/events

تدفق التغييرات

بعض المسارات مشتركة مع مفاتيح API (المنتجات والطلبات والزبائن). الصندوق يتلقى الصيغ المذكورة في هذه الصفحة، ومفتاح API يحتفظ بالصيغ المذكورة في قسم الموارد.

دفعة المنتجات

تأخذ POST /v1/products/batch الحقل items، حتى 100 عنصر. لكل عنصر external_id الخاص بالصندوق وname وsku وbarcode اختياريان وpricing.price كنص بخانتين عشريتين ("4500.00") وinventory.track_stock وstatus (active أو draft أو archived) وcategory اختيارية لها external_id وname خاصان بها.

  • يعدّل العنصر المنتج المرتبط مسبقاً بـ external_id الخاص به. وإن لم يوجد، يتبنّى منتجاً بلا متغيرات له نفس sku وغير مرتبط بعد. وإن لم يوجد، ينشئ منتجاً بمخزون 0.

  • يُعثر على الفئة بـ external_id الخاص بها، أو تُنشأ من اسمها.

  • تذكر الاستجابة كل عنصر: external_id وid وstatus (created أو updated) وerror: null. العنصر المرفوض يحمل كائن error ولا يحمل id ولا status.

  • حدّ الخطة: عندما يملك المتجر عدد المنتجات النشطة الذي تسمح به خطته، فإن الدفعة التي تنشئ منتجاً، مسودة كان أو لا، تُرجع 402 product_limit_reached. العناصر التي سبقته تبقى مكتوبة. وتحويل منتج موجود إلى active بعد الحدّ خطأ على ذلك العنصر وحده.

  • الدفعة لا تضبط المخزون أبداً. المخزون يمرّ عبر نداء التعديلات.

الصور

  1. POST /v1/media/uploads مع filename وcontent_type (image/jpeg أو image/png أو image/webp) وsize (حتى 8 ميغابايت) وsha256. تحمل الاستجابة media_id ورابطاً موقّعاً upload_url صالحاً 10 دقائق.

  2. يرسل الصندوق البايتات الخام بـ PUT إلى upload_url، دون ترويسات DZBuild.

  3. POST /v1/products/{id}/images مع media_id وposition يربط الصورة. يجب أن يطابق الحجم وsha256 التذكرة، وإلا يُرجع النداء 422 media_mismatch. التذكرة المجهولة أو المنتهية تُرجع 404 media_not_found. يحمل المنتج حتى 20 صورة.

المخزون

تأخذ POST /v1/inventory/adjustments/batch حتى 500 عنصر. يذكر كل عنصر product_external_id وtarget: "product" وإما set (قطع كاملة) وإما delta، وreason (pos_sale أو pos_return أو restock أو count أو loss) وref فريداً.

  • لا يُعدَّل إلا مخزون المنتجات التي تتابع المخزون على مستوى المنتج. المنتج الذي له مخزون لكل متغير يُرجع خطأ العنصر variant_product، والذي لا يتابع المخزون not_tracked، والمنتج الذي لم يعد موجوداً unknown_product.

  • تذكر الاستجابة كل عنصر بـ ref مع status إما ok وإما error.

  • تغييرات مخزون الصندوق لا تظهر أبداً في سجل تغييرات لوحة التحكم ولا تعرض تراجعاً.

وثائق الصندوق

تسجّل POST /v1/pos/sales تذكرة أو فاتورة أو وصل تسليم، وPOST /v1/pos/sales/{sale_id}/refunds وصل إرجاع أو إشعاراً دائناً على ذلك البيع، وPOST /v1/pos/closures إغلاق Z بمجاميعه وبصماته.

  • تُحفظ الوثائق كما أُرسلت ولا تتغير أبداً: لا يوجد مسار تعديل أو حذف.

  • يُرجع البيع 201 مع {"id": 99120, "stock_applied": false}. المخزون يمرّ عبر نداء التعديلات، ولا يمرّ أبداً عبر وثيقة.

  • وثائق الصندوق منفصلة عن الطلبات. لا تُحسب في حدّ الطلبات الشهري للمتجر، ولا تُرسل أي إشعار، ولا تصل أبداً إلى Google Sheets ولا إلى webhooks.

  • المبالغ نصوص بخانتين عشريتين، والكميات أرقام بثلاث خانات عشرية على الأكثر، مع حتى 500 سطر و20 دفعة في الوثيقة.

  • إرسال وثيقة سُجّل external_id الخاص بها من قبل يُرجع 409 already_exists مع الرقم المسجّل في error.details.id. يعدّ الصندوق ذلك نجاحاً.

  • المرتجع على بيع متجر آخر يُرجع 404 not_found.

الطلبات

  • تعطي GET /v1/orders?updated_since=... وGET /v1/orders/{id} طلبات المتجر بصيغة الصندوق مع منتجاتها. order_number هو الرقم القصير للمتجر إن وُجد.

  • POST /v1/orders/{id}/claim مع device_id وterminal: أول صندوق يأخذ الطلب. الصندوق نفسه إذا أخذه من جديد يتلقى 200، وأي صندوق آخر يتلقى 409 order_claimed.

  • PATCH /v1/orders/{id} مع status يتطلب أخذ الطلب (409 claim_required في غير ذلك). الانتقالات المسموحة: من pending أو confirmed إلى processing أو shipped أو delivered، ومن processing إلى shipped أو delivered، ومن shipped إلى delivered. أي انتقال آخر يُرجع 409 transition_not_allowed.

  • تأخذ POST /v1/orders/{id}/cancel الحقل reason (out_of_stock أو customer_unreachable أو duplicate أو other) وnote اختيارية حتى 500 حرف. يعود المخزون حسب قواعد مخزون المتجر. إذا كان صندوق آخر قد أخذ الطلب، يُرجع الإلغاء 409 order_claimed.

  • تغيير الحالة من الصندوق يشغّل نفس الخطوات التي يشغّلها تغيير من لوحة التحكم، ومنها الإشعارات وتحديث Google Sheets.

الزبائن

تُرجع GET /v1/customers?phone=0550123456 صفحة فيها عنصر واحد على الأكثر: id وis_banned وfraud_score. تبحث في زبائن المتجر وحدهم، وتقبل الرقم مع +213 أو بدونه، ولا تعطي اسماً ولا عنواناً ولا سجلاً. الرقم المجهول يعطي صفحة فارغة.

الأحداث

تُرجع GET /v1/events?wait=25&limit=200&cursor=... الحقول items وnext_cursor وhas_more. الحقل next_cursor موجود دائماً، حتى في صفحة فارغة، ويعيده الصندوق في النداء التالي.

  • تحتفظ الحافة بالنداء حتى 25 ثانية وتجيب فور حدوث تغيير.

  • النداء الأول، دون مؤشر، يبدأ بحدث order.updated لكل طلب في حالة pending أو confirmed أو processing.

  • الأنواع: order.created وorder.updated وproduct.updated وproduct.deleted وinventory.level_changed وcustomer.updated وdevice.revoked. لكل حدث id ثابت، فيستطيع الصندوق تجاهل التكرار.

  • يحمل inventory.level_changed الحقول old وnew وdelta وsource: order عندما يحرّك طلبٌ المخزون (مع رقم الطلب)، وdashboard لأي تغيير آخر حدث خارج الصندوق، وpos عندما يغيّره صندوق آخر في المتجر نفسه (يتجاهل الصندوق هذا المصدر).

  • كتابات الصندوق نفسه على المنتجات والمخزون لا تُرسل إليه من جديد.

  • يحمل device.revoked الحقل device_id كنص، مرة واحدة، بعد فصل الصندوق.

  • المؤشر الذي لم تُصدره هذه الواجهة يُرجع 400 bad_request.

النسخ الاحتياطية

لا تحفظ DZBuild النسخ الاحتياطية للصناديق. تُرجع GET /v1/backups وPOST /v1/backups وPOST /v1/backups/{id}/complete وGET /v1/backups/{id}/download دائماً 501 not_implemented، ويحتفظ الصندوق بنسخه على الحاسوب.

رموز الأخطاء

الحالة

code

متى

400

bad_request

updated_since خاطئ أو مؤشر لم تُصدره هذه الواجهة

401

unauthorized

رمز مفقود أو خاطئ أو منتهٍ، أو ربط منتهٍ

402

product_limit_reached

دفعة تنشئ منتجاً بعد حدّ الخطة

403

forbidden

مسار خارج قائمة الصندوق، أو متجر لم يختره صاحبه

404

not_found

منتج أو بيع أو طلب ليس في هذا المتجر

404

device_not_found

رقم صندوق ليس هذا الصندوق في هذا المتجر

404

media_not_found

تذكرة صورة مجهولة أو منتهية

409

already_exists

وثيقة بهذا external_id مسجّلة؛ رقمها في details.id

409

order_claimed

صندوق آخر أخذ الطلب

409

claim_required

تحريك طلب لم يأخذه هذا الصندوق

409

transition_not_allowed

الانتقال غير مسموح من حالة الطلب

410

device_revoked

فُصل الصندوق

413

payload_too_large

جسم أكبر من 1 ميغابايت

422

validation_error

حقل خاطئ؛ يذكره details.field

422

media_mismatch

الصورة المرفوعة لا تطابق تذكرتها

422

idempotency_key_reuse

نفس Idempotency-Key مع جسم مختلف

429

rate_limited

تجاوز حدّ؛ انتظر Retry-After

501

not_implemented

مسارات النسخ الاحتياطية

503

storage_unavailable

تخزين الصور غير متاح؛ أعد المحاولة لاحقاً

هل أجاب هذا عن سؤالك؟