ai-wpa/app/api/payments/success/route.ts

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 }
}