الطلبات والمدفوعات والاستردادات
كيف يصبح الحجز طلبًا مدفوعًا: الدفع في صفحة Stripe أو PayPal نفسها، والدفع الاختباري، والتذاكر المجانية، ورسوم الحجز، والطلبات في اللوحة، والاستردادات التي تنتظر تأكيد المزوّد.
لحزمة الحزمة الكاملة
من الحجز إلى طلب مدفوع
- يحجز المشتري مقاعد أو أماكن على الموقع، ثم يكتب اسمًا وبريدًا إلكترونيًا، ويختار طريقة دفع، ويقبل الشروط. لا حاجة إلى حساب.
- تحوّل واجهة API الحجز إلى طلب (برقم مرجعي مثل
TKT-1042) في حالة بانتظار الدفع، بمبالغ الحجز. ولا يرسل المتصفح أي سعر أبدًا. - يدفع المشتري في صفحة المزوّد نفسها. ولا تُكتب بيانات البطاقة على موقعك أبدًا.
- يؤكد المزوّد، فتُصدر واجهة API تذكرة لكل مقعد أو مكان، وتجعل الطلب مدفوعًا، وترسل التذاكر بالبريد، وتُخطر الفريق. كل بريد عن الطلب يكون بلغة صفحة الموقع التي أتمّ المشتري الدفع منها، الإنجليزية أو العربية، مع عنوان الفعالية بتلك اللغة.
لا يقرر الموقع أبدًا أن الطلب مدفوع. وبينما ينتظر المشتري على «نؤكّد دفعتك الآن»، تسأل واجهة API المزوّد بنفسها، فتتحول الدفعة إلى تذاكر حتى على حاسوب محمول لا يصل إليه خطاف الويب الخاص بالمزوّد. الدفعة الملغاة تُبقي الحجز لمحاولة أخرى؛ والفاشلة تُبقي بيانات المشتري.
طرق الدفع
| الطريقة | تُضبط في .env الخاص بواجهة API | كيف يعمل |
|---|---|---|
| Stripe | STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET | صفحة Checkout المستضافة من Stripe. يعيد Stripe المشتري إلى الموقع، وتؤكد واجهة API من خطاف الويب الموقَّع أو بسؤال Stripe. |
| PayPal | PAYPAL_CLIENT_ID وPAYPAL_CLIENT_SECRET وPAYPAL_WEBHOOK_ID وPAYPAL_ENV (sandbox أو live) | يوافق المشتري على PayPal الذي يعيده إلى واجهة API؛ فتلتقط واجهة API الدفعة ثم ترسله إلى الموقع. |
| الدفع الاختباري | PAYMENTS_SIMULATOR (auto افتراضيًا، أو on أو off) | صفحة من الموقع تحل محل المزوّد، فيها ادفع ورفض وإلغاء. لا تحرّك أي مال. |
- يُعرض كل مزوّد متى ضُبطت مفاتيحه. استخدم مفاتيح الاختبار أولًا (
sk_test_...وsandbox في PayPal): فهي لا تحرّك أي مال. - مع
PAYMENTS_SIMULATOR=autoيُعرض الدفع الاختباري ما دام لا يوجد مفتاح حي، فيستطيع تثبيت جديد بيع تذكرة فورًا، ولا يظهر أبدًا في متجر حي. - تعرض الإعدادات ثم الدفع في اللوحة كل مزوّد متصلًا أو في وضع الاختبار أو غير مضبوط، مع المتغيرات التي تُضبط وعنوان خطاف الويب. ولا تُكتب المفاتيح في اللوحة أبدًا.
خطافات الويب
قبل الإطلاق، سجّل خطاف الويب لدى كل مزوّد على العنوان العام لواجهة API لديك:
| المزوّد | العنوان | الفعاليات |
|---|---|---|
| Stripe | https://<your-api>/api/webhooks/stripe | checkout.session.completed وcheckout.session.async_payment_succeeded وcheckout.session.async_payment_failed وrefund.updated. ويوضع سر توقيعه في STRIPE_WEBHOOK_SECRET. |
| PayPal | https://<your-api>/api/webhooks/paypal | PAYMENT.CAPTURE.COMPLETED وPAYMENT.CAPTURE.DENIED وPAYMENT.CAPTURE.REFUNDED. ويوضع معرّفه في PAYPAL_WEBHOOK_ID. |
يُتحقق من توقيع المزوّد في كل استدعاء قبل أي شيء آخر، ويُعمل بكل حدث مرة واحدة مهما تكرر وصوله. اضبط STOREFRONT_URL على عنوان الموقع، حيث ترجع صفحات الدفع بالمشترين، وPUBLIC_API_URL على عنوان واجهة API، لعودة PayPal.
التذاكر المجانية
نوع التذكرة المسعَّر بـ 0 لا يحمل رسومًا. وحين لا يكلّف الطلب شيئًا، لا تعرض صفحة الدفع طريقة دفع، ويظهر الإجمالي مجاني، ويؤكد احصل على التذاكر الطلب فورًا، مع بطاقاته وبريده وإشعار الفريق، بمفاتيح الدفع أو بدونها. لا يُسأل أي مزوّد، ولا حتى الدفع الاختباري.
يعرض الطلب المجاني "مجاني" كمزوّده. وليس فيه ما يُسترد: تُلغى تذاكره بدلًا من ذلك. فعالية Creative Mornings في البيانات التجريبية مجانية، وتبيع Meadow Days تذاكر مجانية للأطفال دون 12 عامًا.
رسوم الحجز والضريبة
- رسوم الحجز نسبة مئوية من سعر كل تذكرة، تُقرَّب مرة واحدة لكل تذكرة وتُضاف إلى إجمالي الحاضر عند الدفع: يدفعها الحاضر دائمًا. تُضبط في الإعدادات ثم عام، من 0 إلى 20% (
fee_bps، والقيمة 300 أي 3% في البيانات التجريبية: مقعدان بسعر $20.00 يصبحان $41.20). - العملة هي عملة مساحة العمل (USD في البيانات التجريبية)، وتُختار في التبويب نفسه من USD وEUR وGBP وSAR وAED، وتُقفل بعد دفع أول تذكرة.
- لا تفرض تيكيتوري أي ضريبة. أعدّ الضريبة لبلدك قبل استلام مدفوعات حقيقية. ورسوم مزوّدي الدفع منفصلة.
حالات الطلبات
| الحالة | المعنى |
|---|---|
| بانتظار الدفع | فتحت صفحة الدفع صفحة المزوّد؛ ولم يُدفع شيء بعد. |
| مدفوع | مؤكد، مع التذاكر. الطلب المجاني يكون مدفوعًا عند الدفع. |
| فشل الدفع | رفض المزوّد الدفعة. |
| منتهي | انتهى الحجز من دون دفع. |
| قيد المراجعة | اختلف المبلغ، أو وصلت دفعة بعد انتهاء الحجز وكانت مقاعده قد ذهبت. تردّ واجهة API مثل هذه الدفعة المتأخرة كاملة بنفسها، وتحسبها النظرة العامة ضمن ما يحتاج إلى انتباه. |
| مسترد جزئيًا، مسترد | استُردّت بعض تذاكره أو كلها. |
صفحة الطلبات
- بطاقات المدفوعة والمعلّقة والمستردّة والفاشلة مع أعدادها، وبحث برقم الطلب أو الاسم أو البريد، وفلاتر للفعالية وحالة الدفع (مدفوع ومجاني ومعلّق ومسترد وفشل وقيد المراجعة) والفترة. الأحدث أولًا، بعشرة طلبات في الصفحة، مع تصدير CSV.
- تعرض صفحة الطلب تفاصيله، والجدول الزمني للدفع مع رابط إلى لوحة Stripe أو PayPal نفسها، وتذاكره مع إعادة إصدار وإلغاء واسترداد، واستردادته.
الاستردادات
- الاستردادات لتذاكر كاملة. حدّد التذاكر في صفحة الطلب واضغط استرداد: تحسب واجهة API المبلغ (سعر كل تذكرة ورسومها) ولا يُكتب يدويًا أبدًا. اختر سببًا وضع علامة على أن الاسترداد يلغي حق الدخول.
- تُعلَّق التذاكر فورًا فلا يدخل بها أحد، ويكون الاسترداد معلّقًا إلى أن يؤكده المزوّد.
- عندما يؤكده، تُلغى التذاكر، وتعود مقاعدها أو أماكنها للبيع (إلا إذا كان حاملها قد دخل بالفعل)، ويصبح الطلب مستردًّا جزئيًا أو مستردًّا، ويصل المشتري بريد بلغة الطلب.
إذا رفض المزوّد أو لم يجب أبدًا، يصبح الاسترداد فاشلًا وتبقى التذاكر معلّقة إلى أن يقرر أحد: إعادة محاولة الاسترداد ترسله مرة أخرى بمفتاح المزوّد نفسه فلا يدفع مرتين أبدًا، وإعادة حق الدخول تعيد للتذاكر حق دخولها دون أن يتحرك أي مال. ويُسترد الطلب المدفوع بالدفع الاختباري بالطريقة نفسها، دون حركة أموال؛ واستردادات الطلبات التجريبية تستقر بعد ثوانٍ من طلبها.
تصل الفعالية الملغاة مشتريها بريدًا لكنها لا تحرّك مالًا: استرد كل طلب من صفحته.
من يستطيع فعل ماذا
| الصلاحية | يتيح | الأدوار التجريبية |
|---|---|---|
orders.view | قراءة الطلبات، وتلقي إشعارات المدفوعة منها | المالك والمدير والمالية |
refunds.create | الاسترداد وإعادة محاولته وإعادة حق الدخول | المالك والمالية |
tickets.manage | إعادة إصدار التذاكر وإلغاؤها | المالك والمالية |
settings.view | رؤية حالة مزوّدي الدفع | المالك |
المسارات خلفها
- يسرد
GET /api/checkout/methodsما يُعرض الآن؛ ويحتاجPOST /api/checkoutإلىX-Hold-Tokenالخاص بالحجز وIdempotency-Keyويجيب برقم الطلب المرجعي وصفحة المزوّد ورمز وصول للطلب يُرسل بعد ذلك باسمX-Order-Token. - الرقم المرجعي للطلب وحده لا يفتح شيئًا: يقرأ المشتري الطلب بذلك الرمز أو برمز الحاضر الخاص (bearer).
- يحتاج
POST /api/admin/orders/:reference/refundsإلىIdempotency-Keyوversionالخاص بالطلب؛ والإصدار الأقدم هو 409VERSION_CONFLICT. والطلب المجاني يجيب بـrefund_nothing_left.