171 lines
4.5 KiB
TypeScript
171 lines
4.5 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
|
|
// Alpha: In-memory membership fee storage
|
|
const membershipFees: Map<string, {
|
|
id: string;
|
|
leagueId: string;
|
|
seasonId?: string;
|
|
type: 'season' | 'monthly' | 'per_race';
|
|
amount: number;
|
|
enabled: boolean;
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
}> = new Map();
|
|
|
|
const memberPayments: Map<string, {
|
|
id: string;
|
|
feeId: string;
|
|
driverId: string;
|
|
amount: number;
|
|
platformFee: number;
|
|
netAmount: number;
|
|
status: 'pending' | 'paid' | 'overdue';
|
|
dueDate: Date;
|
|
paidAt?: Date;
|
|
}> = new Map();
|
|
|
|
const PLATFORM_FEE_RATE = 0.10;
|
|
|
|
export async function GET(request: NextRequest) {
|
|
const { searchParams } = new URL(request.url);
|
|
const leagueId = searchParams.get('leagueId');
|
|
const driverId = searchParams.get('driverId');
|
|
|
|
if (!leagueId) {
|
|
return NextResponse.json(
|
|
{ error: 'leagueId is required' },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
const fee = Array.from(membershipFees.values()).find(f => f.leagueId === leagueId);
|
|
|
|
let payments: typeof memberPayments extends Map<string, infer V> ? V[] : never[] = [];
|
|
if (driverId) {
|
|
payments = Array.from(memberPayments.values()).filter(
|
|
p => membershipFees.get(p.feeId)?.leagueId === leagueId && p.driverId === driverId
|
|
);
|
|
}
|
|
|
|
return NextResponse.json({ fee, payments });
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const body = await request.json();
|
|
const { leagueId, seasonId, type, amount } = body;
|
|
|
|
if (!leagueId || !type || amount === undefined) {
|
|
return NextResponse.json(
|
|
{ error: 'Missing required fields: leagueId, type, amount' },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
if (!['season', 'monthly', 'per_race'].includes(type)) {
|
|
return NextResponse.json(
|
|
{ error: 'Type must be "season", "monthly", or "per_race"' },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Check for existing fee config
|
|
const existingFee = Array.from(membershipFees.values()).find(f => f.leagueId === leagueId);
|
|
|
|
if (existingFee) {
|
|
// Update existing fee
|
|
existingFee.type = type;
|
|
existingFee.amount = amount;
|
|
existingFee.seasonId = seasonId || existingFee.seasonId;
|
|
existingFee.enabled = amount > 0;
|
|
existingFee.updatedAt = new Date();
|
|
membershipFees.set(existingFee.id, existingFee);
|
|
return NextResponse.json({ fee: existingFee });
|
|
}
|
|
|
|
const id = `fee-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
const fee = {
|
|
id,
|
|
leagueId,
|
|
seasonId: seasonId || undefined,
|
|
type,
|
|
amount,
|
|
enabled: amount > 0,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
};
|
|
|
|
membershipFees.set(id, fee);
|
|
|
|
return NextResponse.json({ fee }, { status: 201 });
|
|
} catch (err) {
|
|
console.error('Membership fee creation failed:', err);
|
|
return NextResponse.json(
|
|
{ error: 'Failed to create membership fee' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|
|
|
|
// Record a member payment
|
|
export async function PATCH(request: NextRequest) {
|
|
try {
|
|
const body = await request.json();
|
|
const { feeId, driverId, status, paidAt } = body;
|
|
|
|
if (!feeId || !driverId) {
|
|
return NextResponse.json(
|
|
{ error: 'Missing required fields: feeId, driverId' },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
const fee = membershipFees.get(feeId);
|
|
if (!fee) {
|
|
return NextResponse.json(
|
|
{ error: 'Membership fee configuration not found' },
|
|
{ status: 404 }
|
|
);
|
|
}
|
|
|
|
// Find or create payment record
|
|
let payment = Array.from(memberPayments.values()).find(
|
|
p => p.feeId === feeId && p.driverId === driverId
|
|
);
|
|
|
|
if (!payment) {
|
|
const platformFee = fee.amount * PLATFORM_FEE_RATE;
|
|
const netAmount = fee.amount - platformFee;
|
|
|
|
const paymentId = `mp-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
payment = {
|
|
id: paymentId,
|
|
feeId,
|
|
driverId,
|
|
amount: fee.amount,
|
|
platformFee,
|
|
netAmount,
|
|
status: 'pending',
|
|
dueDate: new Date(),
|
|
};
|
|
memberPayments.set(paymentId, payment);
|
|
}
|
|
|
|
if (status) {
|
|
payment.status = status;
|
|
}
|
|
if (paidAt || status === 'paid') {
|
|
payment.paidAt = paidAt ? new Date(paidAt) : new Date();
|
|
}
|
|
|
|
memberPayments.set(payment.id, payment);
|
|
|
|
return NextResponse.json({ payment });
|
|
} catch (err) {
|
|
console.error('Member payment update failed:', err);
|
|
return NextResponse.json(
|
|
{ error: 'Failed to update member payment' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
} |