6.2 KiB
entry پرداخت بهصورت ریدایرکت خالص به Backend (بدون XHR) — سایت عمومی
پروژه
nobat724_front (سایت عمومی). cross-repo — پرامپت همتا (Backend، اول اجرا شود): clinicpro/.claude/prompt/payment-single-flow-consolidation.md.
زمینه
طبق معماری واحد پرداخت، سایت عمومی نباید هیچ API برای شروع پرداخت صدا بزند؛ فقط مرورگر را به Backend ریدایرکت کند. Backend یک entry ریدایرکتِ خالص دارد:
GET {API}/api/v1/payment/order/{appointmentUuid}?gateway=<name>&return=<frontend_return_url>
Backend این آدرس را میگیرد، سفارش را اعتبارسنجی میکند، Payment میسازد، به بانک وصل میشود و کاربر را به شاپرک میفرستد؛ در پایان به return (همان دامنهٔ مبدأ) با ?status=... برمیگردد.
وضعیت فعلی سایت: components/appointment/paying/index.js هنوز با XHR (request.postAppointmentPayment) پرداخت را شروع میکند و بعد به pay_url میرود. طبق نیاز جدید باید این XHR حذف شود و دکمهٔ پرداخت مستقیماً به payment/order/{uuid} ریدایرکت کند.
مشکل / هدف
حذف کامل فراخوانی API برای شروع پرداخت در سایت عمومی؛ دکمهٔ پرداخت = ریدایرکت مرورگر به GET {API}/api/v1/payment/order/{appointmentUuid}?gateway=...&return=.... انتخاب درگاه (در صورت چند درگاه) قبل از ریدایرکت انجام شود؛ اگر یک درگاه فعال باشد، خودکار.
فایلهای مرتبط
| فایل | نقش |
|---|---|
components/appointment/paying/index.js |
دکمهٔ پرداخت + انتخاب درگاه (از getPaymentConfig) |
services/response.js |
getPaymentConfig (برای فهرست درگاههای فعال) — بدون تغییر |
app/payment/result/page.js |
بازگشت از Backend با status — بدون تغییر |
app/payment/[uuid]/page.js |
نمایش نتیجه — بدون تغییر |
وضعیت فعلی
// components/appointment/paying/index.js
const handlePayment = async () => {
if (!appointmentId) return;
if (!testMode && !selectedBank) return;
setLoading(true);
try {
const res = await request.postAppointmentPayment({ // ❌ XHR برای شروع پرداخت
appointment_uuid: appointmentId,
gateway: testMode ? "mellat" : selectedBank,
frontend_address: `${window.location.origin}/payment/result`,
});
const payUrl = res?.data?.pay_url;
if (payUrl) { window.location.href = payUrl; return; }
throw new Error("pay_url missing");
} catch (error) { alert("خطا در شروع پرداخت..."); setLoading(false); }
};
getPaymentConfig از قبل درگاههای فعال را در gateways میدهد و selectedBank/testMode ست میشوند (بدون تغییر میمانند).
وظایف
۱. تبدیل دکمهٔ پرداخت به ریدایرکتِ خالص (حذف XHR)
handlePayment را طوری بازنویسی کن که بهجای XHR، مستقیماً مرورگر را به entry بکاند ببرد:
const handlePayment = () => {
if (!appointmentId) return;
const gateway = testMode ? "mellat" : selectedBank;
if (!gateway) return; // باید یک درگاه انتخاب شده باشد
setLoading(true);
const apiBase = process.env.NEXT_PUBLIC_API_URL;
const ret = encodeURIComponent(`${window.location.origin}/payment/result`);
window.location.href =
`${apiBase}/api/v1/payment/order/${appointmentId}` +
`?gateway=${encodeURIComponent(gateway)}&return=${ret}`;
};
handlePaymentدیگرasyncنیست و هیچrequest.*صدا نمیزند.NEXT_PUBLIC_API_URLهمان base بکاند است (مثل بقیهٔ سایت).appointmentIdهمانappointment_uuidاست (capability؛ در URL میرود).
۲. حفظ انتخاب درگاه (مرحلهٔ ۲ نیاز)
getPaymentConfigو stategateways/selectedBank/testModeبدون تغییر بمانند؛ Select فقط وقتی چند درگاه فعال است نمایش داده شود.- اگر فقط یک درگاه فعال باشد،
selectedBankاز قبل روی همان ست است (پیشفرضgateways[0]), پس مرحله خودکار است. - دکمه وقتی
!testMode && !selectedBankاستdisabledبماند (از قبل هست).
۳. پاکسازی
- اگر
request.postAppointmentPaymentدیگر جای دیگری استفاده نمیشود، آن را ازservices/response.jsحذف کن (بررسی با grep). اگر جای دیگری استفاده میشود، نگهدار. app/payment/result/page.jsوapp/payment/[uuid]/page.jsبدون تغییر (بازگشت باstatusرا از قبل مدیریت میکنند).
نکات مهم
- هیچ فراخوانی API برای شروع پرداخت نباید بماند — فقط ریدایرکت full-page به
{API}/api/v1/payment/order/{uuid}. Backend همهٔ ارتباط با بانک را انجام میدهد. - بازگشت به دامنهٔ مبدأ:
return=${window.location.origin}/payment/resultتضمین میکند Backend بعد از پرداخت به همین دامنهٔ چند-شهری برگردد؛ Backend این آدرس را در برابرpayment_allowed_frontend_hostsاعتبارسنجی میکند (host دامنه باید whitelist باشد). - انتخاب درگاه همچنان از
GET /api/v1/payment/config(gatewaysفعال) است — درگاه هاردکد نکن. - App Router؛
payingیک client component است (use client). فونت/استایل موجود (MUI + Tailwind, RTL). - بعد از تغییر:
npm run build. تست دستی: کلیک پرداخت → مرورگر به{API}/api/v1/payment/order/...میرود (نه XHR)، سپس شاپرک، سپس بازگشت به/payment/result?status=....