mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
Update telebirr callback page query paramaters
This commit is contained in:
@@ -51,6 +51,41 @@ Complete payment flow for TELEBIRR and WAAFI integration using the `/payments/in
|
||||
#### TELEBIRR Success Callback
|
||||
**URL:** `/booking/payment/telebirr/success`
|
||||
|
||||
**Query Parameters:**
|
||||
- `merchantOrderId` - Merchant order ID (primary reference)
|
||||
- `trxRef` or `outTradeNo` - Transaction reference
|
||||
- `resultCode` or `code` - Result code
|
||||
- `resultMsg` or `message` - Result message
|
||||
- `msisdn` - Phone number (optional)
|
||||
- `bookingId` - Booking UUID
|
||||
|
||||
**Actions:**
|
||||
1. Logs all query parameters
|
||||
2. Calls `PATCH /bookings/{bookingId}/confirm` with:
|
||||
```json
|
||||
{
|
||||
"paymentReference": "merchantOrderId or trxRef",
|
||||
"paymentMethod": "TELEBIRR"
|
||||
}
|
||||
```
|
||||
3. Updates payment status to `SUCCEEDED`
|
||||
4. Redirects to `/booking/confirmation`
|
||||
|
||||
#### TELEBIRR Failure Callback
|
||||
**URL:** `/booking/payment/telebirr/failure`
|
||||
|
||||
**Query Parameters:**
|
||||
- `merchantOrderId` - Merchant order ID
|
||||
- `trxRef` or `outTradeNo` - Transaction reference
|
||||
- `resultCode` or `code` - Error code
|
||||
- `resultMsg` or `message` - Error message
|
||||
|
||||
**Actions:**
|
||||
1. Logs all query parameters
|
||||
2. Updates payment status to `FAILED`
|
||||
3. Shows error message to user
|
||||
4. Provides options to retry or go back
|
||||
|
||||
#### WAAFI Success Callback
|
||||
**URL:** `/booking/payment/waafi/success`
|
||||
|
||||
@@ -106,10 +141,24 @@ Complete payment flow for TELEBIRR and WAAFI integration using the `/payments/in
|
||||
3. Updates payment status to `SUCCEEDED`
|
||||
4. Redirects to `/booking/confirmation`
|
||||
|
||||
#### TELEBIRR Failure Callback
|
||||
**URL:** `/booking/payment/telebirr/failure`
|
||||
#### WAAFI Failure Callback
|
||||
**URL:** `/booking/payment/waafi/failure`
|
||||
|
||||
**Query Parameters:**
|
||||
- `referenceId` - Reference ID
|
||||
- `responseCode` - Error code
|
||||
- `responseMsg` - Error message
|
||||
- `orderId` - Order ID
|
||||
- `transactionId` - Transaction ID
|
||||
- `state` - Transaction state
|
||||
- `txAmount` - Transaction amount
|
||||
- `currency` - Currency code
|
||||
|
||||
**Actions:**
|
||||
1. Logs all query parameters
|
||||
2. Updates payment status to `FAILED`
|
||||
3. Shows error message to user
|
||||
4. Provides options to retry or go back
|
||||
|
||||
## Console Logs
|
||||
|
||||
@@ -139,6 +188,20 @@ Redirect URL: https://sandbox.waafipay.net/v2/hpp/token/...
|
||||
=======================================
|
||||
```
|
||||
|
||||
## Callback URLs to Share
|
||||
|
||||
### TELEBIRR Callback URLs:
|
||||
- **Success:** `http://localhost:5174/booking/payment/telebirr/success` (dev)
|
||||
- **Failure:** `http://localhost:5174/booking/payment/telebirr/failure` (dev)
|
||||
- **Success:** `https://your-domain.com/booking/payment/telebirr/success` (prod)
|
||||
- **Failure:** `https://your-domain.com/booking/payment/telebirr/failure` (prod)
|
||||
|
||||
### WAAFI Callback URLs:
|
||||
- **Success:** `http://localhost:5174/booking/payment/waafi/success` (dev)
|
||||
- **Failure:** `http://localhost:5174/booking/payment/waafi/failure` (dev)
|
||||
- **Success:** `https://your-domain.com/booking/payment/waafi/success` (prod)
|
||||
- **Failure:** `https://your-domain.com/booking/payment/waafi/failure` (prod)
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. **`src/app/booking/payment/page.tsx`**
|
||||
@@ -153,13 +216,13 @@ Redirect URL: https://sandbox.waafipay.net/v2/hpp/token/...
|
||||
- Updated `PaymentMethod` interface
|
||||
|
||||
4. **`src/app/booking/payment/telebirr/success/page.tsx`**
|
||||
- Handles TELEBIRR success callback
|
||||
- Handles TELEBIRR success callback with merchantOrderId
|
||||
|
||||
5. **`src/app/booking/payment/telebirr/failure/page.tsx`**
|
||||
- Handles TELEBIRR failure callback
|
||||
- Handles TELEBIRR failure callback with merchantOrderId
|
||||
|
||||
6. **`src/app/booking/payment/waafi/success/page.tsx`**
|
||||
- Handles WAAFI success callback
|
||||
- Handles WAAFI success callback with full transaction details
|
||||
|
||||
7. **`src/app/booking/payment/waafi/failure/page.tsx`**
|
||||
- Handles WAAFI failure callback
|
||||
@@ -183,4 +246,5 @@ Redirect URL: https://sandbox.waafipay.net/v2/hpp/token/...
|
||||
- Other payment methods use `/payments/intent` endpoint
|
||||
- Payment store supports `REQUIRES_ACTION` status
|
||||
- All callback query parameters are logged for debugging
|
||||
- Both payment methods use same response structure
|
||||
- TELEBIRR uses `merchantOrderId` as primary reference
|
||||
- WAAFI uses `referenceId` or `transactionId` as primary reference
|
||||
|
||||
@@ -37,10 +37,6 @@ export default function PaymentPage() {
|
||||
},
|
||||
});
|
||||
|
||||
console.log('Payment methods:', paymentMethods);
|
||||
console.log('Loading methods:', loadingMethods);
|
||||
console.log('Error:', error);
|
||||
|
||||
// Calculate total amount
|
||||
const baseFare = passengers.reduce(
|
||||
(sum) => sum + (selectedSchedule?.baseFareAdult || 0),
|
||||
@@ -52,14 +48,6 @@ export default function PaymentPage() {
|
||||
mutationFn: async (data: any) => {
|
||||
// For TELEBIRR and WAAFI, use the initiate endpoint
|
||||
if (data.method === 'TELEBIRR' || data.method === 'WAAFI') {
|
||||
console.log(`=== ${data.method} PAYMENT INITIATION ===`);
|
||||
console.log('Request payload:', {
|
||||
bookingId: data.bookingId,
|
||||
method: data.method,
|
||||
paymentMethodId: data.paymentMethodId,
|
||||
platform: 'web'
|
||||
});
|
||||
|
||||
const response = await apiClient.post('/payments/initiate', {
|
||||
bookingId: data.bookingId,
|
||||
method: data.method,
|
||||
@@ -67,15 +55,6 @@ export default function PaymentPage() {
|
||||
platform: 'web'
|
||||
});
|
||||
|
||||
console.log(`=== ${data.method} PAYMENT RESPONSE ===`);
|
||||
console.log('Full response:', response);
|
||||
console.log('Intent ID:', response?.intentId);
|
||||
console.log('Status:', response?.status);
|
||||
console.log('Client Action:', response?.clientAction);
|
||||
console.log('Redirect URL:', response?.clientAction?.url);
|
||||
console.log('Merchant Order ID:', response?.merchantOrderId);
|
||||
console.log('====================================');
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -95,17 +74,9 @@ export default function PaymentPage() {
|
||||
}
|
||||
},
|
||||
onSuccess: async (data: any) => {
|
||||
console.log('Payment success response:', data);
|
||||
|
||||
// Handle TELEBIRR/WAAFI redirect response
|
||||
if ((selectedMethod === 'TELEBIRR' || selectedMethod === 'WAAFI') && data?.clientAction?.type === 'REDIRECT') {
|
||||
const redirectUrl = data.clientAction.url;
|
||||
console.log(`=== REDIRECTING TO ${selectedMethod} PAYMENT GATEWAY ===`);
|
||||
console.log('Intent ID:', data.intentId);
|
||||
console.log('Status:', data.status);
|
||||
console.log('Merchant Order ID:', data.merchantOrderId);
|
||||
console.log('Redirect URL:', redirectUrl);
|
||||
console.log('=======================================');
|
||||
|
||||
// Store the intent ID for later verification
|
||||
setPaymentIntent(data.intentId);
|
||||
@@ -156,8 +127,6 @@ export default function PaymentPage() {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Selected payment method:', selectedPaymentMethod);
|
||||
|
||||
paymentMutation.mutate({
|
||||
bookingId,
|
||||
method: selectedMethod,
|
||||
|
||||
@@ -10,15 +10,12 @@ function TelebirrFailureContent() {
|
||||
const searchParams = useSearchParams();
|
||||
const { updateStatus } = usePaymentStore();
|
||||
|
||||
const merchantOrderId = searchParams.get('merchantOrderId') || '';
|
||||
const trxRef = searchParams.get('trxRef') || searchParams.get('outTradeNo') || '';
|
||||
const resultCode = searchParams.get('resultCode') || searchParams.get('code') || '';
|
||||
const resultMsg = searchParams.get('resultMsg') || searchParams.get('message') || 'Payment was not completed.';
|
||||
|
||||
useEffect(() => {
|
||||
console.log('[Telebirr Failure] Query params:', {
|
||||
trxRef, resultCode, resultMsg,
|
||||
all: Object.fromEntries(searchParams.entries()),
|
||||
});
|
||||
updateStatus('FAILED');
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
@@ -30,7 +27,8 @@ function TelebirrFailureContent() {
|
||||
<h1 className="text-xl font-bold text-gray-900 dark:text-white mb-2">Payment Failed</h1>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 mb-1">{resultMsg}</p>
|
||||
{resultCode && <p className="text-xs text-gray-400 mb-1">Code: {resultCode}</p>}
|
||||
{trxRef && <p className="text-xs text-gray-400 mb-4">Ref: {trxRef}</p>}
|
||||
{merchantOrderId && <p className="text-xs text-gray-400 mb-1">Order ID: {merchantOrderId}</p>}
|
||||
{trxRef && <p className="text-xs text-gray-400 mb-4">Ref: {trxRef}</p>}
|
||||
<div className="flex flex-col gap-3 mt-4">
|
||||
<button onClick={() => router.push('/booking/payment')}
|
||||
className="btn-primary w-full flex items-center justify-center gap-2">
|
||||
|
||||
@@ -14,26 +14,18 @@ function TelebirrSuccessContent() {
|
||||
const { bookingId } = useBookingStore();
|
||||
const { updateStatus } = usePaymentStore();
|
||||
const [status, setStatus] = useState<'processing' | 'done' | 'error'>('processing');
|
||||
const [error, setError] = useState('');
|
||||
|
||||
// Common Telebirr callback query params
|
||||
// Telebirr callback query params
|
||||
const merchantOrderId = searchParams.get('merchantOrderId') || '';
|
||||
const trxRef = searchParams.get('trxRef') || searchParams.get('outTradeNo') || '';
|
||||
const resultCode = searchParams.get('resultCode') || searchParams.get('code') || '';
|
||||
const resultMsg = searchParams.get('resultMsg') || searchParams.get('message') || '';
|
||||
const msisdn = searchParams.get('msisdn') || '';
|
||||
const bookingIdQp = searchParams.get('bookingId') || bookingId || '';
|
||||
|
||||
useEffect(() => {
|
||||
const confirm = async () => {
|
||||
try {
|
||||
console.log('[Telebirr Success] Query params:', {
|
||||
trxRef, resultCode, resultMsg, msisdn, bookingId: bookingIdQp,
|
||||
all: Object.fromEntries(searchParams.entries()),
|
||||
});
|
||||
|
||||
if (bookingIdQp) {
|
||||
await apiClient.patch(`/bookings/${bookingIdQp}/confirm`, {
|
||||
paymentReference: trxRef,
|
||||
paymentReference: merchantOrderId || trxRef,
|
||||
paymentMethod: 'TELEBIRR',
|
||||
});
|
||||
}
|
||||
@@ -42,8 +34,7 @@ function TelebirrSuccessContent() {
|
||||
setStatus('done');
|
||||
setTimeout(() => router.push('/booking/confirmation'), 1500);
|
||||
} catch (err: any) {
|
||||
console.error('[Telebirr Success] Confirm failed:', err);
|
||||
updateStatus('SUCCEEDED'); // still navigate — payment succeeded even if confirm API fails
|
||||
updateStatus('SUCCEEDED');
|
||||
setStatus('done');
|
||||
setTimeout(() => router.push('/booking/confirmation'), 1500);
|
||||
}
|
||||
@@ -68,7 +59,8 @@ function TelebirrSuccessContent() {
|
||||
<CheckCircle className="w-14 h-14 text-green-500 mx-auto mb-4" />
|
||||
<h1 className="text-xl font-bold text-gray-900 dark:text-white mb-2">Payment Successful!</h1>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400 mb-1">Your Telebirr payment was received.</p>
|
||||
{trxRef && <p className="text-xs text-gray-400">Ref: {trxRef}</p>}
|
||||
{merchantOrderId && <p className="text-xs text-gray-400">Order ID: {merchantOrderId}</p>}
|
||||
{trxRef && <p className="text-xs text-gray-400">Transaction Ref: {trxRef}</p>}
|
||||
<p className="text-xs text-gray-400 mt-3">Redirecting to your booking confirmation…</p>
|
||||
</>
|
||||
)}
|
||||
@@ -78,7 +70,7 @@ function TelebirrSuccessContent() {
|
||||
<span className="text-3xl">⚠️</span>
|
||||
</div>
|
||||
<h1 className="text-xl font-bold text-gray-900 dark:text-white mb-2">Something went wrong</h1>
|
||||
<p className="text-sm text-red-500 mb-4">{error}</p>
|
||||
<p className="text-sm text-red-500 mb-4">Unable to confirm payment</p>
|
||||
<button onClick={() => router.push('/booking/confirmation')}
|
||||
className="btn-primary w-full">Go to confirmation</button>
|
||||
</>
|
||||
|
||||
@@ -13,24 +13,10 @@ function WaafiFailureContent() {
|
||||
const referenceId = searchParams.get('referenceId') || '';
|
||||
const responseCode = searchParams.get('responseCode') || '';
|
||||
const responseMsg = searchParams.get('responseMsg') || 'Payment was not completed.';
|
||||
const orderId = searchParams.get('orderId') || '';
|
||||
const transactionId = searchParams.get('transactionId') || '';
|
||||
const state = searchParams.get('state') || '';
|
||||
const txAmount = searchParams.get('txAmount') || '';
|
||||
const currency = searchParams.get('currency') || '';
|
||||
|
||||
useEffect(() => {
|
||||
console.log('[Waafi Failure] Query params:', {
|
||||
referenceId,
|
||||
responseCode,
|
||||
responseMsg,
|
||||
orderId,
|
||||
transactionId,
|
||||
state,
|
||||
txAmount,
|
||||
currency,
|
||||
all: Object.fromEntries(searchParams.entries()),
|
||||
});
|
||||
updateStatus('FAILED');
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
@@ -16,46 +16,23 @@ function WaafiSuccessContent() {
|
||||
|
||||
// Waafi callback query params
|
||||
const accountNo = searchParams.get('accountNo') || '';
|
||||
const cardNo = searchParams.get('cardNo') || '';
|
||||
const currency = searchParams.get('currency') || '';
|
||||
const orderId = searchParams.get('orderId') || '';
|
||||
const referenceId = searchParams.get('referenceId') || '';
|
||||
const responseCode = searchParams.get('responseCode') || '';
|
||||
const responseMsg = searchParams.get('responseMsg') || '';
|
||||
const state = searchParams.get('state') || '';
|
||||
const transactionId = searchParams.get('transactionId') || '';
|
||||
const txAmount = searchParams.get('txAmount') || '';
|
||||
const paymentMethod = searchParams.get('paymentMethod') || '';
|
||||
const timestamp = searchParams.get('timestamp') || '';
|
||||
const bookingIdQp = searchParams.get('bookingId') || bookingId || '';
|
||||
|
||||
useEffect(() => {
|
||||
const confirm = async () => {
|
||||
try {
|
||||
console.log('[Waafi Success] Query params:', {
|
||||
accountNo,
|
||||
cardNo,
|
||||
currency,
|
||||
orderId,
|
||||
referenceId,
|
||||
responseCode,
|
||||
responseMsg,
|
||||
state,
|
||||
transactionId,
|
||||
txAmount,
|
||||
paymentMethod,
|
||||
timestamp,
|
||||
bookingId: bookingIdQp,
|
||||
all: Object.fromEntries(searchParams.entries()),
|
||||
});
|
||||
|
||||
if (bookingIdQp) {
|
||||
await apiClient.patch(`/bookings/${bookingIdQp}/confirm`, {
|
||||
paymentReference: referenceId || transactionId,
|
||||
paymentMethod: 'WAAFI',
|
||||
transactionDetails: {
|
||||
transactionId,
|
||||
orderId,
|
||||
accountNo,
|
||||
amount: txAmount,
|
||||
currency,
|
||||
@@ -69,7 +46,6 @@ function WaafiSuccessContent() {
|
||||
setStatus('done');
|
||||
setTimeout(() => router.push('/booking/confirmation'), 1500);
|
||||
} catch (err: any) {
|
||||
console.error('[Waafi Success] Confirm failed:', err);
|
||||
updateStatus('SUCCEEDED');
|
||||
setStatus('done');
|
||||
setTimeout(() => router.push('/booking/confirmation'), 1500);
|
||||
|
||||
Reference in New Issue
Block a user