← back to Freddy
app/api/revenue/route.ts
98 lines
import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { verifyAuth } from '@/lib/auth';
export async function GET(request: NextRequest) {
const user = verifyAuth(request);
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
try {
const statusFilter = request.nextUrl.searchParams.get('status');
let sql = `
SELECT r.id, r.match_id, r.org_id, r.granter_id,
r.fee_type, r.flat_fee, r.percentage_rate,
r.grant_amount, r.commission_amount,
r.status, r.invoice_date, r.paid_date, r.notes,
r.created_at, r.updated_at,
o.name as org_name,
g.name as granter_name,
CASE WHEN m.id IS NOT NULL THEN c.title ELSE NULL END as cause_title
FROM revenue r
LEFT JOIN organizations o ON o.id = r.org_id
LEFT JOIN granters g ON g.id = r.granter_id
LEFT JOIN matches m ON m.id = r.match_id
LEFT JOIN causes c ON m.id IS NOT NULL AND c.id = m.cause_id
`;
const params: unknown[] = [];
if (statusFilter) {
params.push(statusFilter);
sql += ` WHERE r.status = $${params.length}`;
}
sql += ' ORDER BY r.created_at DESC LIMIT 100';
const result = await query(sql, params);
// Calculate stats
const statsRes = await query(`
SELECT
COALESCE(SUM(COALESCE(commission_amount, 0) + COALESCE(flat_fee, 0)), 0)::numeric as total,
COALESCE(SUM(CASE WHEN status = 'pending' THEN COALESCE(commission_amount, 0) + COALESCE(flat_fee, 0) ELSE 0 END), 0)::numeric as pending,
COALESCE(SUM(CASE WHEN status = 'invoiced' THEN COALESCE(commission_amount, 0) + COALESCE(flat_fee, 0) ELSE 0 END), 0)::numeric as invoiced,
COALESCE(SUM(CASE WHEN status = 'paid' THEN COALESCE(commission_amount, 0) + COALESCE(flat_fee, 0) ELSE 0 END), 0)::numeric as paid
FROM revenue
`);
return NextResponse.json({
revenue: result.rows,
stats: {
total: parseFloat(statsRes.rows[0].total) || 0,
pending: parseFloat(statsRes.rows[0].pending) || 0,
invoiced: parseFloat(statsRes.rows[0].invoiced) || 0,
paid: parseFloat(statsRes.rows[0].paid) || 0,
},
});
} catch (err) {
console.error('[revenue] GET error:', (err as Error).message);
return NextResponse.json({ error: 'Failed to fetch revenue' }, { status: 500 });
}
}
export async function POST(request: NextRequest) {
const user = verifyAuth(request);
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
try {
const body = await request.json();
const { match_id, org_id, granter_id, fee_type, flat_fee, percentage_rate, grant_amount, notes } = body;
if (!fee_type) {
return NextResponse.json({ error: 'fee_type is required' }, { status: 400 });
}
// Calculate commission
let commission = flat_fee || 0;
if (percentage_rate && grant_amount) {
commission += (percentage_rate / 100) * grant_amount;
}
const result = await query(
`INSERT INTO revenue (match_id, org_id, granter_id, fee_type, flat_fee, percentage_rate, grant_amount, commission_amount, notes)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING *`,
[match_id || null, org_id || null, granter_id || null, fee_type, flat_fee || 0, percentage_rate || 0, grant_amount || null, commission, notes || null],
);
return NextResponse.json({ revenue: result.rows[0] }, { status: 201 });
} catch (err) {
console.error('[revenue] POST error:', (err as Error).message);
return NextResponse.json({ error: 'Failed to create revenue entry' }, { status: 500 });
}
}