ai-wpa/app/api/admin/billing/route.ts

184 lines
5.6 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { withAdminAuth } from '@/lib/admin-middleware'
import { connectDB } from '@/lib/mongodb'
import { Billing } from '@/models/billing'
import { Transaction } from '@/models/transaction'
import { z } from 'zod'
const BillingUpdateSchema = z.object({
payment_status: z.enum(['pending', 'completed', 'failed', 'refunded']).optional(),
service_status: z.enum(['active', 'inactive', 'suspended', 'cancelled']).optional(),
amount: z.number().min(0).optional(),
notes: z.string().optional(),
})
export async function GET(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
const { searchParams } = new URL(request.url)
const page = parseInt(searchParams.get('page') || '1')
const limit = parseInt(searchParams.get('limit') || '20')
const search = searchParams.get('search') || ''
const serviceType = searchParams.get('serviceType') || ''
const paymentStatus = searchParams.get('paymentStatus') || ''
const dateFrom = searchParams.get('dateFrom')
const dateTo = searchParams.get('dateTo')
const skip = (page - 1) * limit
// Build filter query
const filter: any = {}
if (search) {
filter.$or = [
{ user_email: { $regex: search, $options: 'i' } },
{ silicon_id: { $regex: search, $options: 'i' } },
{ service_name: { $regex: search, $options: 'i' } },
]
}
if (serviceType && serviceType !== 'all') {
filter.service_type = serviceType
}
if (paymentStatus && paymentStatus !== 'all') {
filter.payment_status = paymentStatus
}
if (dateFrom || dateTo) {
filter.created_at = {}
if (dateFrom) filter.created_at.$gte = new Date(dateFrom)
if (dateTo) filter.created_at.$lte = new Date(dateTo)
}
const [billings, totalBillings] = await Promise.all([
Billing.find(filter).sort({ created_at: -1 }).skip(skip).limit(limit),
Billing.countDocuments(filter),
])
const totalPages = Math.ceil(totalBillings / limit)
// Calculate summary statistics for current filter
const summaryStats = await Billing.aggregate([
{ $match: filter },
{
$group: {
_id: null,
totalAmount: { $sum: '$amount' },
totalTax: { $sum: '$tax_amount' },
totalDiscount: { $sum: '$discount_applied' },
completedCount: {
$sum: { $cond: [{ $eq: ['$payment_status', 'completed'] }, 1, 0] },
},
pendingCount: {
$sum: { $cond: [{ $eq: ['$payment_status', 'pending'] }, 1, 0] },
},
failedCount: {
$sum: { $cond: [{ $eq: ['$payment_status', 'failed'] }, 1, 0] },
},
},
},
])
return NextResponse.json({
billings,
pagination: {
currentPage: page,
totalPages,
totalBillings,
hasNext: page < totalPages,
hasPrev: page > 1,
},
summary: summaryStats[0] || {
totalAmount: 0,
totalTax: 0,
totalDiscount: 0,
completedCount: 0,
pendingCount: 0,
failedCount: 0,
},
})
} catch (error) {
console.error('Admin billing fetch error:', error)
return NextResponse.json({ error: 'Failed to fetch billing data' }, { status: 500 })
}
})
}
export async function POST(request: NextRequest) {
return withAdminAuth(request, async (req, admin) => {
try {
await connectDB()
const body = await request.json()
const { action, billingId, data } = body
if (action === 'update') {
const validatedData = BillingUpdateSchema.parse(data)
const billing = await Billing.findByIdAndUpdate(
billingId,
{
...validatedData,
updated_at: new Date(),
},
{ new: true, runValidators: true }
)
if (!billing) {
return NextResponse.json({ error: 'Billing record not found' }, { status: 404 })
}
return NextResponse.json({ billing })
}
if (action === 'refund') {
const billing = await Billing.findById(billingId)
if (!billing) {
return NextResponse.json({ error: 'Billing record not found' }, { status: 404 })
}
if (billing.payment_status !== 'paid') {
return NextResponse.json({ error: 'Can only refund paid payments' }, { status: 400 })
}
// Update billing status
billing.payment_status = 'refunded'
billing.status = 'cancelled'
await billing.save()
// Create refund transaction
const refundTransaction = new Transaction({
userId: billing.user_id,
type: 'credit',
amount: billing.amount,
description: `Refund for ${billing.service_name}`,
status: 'completed',
reference: `refund_${billing._id}`,
metadata: {
originalBillingId: billing._id,
refundedBy: admin.id,
refundReason: data.refundReason || 'Admin refund',
},
})
await refundTransaction.save()
return NextResponse.json({
billing,
transaction: refundTransaction,
message: 'Refund processed successfully',
})
}
return NextResponse.json({ error: 'Invalid action' }, { status: 400 })
} catch (error) {
console.error('Admin billing action error:', error)
return NextResponse.json({ error: 'Failed to perform billing action' }, { status: 500 })
}
})
}