السيناريو الذي يختبر المتجر فعلًا
يضغط العميل «ادفع الآن»، فيظهر مؤشر تحميل ثم تنقطع الشبكة. يفتح تطبيق البنك فيجد مبلغًا محجوزًا أو عملية معلقة، بينما تعرض صفحة المتجر رسالة «حدث خطأ، حاول مجددًا». في هذه اللحظة قد يؤدي زر المحاولة غير المدروس إلى إنشاء طلب ثانٍ أو إعادة تحصيل غير مقصودة. لا يكفي أن تختصر خطوات Checkout أو تجعل زر الدفع كبيرًا؛ يجب تصميم حالة الاسترداد عندما لا يعرف المتصفح نتيجة العملية. يركز هذا الدليل على هندسة تجربة الدفع غير اليقينية وربط الطلب بالمزود، وليس على نصائح تقليل التخلي عن السلة أو حماية بيانات البطاقات عمومًا.
افصل بين طلب الشراء ومحاولة الدفع
أنشئ معرفًا ثابتًا للطلب قبل إرسال عملية التحصيل، ثم سجّل محاولة دفع مرتبطة به. يمكن أن يضم الطلب عناصر السلة والكمية والضرائب ورسوم الشحن وعنوان التسليم والحالة التجارية، بينما تسجل محاولة الدفع معرف عملية المزود ووقت الإرسال ونتيجتها المعروفة. لا تجعل كل نقرة على الزر تنشئ طلبًا تجاريًا جديدًا. إذا غادر العميل الصفحة وعاد بعد دقيقة، ينبغي أن يستطيع استئناف متابعة الطلب نفسه. يجب أن يكون لديك مصدر حقيقة واضح: قاعدة طلباتك لحالة الوفاء التجاري، ومزود الدفع لحالة المعاملة المالية، مع آلية مصالحة بينهما.
لا تساوِ مهلة الشبكة بفشل الخصم
قد تنتهي مهلة الاتصال بعد أن يستقبل مزود الدفع الطلب وينفذه، وقبل أن تصل الاستجابة إلى متجرك. لذلك فإن ظهور Timeout في الخادم لا يعني أن الأموال لم تُحجز. عند غياب النتيجة، انقل محاولة الدفع إلى حالة «قيد التحقق» بدل «فشل مؤكد»، ثم استعلم عن حالة العملية بمعرفها من واجهة المزود المعتمدة. إن كان المزود يدعم مفاتيح عدم تكرار الأثر Idempotency Keys، فاستخدم مفتاحًا ثابتًا للعملية المنطقية نفسها وفق وثائقه، لا مفتاحًا جديدًا مع كل Retry. تختلف تفاصيل الاحتفاظ بالمفتاح وحدود إعادة الطلب بين المزودين؛ لا تفترض أنها موحدة.
حالات الطلب التي يفهمها المستخدم
لا تعرض للعميل المصطلحات الداخلية مثل 502 أو webhook retry. استخدم حالات واضحة: «لم نبدأ الدفع»، و«جارٍ تأكيد العملية»، و«تم الدفع وتسجيل الطلب»، و«لم يكتمل الدفع ويمكن المحاولة»، و«نحتاج مساعدة الدعم». يجب أن ترتبط كل حالة بدليل فعلي في السجلات. لا تعلن «تم الدفع» اعتمادًا على رسالة من المتصفح وحده إذا كان المزود لم يؤكد العملية. ولا تعرض «فشل الدفع» إذا كانت العملية ما تزال معلقة. اشرح متى يستطيع العميل إغلاق الصفحة بأمان، وأرسل إشعارًا بعد تأكيد النتيجة إذا كان لديه وسيلة تواصل وموافقة مناسبة.
كيف يعمل مسار التحقق في الخلفية؟
بعد إرسال محاولة الدفع، خزّن معرفها ومعرف الطلب ونتيجة الاستجابة إن وصلت. إذا انقطع الاتصال، تستطيع خدمة خلفية استعلام المزود عن حالة المعاملة أو انتظار إشعار خادم إلى خادم Webhook. تحقق من توقيع الإشعار وفق وثائق المزود، ولا تعتمد على محتوى طلب غير موثق لتغيير حالة الطلب. قد يصل الإشعار مرتين أو متأخرًا أو بترتيب غير متوقع؛ لذلك يجب أن تكون معالجة الحدث قابلة للتكرار دون مضاعفة الأثر. اجعل تسجيل «تم الدفع» عملية ذرية قدر الإمكان مع منع تنفيذ الشحن مرتين للطلب نفسه.
جدول انتقالات الحالة
جدول إرشادي؛ حالات مزود الدفع الفعلية قد تكون أكثر تفصيلًا.
| بانتظار الدفع | المزود يؤكد النجاح | ثبت الدفع مرة واحدة |
| بانتظار الدفع | مهلة اتصال | حوّل إلى قيد التحقق |
| قيد التحقق | إشعار نجاح موثوق | أكد الطلب وأخطر العميل |
| قيد التحقق | فشل نهائي موثق | اسمح بمحاولة جديدة مضبوطة |
| مدفوع | إشعار نجاح مكرر | سجل الحدث دون تكرار الشحن |
| ملغى | إشعار مالي متأخر | راجع التسوية والاسترداد قبل أي وفاء |
حماية زر إعادة المحاولة دون تعطيل العميل
يمكن تعطيل زر الدفع مؤقتًا أثناء إرسال الطلب لتقليل النقرات المتكررة، لكن هذا ليس ضمانًا كافيًا: قد يعيد العميل فتح الصفحة أو يستخدم جهازًا آخر أو يعيد الخادم الطلب تلقائيًا. الضمان الحقيقي يأتي من تعريف العملية في الخادم ومفتاح عدم التكرار والتحقق من حالة المعاملة. عند ظهور حالة غير محسومة، اعرض زر «تحقق من حالة الدفع» بدل «ادفع مرة أخرى». وإذا ثبت الفشل النهائي، اسمح بمحاولة جديدة مرتبطة بالطلب نفسه وفق سياسة المزود. لا تمنع المستخدم من الوصول إلى الدعم أو تفاصيل الطلب لمجرد أن الاتصال ضعيف.
متى تنشئ محاولة دفع جديدة؟
لا تنشئ محاولة جديدة لمجرد انتهاء مؤقت في الواجهة. تحقق أولًا من حالة المحاولة السابقة، ومن أن مزود الدفع يسمح بإعادة الاستخدام أو يحتاج معاملة جديدة. بعض الأنظمة تفصل التفويض المالي عن التحصيل النهائي، وقد يكون المبلغ محجوزًا لا محصلًا. عند فشل موثق أو إلغاء صريح، أنشئ محاولة جديدة بمعرف جديد مع الإبقاء على سجل المحاولة القديمة. إذا تغيرت السلة أو رسوم الشحن، يجب أن تعيد عرض المبلغ النهائي وتطلب موافقة واضحة قبل محاولة جديدة. لا تستخدم معرف عملية قديمة مع مبلغ مختلف وتفترض أن المزود سيتصرف كما تتوقع.
الويب هوك ليس بديلًا عن قاعدة حالات محكمة
قد تتأخر إشعارات Webhook أو تتكرر، وقد يتوقف خادم الاستقبال مؤقتًا. لذلك احتفظ بجدول للأحداث المستلمة ومعرف فريد لكل حدث، وامنع معالجته تجاريًا أكثر من مرة. إذا وصل إشعار «نجاح» بعد أن عالجت الطلب، سجّل وصوله ولا تكرر حجز المخزون أو إرسال البريد أو الشحن. إذا وصل إشعار متعارض، راجع الحالة الرسمية لدى المزود بدل اختيار آخر حدث زمنيًا بصورة عمياء. ينبغي أن تتضمن سجلات المراجعة سبب كل انتقال في حالة الطلب، ومصدره، ومعرف الحدث، دون تخزين بيانات بطاقة حساسة في سجل التطبيق.
كيف تتعامل مع المخزون أثناء انتظار الدفع؟
قد يحجز المتجر قطعة نادرة لفترة قصيرة أثناء إتمام الدفع. إذا علقت المعاملة، يصبح القرار أصعب: تحرير المخزون فورًا قد يسمح ببيع القطعة مرتين إذا تأكد الدفع لاحقًا، وحجزها إلى الأبد يضر العملاء الآخرين. صمم مهلة حجز واضحة وسياسة تسوية عند وصول تأكيد متأخر. عند انتهاء المهلة، تحقق من المعاملة قبل تحرير الحجز أو نقل الطلب إلى مراجعة يدوية. إذا كانت السلعة رقمية، امنع منح الترخيص مرتين. وإذا كانت مادية، امنع إنشاء شحنتين لنفس الطلب. يجب أن تكون قواعد المخزون متسقة مع حالة الدفع لا مع رسالة المتصفح فقط.
رسائل خدمة العملاء في الحالة غير المحسومة
من الأفضل أن تظهر للعميل رسالة مثل «لم نتمكن من تأكيد نتيجة الدفع بعد. لا تعِد العملية الآن؛ يمكنك متابعة الحالة من صفحة طلبك». أضف رقم طلب لا يكشف بيانات خاصة، ووقت آخر تحديث، وطريقة تواصل واضحة. تجنب وعدًا زمنيًا قاطعًا للاسترداد أو فك الحجز إذا لم تكن سياسة البنك والمزود تضمنه. يمكن إبلاغ العميل أن بعض العمليات المعلقة تظهر مؤقتًا في كشف البنك، لكن القرار النهائي يحتاج مراجعة المصدر المالي. لا تطلب من العميل إرسال صورة كاملة لبطاقته أو رمز تحقق إلى الدعم؛ اجمع الحد الأدنى اللازم للتحقق من المشكلة.
اختبارات الفشل أهم من اختبار نجاح الدفع
نفذ في بيئة اختبار رسمية للمزود حالات انقطاع اتصال المتصفح بعد إرسال الطلب، وتأخر الاستجابة، ووصول إشعار نجاح مرتين، وفشل استعلام الحالة، وعودة العميل من صفحة البنك، وتحديث الصفحة أثناء الانتظار. افحص أن الطلب لا يتكرر وأن العميل يستطيع استعادة حالة السلة وأن سجل الأحداث يوضح ما حدث. اختبر تغيير عنوان الشحن بعد بدء الدفع، وتغير سعر منتج، ونفاد المخزون، حتى لا تنشأ فجوة بين المبلغ الذي وافق عليه العميل والطلب النهائي. لا تجرِ اختبارات خصم حقيقية على عملاء دون موافقة أو خارج أدوات الاختبار المخصصة.
مثال محاسبي مبسط
افترض أن عميلًا اشترى منتجًا بمئة وحدة نقدية. أرسل المتجر طلب الدفع مرة واحدة، ثم فقد الاتصال قبل الاستجابة. إذا ضغط العميل مرة ثانية وأنشأ النظام معاملة جديدة، قد تظهر عمليتان ماليتان بقيمة مئتين إجمالًا رغم وجود طلب واحد. أما التصميم الصحيح فيستعلم أولًا عن المعاملة الأولى، ثم يؤكد الطلب أو يسمح بمحاولة جديدة فقط بعد التحقق من الفشل. لا تخلط بين حجز مؤقت وتحصيل نهائي أو استرداد مكتمل؛ لكل منها أثر مختلف في كشف العميل والمحاسبة. المثال يوضح خطر الازدواج ولا يفترض سلوكًا معينًا لأي بنك أو مزود.
خطوات اعتماد المسار قبل إطلاق المتجر
قائمة فحص الاسترداد بعد انقطاع الدفع
- ثبّت معرف طلب قبل إنشاء محاولة الدفع
- اربط المحاولة بمعرف مزود ومفتاح عدم تكرار مناسب
- عرّف حالة قيد التحقق بوضوح
- تحقق من توقيع أحداث المزود ومنع تكرار معالجتها
- امنع تكرار حجز المخزون أو الوفاء التجاري
- اختبر المهلة والتحديث والعودة من صفحة البنك
- اعرض حالة مفهومة ودعمًا دون كشف بيانات حساسة
- صالح سجلات الطلبات مع تقرير المزود دوريًا
قرار هندسي يوازن الثقة وسهولة الاستخدام
المتجر السهل ليس الذي يحذف كل خطوة تحقق، بل الذي يطلب من العميل أقل قدر لازم من العمل ويحتفظ في الخلفية بحالة مالية دقيقة. يمكن لواجهة بسيطة أن تخفي نظام حالات معقدًا بشرط ألا تخفي الحقيقة عن المستخدم. لا تجعل فشل اتصال مؤقتًا سببًا لتكرار الخصم، ولا تجعل الشك في النتيجة عذرًا لإبقاء العميل بلا معلومة. راقب معدل الحالات المعلقة وزمن تسويتها وعدد الطلبات المكررة والأخطاء في ربط المخزون، ثم حسّن المسار وفق بيانات حقيقية. يجب أن يكون نجاح الاختبار هو «طلب واحد ومبلغ صحيح وتجربة واضحة» لا مجرد وصول المستخدم إلى شاشة الشكر.
المراجع والقراءة المرتبطة
تشرح وثائق Stripe الرسمية التعامل مع الطلبات غير المكررة: https://docs.stripe.com/api/idempotent_requests ، ومعالجة أحداث الدفع: https://docs.stripe.com/webhooks . وتشرح مادة إيجي تاج «تقليل التخلي عن سلة الشراء من خلال اختبار خطوات الدفع» تجربة المستخدم قبل التحصيل، بينما تركز هذه المادة على الاسترداد بعد عدم اليقين. ويمكن الرجوع إلى «Idempotency في APIs: لماذا يجب ألا يكرر Retry عملية الدفع أو الإنشاء؟» لفهم الفكرة العامة. لا تطبق تفاصيل مزود بعينه على مزود آخر دون مراجعة عقده وواجهاته وسياسة معالجة الأموال.
شارك في تقييم ونقاش المقال
رأيك يضيف قيمة للمقال ويساعدنا على تحسين المحتوى والنقاش حوله.
النقاش
جارٍ تحميل التعليقات…