initial commit
This commit is contained in:
147
app/api/transactions/route.ts
Normal file
147
app/api/transactions/route.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
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 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user