238 lines
6.6 KiB
TypeScript
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:4024'
|
|
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',
|
|
},
|
|
]
|
|
}
|