Stripe في Laravel. نمذج الدفعة لا النداء.
الدفعة آلة حالات بحدثين يحركان المال، لا حقل صح وخطأ على الطلب. ماذا يعني ذلك لمخططك، وأين يتوقف Cashier، وأي أعمدة تحتاجها من اليوم الأول.
تبدأ أغلب تكاملات Stripe بنداء للحزمة وعمود اسمه paid. وتعمل نحو أربعة أشهر،
وهي تقريبًا المدة اللازمة لوصول أول استرداد جزئي، أو أول عملية متنازع عليها، أو
أول طلب طلب فيه بنك العميل مصادقة ولم يعد العميل أبدًا.
المشكلة ليست الواجهة البرمجية قط. المشكلة أن الدفعة نُمذجت بوصفها شيئًا وقع، وهي شيء لا يزال يقع.
ما تُكامله آلة حالات
يمر الـ PaymentIntent بحالات: يحتاج وسيلة دفع، ويحتاج إجراءً من العميل، وهو قيد المعالجة، ونجح، وأُلغي. وعدة من هذه الانتقالات يقودها بنك لا شيفرتك، وبعضها يستغرق دقائق.
ولهذا نتيجة واحدة مباشرة على مخططك، وهي المقالة كلها في جملة: صف الدفعة عندك
يحمل حالة لا علامة. فإن كان العمود قيمة منطقية، انهارت "العميل الآن على شاشة
3D Secure" و"رفض البنك" و"المال مفوَّض لكنه غير محصَّل" كلها في false، ولم يعد
فريق الدعم يفرّق بينها.
نمذج الحالات التي تتصرف بناءً عليها فعلًا. أغلب الشركات تحتاج خمسًا أو ستًا: يتطلب إجراءً، قيد المعالجة، مفوَّض، محصَّل، فاشل، ملغى. اجعلها تعدادًا حقيقيًا واجعل الانتقالات صريحة - فمقصد عمود الحالة أن تُرفض النقلات غير المشروعة، لا أن يُستبدل نص.
التفويض والتحصيل حدثان
يمكن لدفعة ببطاقة أن تحجز المال دون أن تأخذه. يحتفظ التفويض بالمبلغ أيامًا،
والتحصيل فعل منفصل هو قبضه فعليًا. ويعرض Stripe ذلك بـ capture_method: manual.
وكل من يشحن بضاعة يحتاج هذا، لأن أخذ المال مقابل شيء لم تُرسله بعدُ استرداد قادم، وفي بعض الولايات القضائية مشكلة تنظيمية أيضًا. ومن يبيع خدمة بعربون يحتاجه. ومن يبني سوقًا متعدد البائعين يحتاجه.
وأثره في المخطط أن المبلغ المفوَّض والمبلغ المحصَّل عمودان مختلفان، وهما كثيرًا ما يكونان رقمين مختلفين. تفوّض السلة كاملة، ثم ينفد صنف، ثم تحصّل أقل. ونموذج طلب بمبلغ واحد لا يعبّر عن ذلك، وإلحاقه لاحقًا يعني ترحيلًا على كل صف تاريخي بينما تنتظر المالية.
وأيضًا: التفويض ينتهي. فإن لم يحصّله شيء داخل النافذة، سقط الحجز وخرج المال عن متناولك. وهذه مهمة مجدولة تبحث عن تفويضات تقترب من الانتهاء، ولن يذكّرك بها Stripe.
حفظ البطاقة ليس حفظ بطاقة
حين يعلّم العميل "تذكّر بطاقتي"، فأنت لا تخزّن شيئًا. أنت تُنشئ سجلًا لإذن، وللإذن شروط: فيمَ يحق لك الخصم، وهل يجب أن يكون العميل حاضرًا، وهل سيطلب بنكه مصادقة مجددًا.
ويفصل Stripe ذلك إلى SetupIntent لجمع الإذن وخصومات off_session لاستعماله.
والتفريق مهم لأن الخصم خارج الجلسة قد يفشل طالبًا مصادقة، ولا عميل هناك ليصادق.
فعلى شيفرتك أن تعالج دفعة فشلت على نحو لا ذنب فيه لأحد، ويُصلَح بإرسال رابط إلى
العميل.
وهنا تحطّ القواعد الأوروبية أيضًا. فتحت SCA يجب أن يقع الخصم غير المصحوب بحضور ضمن استثناء أو يحمل اتفاقًا سابقًا، ما يعني عمليًا أن التفويض أُعِدّ إعدادًا صحيحًا وقت حفظ البطاقة. وأن تخطئ في ذلك أمر غير مرئي إلى أن تبلغ نسبة الفشل في تجديداتك خمسة عشر بالمئة ولا يعرف أحد السبب.
أين يتوقف Cashier
Cashier برنامج جيد، وهو مكتبة اشتراكات. فإن كنت تبيع خططًا بخيار شهري وسنوي، فهو يحمل دورة الحياة وحساب التناسب وفترات السماح وسجلات الفواتير، وكتابة ذلك بنفسك شهر ضائع.
وهو لا يغطي الدفعات المفردة بتحصيل يدوي، ولا تقسيمات الأسواق، ولا التسوية متعددة الأطراف، ولا سلة دفع يُحسب مبلغها من عربة متغيّرة. هذه هي الحزمة مباشرة، وهذا متوقع لا عيب في المكتبة.
والخطأ الذي يستحق التجنب هو اعتبار جداول Cashier نموذج دفعاتك. إنها تصف اشتراكات. أما طلباتك وتحصيلاتك واستردادك وعمولاتك فهي لك، ويجب أن توجد سواء كان في الأمر اشتراك أم لا.
الصف الذي تحتاجه فعلًا
كحد أدنى، لكل محاولة دفع:
- معرّفك أنت ومعرّف المزوّد، مفهرسين.
- الحالة تعدادًا، مع ختم زمني لآخر انتقال.
- المبلغ المفوَّض والمحصَّل والمرتجع - ثلاثة أعداد صحيحة بالوحدة الصغرى للعملة، كما ينبغي أن يُخزَّن المال دائمًا.
- رمز العملة، منفصلًا.
- العمولة متى عرفتها، فإيرادك ليس ما دفعه العميل.
- مفتاح التفرّد الذي أرسلته.
- مفتاح أجنبي إلى ما تدفع هذه الدفعة ثمنه.
والأخيران يعملان أكثر مما يبدوان. فمفتاح التفرّد هو ما يمنع مهمة معادة من الخصم مرتين، والطابور تحتك سيعيد المحاولة. ويقبل Stripe المفتاح في كل طلب يغيّر شيئًا ويعيد الرد الأصلي بدل الخصم ثانية، لكن فقط إن أرسلت واحدًا، وفقط إن كان مشتقًا من المحاولة لا مولَّدًا من جديد.
ما تبنيه أولًا
ابنِ آلة الحالات ومستقبل الـ webhook قبل شاشة الدفع. فالشاشة بعد ظهيرة، والحالات هي النظام. وسلة دفع تبدو مثالية وتعلن النجاح من العودة هي النسخة التي تفقد الطلبات بصمت، لأن العودة ليست ما يخبرك بنجاح الدفعة.
ثم طابِق. اسأل Stripe يوميًا عن كل ما تغيّر وقارنه بصفوفك. لا لأن الـ webhooks غير موثوقة، بل لأنك تريد أن تعرف متى انحرف شيء، والبديل الوحيد أن تعرفه من عميل.
نؤدي هذا العمل ضمن مشاريع التجارة الإلكترونية وبمفرده، وسؤالنا الأول واحد دائمًا: التفويض والتحصيل معًا أم منفصلين؟ الجواب يغيّر المخطط، والإجابة عنه في الأسبوع الأول أسهل منها في الشهر السادس.
