110 lines
3.9 KiB
TypeScript
110 lines
3.9 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import crypto from 'crypto'
|
|
|
|
interface PayUResponse {
|
|
status: string
|
|
txnid: string
|
|
amount: string
|
|
productinfo: string
|
|
firstname: string
|
|
email: string
|
|
hash: string
|
|
key: string
|
|
[key: string]: string
|
|
}
|
|
|
|
/**
|
|
* PayU Payment Success Handler
|
|
* Processes successful payment responses from PayU gateway
|
|
*/
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const formData = await request.formData()
|
|
const payuResponse: Partial<PayUResponse> = {}
|
|
|
|
// Extract all PayU response parameters
|
|
for (const [key, value] of formData.entries()) {
|
|
payuResponse[key] = value.toString()
|
|
}
|
|
|
|
const { status, txnid, amount, productinfo, firstname, email, hash, key: merchantKey } = payuResponse
|
|
|
|
// Validate required parameters
|
|
if (!status || !txnid || !amount || !hash) {
|
|
console.error('Missing required PayU parameters')
|
|
return NextResponse.redirect(new URL('/payment/failed?error=invalid-response', request.url))
|
|
}
|
|
|
|
// Verify payment status
|
|
if (status !== 'success') {
|
|
console.log(`Payment failed for transaction: ${txnid}, status: ${status}`)
|
|
return NextResponse.redirect(new URL('/payment/failed?txn=' + txnid, request.url))
|
|
}
|
|
|
|
// Verify PayU hash for security
|
|
const merchantSalt = process.env.PAYU_MERCHANT_SALT || 'test-salt'
|
|
const expectedHashString = `${merchantSalt}|${status}|||||||||||${email}|${firstname}|${productinfo}|${amount}|${txnid}|${merchantKey}`
|
|
const expectedHash = crypto.createHash('sha512').update(expectedHashString).digest('hex').toLowerCase()
|
|
|
|
if (hash?.toLowerCase() !== expectedHash) {
|
|
console.error(`Hash mismatch for transaction: ${txnid}`)
|
|
// Log potential fraud attempt
|
|
console.error('Expected hash:', expectedHash)
|
|
console.error('Received hash:', hash?.toLowerCase())
|
|
return NextResponse.redirect(new URL('/payment/failed?error=hash-mismatch', request.url))
|
|
}
|
|
|
|
try {
|
|
// TODO: Update database with successful payment
|
|
// In a real implementation:
|
|
// await updateBillingStatus(txnid, 'success')
|
|
// await updateUserBalance(userSiliconId, parseFloat(amount))
|
|
|
|
console.log(`Payment successful for transaction: ${txnid}, amount: ₹${amount}`)
|
|
|
|
// Mock database update for demo
|
|
await mockUpdatePaymentStatus(txnid as string, 'success', parseFloat(amount as string))
|
|
|
|
// Redirect to success page with transaction details
|
|
const successUrl = new URL('/payment/success', request.url)
|
|
successUrl.searchParams.set('txn', txnid as string)
|
|
successUrl.searchParams.set('amount', amount as string)
|
|
|
|
return NextResponse.redirect(successUrl)
|
|
|
|
} catch (dbError) {
|
|
console.error('Database update error:', dbError)
|
|
// Even if DB update fails, payment was successful at gateway
|
|
// Log for manual reconciliation
|
|
return NextResponse.redirect(new URL('/payment/success?warning=db-update-failed&txn=' + txnid, request.url))
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Payment success handler error:', error)
|
|
return NextResponse.redirect(new URL('/payment/failed?error=processing-error', request.url))
|
|
}
|
|
}
|
|
|
|
// Mock function for demonstration
|
|
async function mockUpdatePaymentStatus(txnid: string, status: string, amount: number) {
|
|
// In real implementation, this would update MongoDB/database
|
|
console.log(`Mock DB Update: Transaction ${txnid} marked as ${status}, amount: ₹${amount}`)
|
|
|
|
// Simulate database operations
|
|
const billingUpdate = {
|
|
billing_id: txnid,
|
|
payment_status: status,
|
|
payment_date: new Date(),
|
|
amount: amount
|
|
}
|
|
|
|
const userBalanceUpdate = {
|
|
// This would update user's account balance for "add_balance" transactions
|
|
increment: status === 'success' && txnid.includes('balance') ? amount : 0
|
|
}
|
|
|
|
// Mock delay
|
|
await new Promise(resolve => setTimeout(resolve, 100))
|
|
|
|
return { billingUpdate, userBalanceUpdate }
|
|
} |