المدفوعات
كيف تستقبل صفحة إتمام الطلب الدفع، وكيف تربط Stripe أو PayPal، وما يحدث للطلب في كل خطوة.
لحزمة الحزمة الكاملة
كيف تستلم صفحة إتمام الشراء الدفع
يدفع العميل على صفحة المزوّد نفسه، Stripe Checkout أو PayPal، لذلك لا يرى الموقع ولا واجهة API رقم البطاقة أبدًا. تحسب واجهة API سعر الطلب بنفسها، من قائمتها ورسومها وخصوماتها، ولا تعتمد أبدًا على الأسعار التي يرسلها المتصفح.
| الطريقة | يُعرض عندما | ما يحدث |
|---|---|---|
| الدفع بالبطاقة (Stripe) | يكون STRIPE_SECRET_KEY مضبوطًا | يُحفظ الطلب غير مدفوع ويذهب المتصفح إلى صفحة Stripe. يصبح الطلب مدفوعًا بعد أن تسأل واجهة API منصة Stripe عمّا حدث ويتطابق المبلغ. |
| PayPal | يكون PAYPAL_CLIENT_ID وPAYPAL_CLIENT_SECRET مضبوطين | الأمر نفسه، على صفحة PayPal: تحصّل واجهة API الدفعة الموافق عليها قبل أن يُعدّ الطلب مدفوعًا. |
| الدفع التجريبي | لا يوجد مزوّد مضبوط | يجعل الطلب مدفوعًا من دون تحويل أي مال، حتى يمكن تجربة المسار كاملًا محليًا. لا يُعرض أبدًا بجوار مزوّد مضبوط. |
يمكن للزوار إتمام الطلب باسمهم وبريدهم الإلكتروني؛ ويرى العملاء المسجّلون الطلب في حساباتهم. ينتقل الطلب المدفوع إلى قائمة انتظار المطبخ؛ ولا يستطيع الفريق تأكيد الطلب غير المدفوع.
الأسعار بالدولار الأمريكي. يكلّف التوصيل $2.99 والاستلام مجاني في الإعدادات التجريبية، مع حد أدنى للتوصيل قدره $10.00. لا يوجد سطر ضريبة منفصل: يدفع العميل أسعار القائمة مع الرسوم، ناقص أي خصم. يغيّر الفريق الرسوم في لوحة التحكم، من «الإعدادات»، ثم «المطعم»، حيث تُعرض أيضًا طرق الدفع التي يوفرها هذا البناء وما إذا كانت كل منها تعمل في الوضع التجريبي أو الحقيقي.
اربط Stripe
أضف مفتاحك السري
من صفحة مفاتيح API في لوحة تحكم Stripe، ضع المفتاح السري في ملف
.envالخاص بواجهة API. استخدم مفتاحًا تجريبيًا (sk_test_…) حتى تكون مستعدًا لاستقبال أموال حقيقية: فهو لا يحوّل أي مال.ملف .env الخاص بواجهة APISTRIPE_SECRET_KEY=sk_test_…اشترك في webhook
في Stripe، أضف نقطة نهاية webhook على عنوان واجهة API الخاصة بك متبوعًا بـ
/api/payments/webhooks/stripe، مشتركة فيcheckout.session.completedوcheckout.session.expiredوcharge.refundedوcharge.dispute.created. انسخ سر التوقيع الخاص بها إلى ملف.envالخاص بواجهة API.ملف .env الخاص بواجهة APISTRIPE_WEBHOOK_SECRET=whsec_…تحقق من عناوين العودة
يعيد Stripe المتصفح إلى
API_PUBLIC_URL، وترسله واجهة API بعد ذلك إلى الموقع علىSTOREFRONT_URL. محليًا تعمل القيمتان الافتراضيتان. على نطاقاتك الخاصة، اضبط الاثنين على العناوين الحقيقية.أعد تشغيل واجهة API
النتيجة المتوقعة: تعرض صفحة إتمام الطلب «الدفع بالبطاقة»، ويظهر في «الإعدادات»، ثم «المطعم»، ثم «الدفع» كطريقة معروضة، في الوضع التجريبي.
لا تحتاج إلى المفتاح القابل للنشر (publishable key): يتم الدفع على صفحة Stripe نفسها. لاختبار الـ webhook على جهازك، يمكن لـ Stripe CLI تمرير الأحداث إلى http://localhost:8000/api/payments/webhooks/stripe، ويطبع سر التوقيع الذي تستخدمه أثناء عمله.
اربط PayPal
أضف بيانات اعتماد تطبيقك
من لوحة مطوّري PayPal، انسخ معرّف العميل (client id) والسر الخاصين بتطبيقك إلى ملف
.envالخاص بواجهة API. قيمةPAYPAL_ENVالافتراضية هيsandbox، التي لا تحوّل أي مال؛ أماliveفتستقبل مدفوعات حقيقية.ملف .env الخاص بواجهة APIPAYPAL_CLIENT_ID=your-paypal-sandbox-client-id PAYPAL_CLIENT_SECRET=your-paypal-sandbox-client-secret PAYPAL_ENV=sandboxاشترك في webhook
أضف webhook على عنوان واجهة API الخاصة بك متبوعًا بـ
/api/payments/webhooks/paypal، مع أحداث تحصيل الدفع: مكتمل، ومرفوض، ومسترد، ومعكوس. انسخ معرّف الـ webhook إلى ملف.envالخاص بواجهة API: تتحقق واجهة API من كل استدعاء بمقارنته به.ملف .env الخاص بواجهة APIPAYPAL_WEBHOOK_ID=your-paypal-webhook-idأعد تشغيل واجهة API
النتيجة المتوقعة: تعرض صفحة إتمام الطلب PayPal.
ما يحدث للطلب
| الحدث | الطلب |
|---|---|
| يرسله العميل | يُحفظ قيد الانتظار وغير مدفوع. يحجز مخزونه وأي نقاط مكافآت استبدلها العميل. |
| يؤكد المزوّد الدفع | مدفوع، بعودة العميل أو بالـ webhook، أيهما يصل أولًا. عودة المتصفح وحدها لا تجعل الطلب مدفوعًا أبدًا: تسأل واجهة API المزوّد أولًا. |
| يغادر العميل صفحة الدفع | يُتحقق منه لدى المزوّد بعد 35 دقيقة لـ Stripe و3 ساعات لـ PayPal، ثم يُلغى كدفع فاشل، ويُعاد مخزونه ونقاطه. |
| يُبلغ المزوّد عن استرداد كامل | مُسترد، وتُسحب النقاط التي اكتسبها. الاسترداد الجزئي في Stripe يُسجَّل ويبقى الطلب كما هو. |
الدفعة التي تصل لطلب أُلغي من قبل تُسجَّل على أنها تحتاج إلى استرداد ولا تعيد الطلب أبدًا. لا يستطيع الفريق جعل الطلب مُستردًا يدويًا: يتم الاسترداد في Stripe أو PayPal، ويحدّث الـ webhook الطلب.
الدفع التجريبي
- من دون أي مزوّد مضبوط، تعرض صفحة إتمام الطلب «دفع تجريبي» و«أرسل الطلب التجريبي». يصبح الطلب مدفوعًا فورًا، من دون تحويل أي مال، حتى يمكن تجربة قائمة انتظار المطبخ وصفحة التتبّع من البداية إلى النهاية.
- بمجرد ضبط Stripe أو PayPal، يختفي الدفع التجريبي، ويُرفض أي طلب يطلبه.
- الـ webhook الخاص بالدفع التجريبي،
POST /api/payments/webhooks/demo، يرفض كل استدعاء ما لم يكنPAYMENT_WEBHOOK_SECRETمضبوطًا ومرسلًا في الترويسةx-webhook-secret.
استلام مدفوعات حقيقية
- ضع المفاتيح الحقيقية (
sk_live_…، أو تطبيق PayPal الحقيقي معPAYPAL_ENV=live) و webhook منشأً في الوضع الحقيقي، وله سر توقيع أو معرّف خاص به. - اضبط
API_PUBLIC_URLوSTOREFRONT_URLعلى عناوينك الحقيقية، وأضف الموقع إلىCORS_ORIGIN: عنوان العودة الذي ليس فيه يُرفض. - تعرض «الإعدادات»، ثم «المطعم»، ثم «الدفع» كل طريقة على أنها «مباشر، أموال حقيقية» بمجرد أن تعمل ببيانات اعتماد حقيقية.
- المبالغ بالدولار الأمريكي في كل مكان: تحصّل واجهة API بالعملة
CURRENCYمنback-end/src/common/constants/ordering.constants.ts، وتعرض الواجهتان الأماميتان الأسعار بالدولار. استخدام عملة أخرى يتطلب تعديل الكود في واجهة API والواجهات الأمامية، مع ضبطNEXT_PUBLIC_ANALYTICS_CURRENCYبما يطابقها.