ai-wpa/app/api/transactions/route.ts

148 lines
4.5 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { authMiddleware } from '@/lib/auth-middleware'
import connectDB from '@/lib/mongodb'
import { Transaction } from '@/models/transaction'
import { Billing } from '@/models/billing'
// Query parameters schema
const TransactionQuerySchema = z.object({
page: z.string().optional().default('1'),
limit: z.string().optional().default('10'),
type: z.enum(['debit', 'credit', 'all']).optional().default('all'),
service: z.string().optional(),
})
export async function GET(request: NextRequest) {
try {
// Authenticate user
const user = await authMiddleware(request)
if (!user) {
return NextResponse.json(
{
success: false,
error: { message: 'Authentication required', code: 'UNAUTHORIZED' },
},
{ status: 401 }
)
}
await connectDB()
// Parse query parameters
const { searchParams } = new URL(request.url)
const queryParams = TransactionQuerySchema.parse({
page: searchParams.get('page') || undefined,
limit: searchParams.get('limit') || undefined,
type: searchParams.get('type') || undefined,
service: searchParams.get('service') || undefined,
})
const page = parseInt(queryParams.page)
const limit = Math.min(parseInt(queryParams.limit), 100) // Max 100 per page
const skip = (page - 1) * limit
// Build query filter
const filter: any = { email: user.email }
if (queryParams.type !== 'all') {
filter.type = queryParams.type
}
if (queryParams.service) {
filter.service = { $regex: queryParams.service, $options: 'i' }
}
// Build billing filter
const billingFilter: any = {
$or: [{ user: user.email }, { siliconId: user.id }],
}
// console.log('billingFilter', user.email)
if (queryParams.service) {
billingFilter.service = { $regex: queryParams.service, $options: 'i' }
}
// Get both transactions and billing records
const [transactions, billingRecords, transactionCount, billingCount] = await Promise.all([
Transaction.find(filter).sort({ createdAt: -1 }).lean().exec(),
Billing.find(billingFilter).sort({ createdAt: -1 }).lean().exec(),
Transaction.countDocuments(filter).exec(),
Billing.countDocuments(billingFilter).exec(),
])
// Transform billing records to transaction format
const transformedBillings = billingRecords.map((billing: any) => ({
_id: billing._id,
transactionId: billing.billing_id,
type: 'debit' as const,
amount: billing.amount,
service: billing.service,
serviceId: billing.serviceId,
description: billing.remarks || `${billing.service} - ${billing.cycle} billing`,
status: billing.status === 'pending' ? 'pending' : 'completed',
previousBalance: 0, // We don't have this data in billing
newBalance: 0, // We don't have this data in billing
createdAt: billing.createdAt,
updatedAt: billing.updatedAt,
email: billing.user,
userId: billing.siliconId,
}))
// Combine and sort all records
const allRecords = [...transactions, ...transformedBillings].sort(
(a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
)
// Apply type filter to combined records
const filteredRecords =
queryParams.type === 'all'
? allRecords
: allRecords.filter((record) => record.type === queryParams.type)
// Apply pagination to filtered records
const totalCount = filteredRecords.length
const paginatedRecords = filteredRecords.slice(skip, skip + limit)
const totalPages = Math.ceil(totalCount / limit)
return NextResponse.json({
success: true,
data: {
transactions: paginatedRecords,
pagination: {
page,
limit,
totalCount,
totalPages,
hasNext: page < totalPages,
hasPrev: page > 1,
},
},
})
} catch (error) {
console.error('Get transactions error:', error)
if (error instanceof z.ZodError) {
return NextResponse.json(
{
success: false,
error: {
message: 'Invalid query parameters',
code: 'VALIDATION_ERROR',
details: error.format(),
},
},
{ status: 400 }
)
}
return NextResponse.json(
{
success: false,
error: { message: 'Failed to fetch transactions', code: 'INTERNAL_ERROR' },
},
{ status: 500 }
)
}
}