ai-wpa/app/api/balance/add/route.ts

238 lines
6.6 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import jwt from 'jsonwebtoken'
import crypto from 'crypto'
interface AddBalanceRequest {
amount: number
currency: 'INR' | 'USD'
}
interface UserTokenPayload {
siliconId: string
email: string
type: string
}
/**
* Add Balance API
* Initiates "Add Balance" transaction for user accounts
*/
export async function POST(request: NextRequest) {
try {
// Verify user authentication
const token = request.cookies.get('accessToken')?.value
if (!token) {
return NextResponse.json(
{ success: false, message: 'Authentication required' },
{ status: 401 }
)
}
const secret = process.env.JWT_SECRET || 'your-secret-key'
const user = jwt.verify(token, secret) as UserTokenPayload
// Parse request body
const body: AddBalanceRequest = await request.json()
const { amount, currency } = body
// Validate input
if (!amount || amount <= 0 || !['INR', 'USD'].includes(currency)) {
return NextResponse.json(
{ success: false, message: 'Invalid amount or currency' },
{ status: 400 }
)
}
// Validate amount limits
const minAmount = currency === 'INR' ? 100 : 2 // Minimum ₹100 or $2
const maxAmount = currency === 'INR' ? 100000 : 1500 // Maximum ₹1,00,000 or $1500
if (amount < minAmount || amount > maxAmount) {
return NextResponse.json(
{
success: false,
message: `Amount must be between ${currency === 'INR' ? '₹' : '$'}${minAmount} and ${currency === 'INR' ? '₹' : '$'}${maxAmount}`,
},
{ status: 400 }
)
}
try {
// Generate unique transaction ID
const transactionId = generateTransactionId()
// TODO: Save transaction to database
// In real implementation:
// await saveAddBalanceTransaction({
// siliconId: user.siliconId,
// amount,
// currency,
// transaction_id: transactionId,
// status: 'pending'
// })
// Mock database save for demo
await mockSaveAddBalanceTransaction(user.siliconId, amount, currency, transactionId)
// PayU configuration
const merchantKey = process.env.PAYU_MERCHANT_KEY || 'test-key'
const merchantSalt = process.env.PAYU_MERCHANT_SALT || 'test-salt'
const payuUrl = process.env.PAYU_URL || 'https://test.payu.in/_payment'
// Prepare payment data
const productinfo = 'add_balance'
const firstname = 'Customer'
const email = user.email
const phone = '9876543210' // Default phone or fetch from user profile
// Success and failure URLs for balance transactions
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:4023'
const surl = `${baseUrl}/api/balance/success`
const furl = `${baseUrl}/api/balance/failure`
// Generate PayU hash
const hashString = `${merchantKey}|${transactionId}|${amount}|${productinfo}|${firstname}|${email}|||||||||||${merchantSalt}`
const hash = crypto.createHash('sha512').update(hashString).digest('hex')
// Return payment form data for frontend submission
const paymentData = {
success: true,
transaction_id: transactionId,
currency,
payment_url: payuUrl,
form_data: {
key: merchantKey,
txnid: transactionId,
amount: amount.toFixed(2),
productinfo,
firstname,
email,
phone,
surl,
furl,
hash,
service_provider: 'payu_paisa',
},
}
return NextResponse.json(paymentData)
} catch (dbError) {
console.error('Database error during add balance:', dbError)
return NextResponse.json(
{ success: false, message: 'Failed to initiate balance transaction' },
{ status: 500 }
)
}
} catch (error) {
console.error('Add balance error:', error)
return NextResponse.json(
{ success: false, message: 'Add balance initiation failed' },
{ status: 500 }
)
}
}
/**
* Get Add Balance History
*/
export async function GET(request: NextRequest) {
try {
// Verify user authentication
const token = request.cookies.get('accessToken')?.value
if (!token) {
return NextResponse.json(
{ success: false, message: 'Authentication required' },
{ status: 401 }
)
}
const secret = process.env.JWT_SECRET || 'your-secret-key'
const user = jwt.verify(token, secret) as UserTokenPayload
// TODO: Fetch balance history from database
// In real implementation:
// const history = await getBalanceHistory(user.siliconId)
// Mock balance history for demo
const mockHistory = await getMockBalanceHistory(user.siliconId)
return NextResponse.json({
success: true,
balance_history: mockHistory,
})
} catch (error) {
console.error('Get balance history error:', error)
return NextResponse.json(
{ success: false, message: 'Failed to fetch balance history' },
{ status: 500 }
)
}
}
// Utility functions
function generateTransactionId(): string {
const timestamp = Date.now().toString(36)
const random = Math.random().toString(36).substr(2, 5)
return `bal_${timestamp}${random}`.toUpperCase()
}
// Mock functions for demonstration
async function mockSaveAddBalanceTransaction(
siliconId: string,
amount: number,
currency: string,
transactionId: string
) {
console.log(`Mock DB Save: Add Balance Transaction`)
console.log(`SiliconID: ${siliconId}, Amount: ${amount} ${currency}, TxnID: ${transactionId}`)
// Mock database record
const transaction = {
id: Date.now(),
silicon_id: siliconId,
transaction_id: transactionId,
amount,
currency,
status: 'pending',
created_at: new Date(),
updated_at: new Date(),
}
// Mock delay
await new Promise((resolve) => setTimeout(resolve, 100))
return transaction
}
async function getMockBalanceHistory(siliconId: string) {
// Mock balance transaction history
return [
{
id: 1,
transaction_id: 'BAL_123ABC',
amount: 1000,
currency: 'INR',
status: 'success',
created_at: '2025-01-15T10:30:00Z',
updated_at: '2025-01-15T10:31:00Z',
},
{
id: 2,
transaction_id: 'BAL_456DEF',
amount: 500,
currency: 'INR',
status: 'failed',
created_at: '2025-01-10T14:20:00Z',
updated_at: '2025-01-10T14:21:00Z',
},
{
id: 3,
transaction_id: 'BAL_789GHI',
amount: 2000,
currency: 'INR',
status: 'success',
created_at: '2025-01-05T09:15:00Z',
updated_at: '2025-01-05T09:16:00Z',
},
]
}