148 lines
4.5 KiB
TypeScript
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 }
|
|
)
|
|
}
|
|
}
|