التجارة السعودية · تشغيل المحافظ

محافظ عملاء زد: Credit وDebit جماعيان بمطابقة آمنة

دليل إنتاجي لتعديلات المحافظ الجماعية يصمد أمام النجاح الجزئي وHTTP 200 مع عناصر فاشلة وTimeout وإعادة Workers والتدقيق.

المسار المرتبطهندسة التجارة الإلكترونية
رسم تقني أصلي لحملة محافظ زد تمر عبر الموافقة وCommand Ledger ونتائج Bulk لكل عميل ثم المطابقة؛ وليس لقطة من لوحة زد.
تصوّر بصري للفكرة — يتبعه شرح ومخطط تنفيذي داخل المقال.

يكون تكامل محافظ العملاء في زد أكثر أمانًا عندما يعامل تطبيقك كل إضافة أو خصم كأمر مالي له Operation ID وحالة دائمة ومسار مطابقة. لا تعتبر HTTP 200 من طلب Bulk نجاحًا كاملًا؛ توضح زد صراحة أن Bulk Credit وBulk Debit قد يعيدان 200 حتى لو فشلت كل العناصر، لذلك عقد النتيجة الحقيقي هو قوائم succeeded وfailed لكل عميل مع failed_count. احفظ النية قبل استدعاء زد، وسجل Transaction ID لكل نجاح، وأعد فقط العملاء غير المحسومين، ثم طابق الأرصدة والمعاملات.

هذا شرح عملي مبني على وثائق زد الرسمية لمحافظ العملاء، وقد تحققت منها في 20 أكتوبر 2026. هو دليل هندسي وليس خبرًا أو نصيحة مالية. توثق زد سلوك المنصة، أما Operation Ledger وIdempotency والموافقات والمطابقة أدناه فهي توصيات تصميمية للتطبيق.

ابدأ بأهلية المتجر وحدود الصلاحيات

توثق زد APIs محافظ العملاء للمتاجر التي تعمل بعملات SAR وAED وQAR وKWD وBHD وOMR. المتجر بعملة أخرى يتلقى خطأ يفيد أن المحافظ متاحة لدول الخليج فقط. افحص الأهلية أثناء Onboarding بدل اكتشاف القيد وسط حملة.

صلاحيات القراءة والكتابة منفصلة. عرض المحافظ والأرصدة وPending Cashback والتحليلات يستخدم Customer Wallet Read Scope. أما Credit وDebit فيحتاجان Write Scope، وتقول زد إن الكتابة تحتاج موافقة مسبقة على Use Case مسموح أثناء App Review. لا تطلب Write Access لمجرد احتمال استخدامها لاحقًا. أبقِ التقارير وتجهيز الحملة والتحقق من الرصيد قابلة للعمل بصلاحية القراءة فقط.

لا تقبل Store ID أو Customer ID أو Amount أو Reason من عميل غير موثوق ثم تمررها مباشرة إلى زد. استخرج المتجر من Installation موثقة، وتحقق من صلاحية الموظف، وافحص العملة والقيمة بوحدات العملة الصغرى داخل نظامك، وسجل من وافق. Credit ينشئ قيمة وDebit يزيلها؛ كلاهما يحتاج ضوابط أقوى من تحديث Profile عادي.

مثّل تعديل المحفظة كأمر لا كنقرة زر

أنشئ Internal Operation واحدة قبل الطلب الخارجي. يحتوي السجل المفيد merchant_id وoperation_id وtype وamount_minor وcurrency وreason_code وexpiry_at وrequested_by وapproved_by وsource_reference وstatus. ولكل عميل Target فرعية بحالة مستقلة: prepared أو submitted أو succeeded أو failed أو unknown أو reconciled.

Operation ID هي حد Idempotency لديك حتى لو لم تعرض واجهة المنصة حقل Idempotency Key. ضع Unique Constraint على merchant_id مع operation_id، وقيدًا آخر على merchant_id وsource_reference وcustomer_id وadjustment_type. عند إعادة Worker أو Double Click أو Queue Redelivery يجد النظام الأمر الموجود بدل إصدار Credit جديد.

لا تخلط Amount مع Balance. التعديل Event، أما الرصيد فهو Projection تملكها المنصة في لحظة معينة. خزّن القيمة المطلوبة وUpstream Transaction ID، لكن اجلب الرصيد الحالي عندما يحتاج المسار حقيقة رسمية. تفرق استجابة الرصيد في زد بين total_balance وbalance المتاح وheld_balance وcurrency وpending_cashback؛ لذلك لا يستطيع رقم واحد تمثيل كل الحالات.

اعتبر Bulk HTTP 200 نجاح نقل فقط

تطبق واجهتا Bulk Credit وBulk Debit في زد القيمة نفسها على مجموعة Customer IDs. تحتوي الاستجابة الموثقة على succeeded وfailed مع total وsucceeded_count وfailed_count. وتحذر الوثائق من أن Endpoint قد تعيد 200 حتى عندما تفشل كل التعديلات. لذا يجيب Status فقط: هل وصلتك استجابة منظمة؟ ولا يجيب: هل نجح العمل التجاري؟

تحقق من أربعة Invariants قبل إكمال Batch: total يساوي عدد الأهداف، وsucceeded_count يطابق عناصر النجاح الصالحة، وfailed_count يطابق عناصر الفشل، وكل عميل مطلوب يظهر مرة واحدة فقط. إذا احتوت الاستجابة Customer IDs مكررة أو أهدافًا مفقودة أو أعدادًا متعارضة، انقل العملية إلى needs_review بدل التخمين.

ثبّت نتيجة كل عميل منفصلة. خزّن Zid transaction_id عند النجاح، وخطأ المنصة عند الفشل. الاستجابة المختلطة partially_succeeded وليست failed ولا succeeded. كوّن Sub-batch جديدة من العملاء الفاشلين صراحةً فقط عندما يصنف الخطأ بأنه Transient. لا ترسل الدفعة الأصلية كلها مرة أخرى، لأن ذلك قد يكرر Credit لمن نجحوا.

operation = create_or_get_operation(source_reference)
targets = reserve_unique_targets(operation, customer_ids)
response = zid.bulk_credit(targets.prepared, amount, reason, expires_at)

assert response.total == targets.prepared.count
for item in response.succeeded:
    mark_succeeded(item.customer_id, item.transaction_id)
for item in response.failed:
    mark_failed(item.customer_id, item.error)

if response.failed_count > 0:
    enqueue_retry_only_for_classified_transient_failures()
enqueue_reconciliation(operation.id)
احفظ النية، وافحص نتيجة كل عميل، وأعد الفشل المؤكد فقط، وطابق النتائج المجهولة قبل إغلاق الحملة.
احفظ النية، وافحص نتيجة كل عميل، وأعد الفشل المؤكد فقط، وطابق النتائج المجهولة قبل إغلاق الحملة. اضغط لعرض أكبر

افصل الفشل المؤكد عن النتيجة المجهولة

Failed Entry موثقة تعني فشلًا تجاريًا مؤكدًا لذلك العميل. أما Timeout أو انقطاع الاتصال أو استجابة مشوهة فشيء آخر: قد تكون زد نفذت التعديل رغم أن تطبيقك لم يستلم Transaction ID. اجعل حالة الهدف unknown. إعادة المحاولة العمياء غير آمنة لأن الطلب الثاني قد ينشئ تعديلًا ثانيًا.

طابق النتيجة المجهولة عبر Customer Wallet Transactions والرصيد الحالي. ابحث عن Customer وDirection وAmount وReason ونافذة زمنية ضيقة، ثم خزّن Zid Transaction ID المطابقة. إذا كان الدليل ملتبسًا، اطلب Operator Review. فرق الرصيد وحده لا يكفي لأن Cashback أو Redemption أو تعديلًا يدويًا آخر قد يغير المحفظة بالتزامن.

للحملات ذات القيمة العالية أو الجمهور الكبير استخدم Maker-Checker Approval: مستخدم مصرح يجهز الأمر وآخر يوافق عليه. جمّد Payload غير القابلة للتغيير بعد الموافقة. أي تعديل في القيمة أو الجمهور أو السبب أو الانتهاء ينشئ Operation ID جديدة وموافقة جديدة.

شغّل الحملات كمهام محدودة وقابلة للمراقبة

حوّل الجمهور الكبير إلى Target Rows دائمة قبل الإرسال. استخدم Batches صغيرة وBounded Concurrency والتزم بإرشادات Rate Limit للمنصة. يأخذ Worker مجموعة محدودة من الأهداف prepared، ويرسلها، ويحفظ الاستجابة، ثم يحرر Lease. إذا انهار تظل لديك حالات قابلة للتعافي بدل جمهور نُفذ جزء منه بلا أثر واضح.

واجهة List Wallets في زد Paginated ويمكنها التصفية حسب الحد الأدنى أو الأقصى للرصيد والرصيد القريب من الانتهاء. استخدمها للاختيار أو المطابقة من دون تحميل المتجر كاملًا في الذاكرة. احفظ معايير اختيار الحملة ووقتها. إذا كان الجمهور يجب أن يبقى ثابتًا فحوّل Customer IDs إلى Snapshot قبل الموافقة؛ لا تعِد تشغيل Filter متحركة في منتصف التنفيذ.

تستخدم Pending Cashback Cursor Pagination. احفظ Next Cursor نفسها كـOpaque Checkpoint، ولا تحسب Offset أو تفترض ترتيب الصفحات. وبالنسبة للتصدير توثق زد Export Request غير متزامنة؛ استخدمها للمراجعة البشرية أو Audit Extract كبير، لا كاعتماد متزامن داخل Checkout.

طابق الأرصدة والمعاملات وإجماليات الحملة

نفذ Reconciliation على مستويين. لكل عميل تأكد أن كل Target ناجحة داخليًا لديها Zid Transaction ID وأن حالات unknown حُلت أو رُفعت للمراجعة. وعلى مستوى الحملة قارن أعداد requested وsucceeded وfailed وunknown وreconciled، مع إجمالي القيم المطلوبة والمطبقة. يجب أن تساوي الأعداد الجمهور الأصلي.

استخدم Wallet Analytics كإشارة إجمالية لا كبديل عن Command Ledger. توثق زد مقاييس على مستوى المتجر تشمل الرصيد القائم وCashback وRedemptions وROI، وتحليلات حسب Cashback Rule. قد تكشف Drift أو أثرًا غير متوقع للحملة، لكنها لا تثبت أن تعديل عميل محدد نُفذ مرة واحدة بالضبط.

يجب أن تنبه المراقبة عن Unknown Outcomes الأقدم من هدف المطابقة، والفشل المتكرر حسب Error Class، وعدم تطابق الأعداد، والقيمة الإجمالية غير المعتادة، وWrite Calls من Actors غير متوقعين، وحملة متوقفة بلا تقدم. احتفظ بسجل التدقيق وفق المتطلبات التعاقدية والتنظيمية، وقلل نسخ بيانات العملاء.

متى لا تستخدم تعديل المحفظة

لا تستخدم Wallet Credit بدل Payment Reversal أو Order Refund أو تصحيح إيراد محاسبي إلا إذا عرّفت سياسة العمل هذه المعالجة بوضوح. Promotional Credit وCashback Reward وRefund وGoodwill Adjustment لها ملكية وانتهاء وأثر تقريري مختلف حتى لو رفعت جميعها الرصيد.

لا تخصم من محفظة لإصلاح اختلاف في تقرير داخلي. أثبت المعاملة الرسمية أولًا واحصل على الموافقة. ولا تسمح لقيمة سالبة باختيار الاتجاه؛ اعرض Credit وDebit كأمرين منفصلين بصلاحيات وReason Codes منفصلة.

عقد الإنتاج واضح: تحقق من الأهلية والصلاحيات الموافق عليها، وأنشئ أمرًا دائمًا واحدًا، وثبّت الأهداف الفريدة، وافحص نتيجة كل عنصر في Bulk Response، وأعد فقط حالات الفشل المؤقت المؤكدة، وطابق النتائج المجهولة مع Transactions، واحتفظ بسجل تدقيق ظاهر للمشغّل. هكذا تصبح Bulk API المريحة عملية محفظة مضبوطة وليست زر حملة غير قابل للعكس.

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

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

إعداد: Noor Yasser

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

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

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

احجز لقاءً لمدة ٣٠ دقيقةالخدمة المرتبطةتطبيقات سلة وزد وأدوات التجّارمشروع من الأعمالMember Plus