115 lines
2.9 KiB
TypeScript
115 lines
2.9 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { getServerSession } from "next-auth";
|
|
import { authOptions } from "@/lib/auth";
|
|
import { isAdminEmail } from "@/lib/admin";
|
|
import { refundRepo } from "@/server/repositories/refund.repo";
|
|
import { buildCsv, csvDateJakarta, csvResponse } from "@/lib/csv";
|
|
|
|
export const runtime = "nodejs";
|
|
export const dynamic = "force-dynamic";
|
|
|
|
const VALID_STATUS = new Set([
|
|
"PENDING",
|
|
"APPROVED",
|
|
"REJECTED",
|
|
"PROCESSING",
|
|
"SUCCEEDED",
|
|
"FAILED",
|
|
]);
|
|
const VALID_REASON = new Set([
|
|
"USER_CANCELLATION",
|
|
"ORGANIZER_CANCELLED",
|
|
"TRIP_ISSUE",
|
|
"ADMIN_ADJUSTMENT",
|
|
"DISPUTE_RESOLVED",
|
|
]);
|
|
|
|
function parseDate(value: string | null): Date | undefined {
|
|
if (!value) return undefined;
|
|
const d = new Date(value);
|
|
return Number.isNaN(d.getTime()) ? undefined : d;
|
|
}
|
|
|
|
export async function GET(req: NextRequest) {
|
|
const session = await getServerSession(authOptions);
|
|
if (!session?.user || !isAdminEmail(session.user.email)) {
|
|
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
|
}
|
|
|
|
const params = req.nextUrl.searchParams;
|
|
const statusParam = params.get("status");
|
|
const status =
|
|
statusParam && VALID_STATUS.has(statusParam)
|
|
? (statusParam as
|
|
| "PENDING"
|
|
| "APPROVED"
|
|
| "REJECTED"
|
|
| "PROCESSING"
|
|
| "SUCCEEDED"
|
|
| "FAILED")
|
|
: undefined;
|
|
const reasonParam = params.get("reason");
|
|
const reason =
|
|
reasonParam && VALID_REASON.has(reasonParam)
|
|
? (reasonParam as
|
|
| "USER_CANCELLATION"
|
|
| "ORGANIZER_CANCELLED"
|
|
| "TRIP_ISSUE"
|
|
| "ADMIN_ADJUSTMENT"
|
|
| "DISPUTE_RESOLVED")
|
|
: undefined;
|
|
|
|
const rows = await refundRepo.listByStatus(status, {
|
|
dateFrom: parseDate(params.get("dateFrom")),
|
|
dateTo: parseDate(params.get("dateTo")),
|
|
reviewerEmail: params.get("reviewer") || undefined,
|
|
reason,
|
|
});
|
|
|
|
const csv = buildCsv(
|
|
[
|
|
"Refund ID",
|
|
"Status",
|
|
"Reason",
|
|
"Nominal (IDR)",
|
|
"Dilaporkan oleh",
|
|
"Catatan laporan",
|
|
"Catatan admin",
|
|
"Dibuat",
|
|
"Reviewed at",
|
|
"Succeeded at",
|
|
"Failed at",
|
|
"Reviewer email",
|
|
"Booking ID",
|
|
"Peserta nama",
|
|
"Peserta email",
|
|
"Trip ID",
|
|
"Trip judul",
|
|
"Trip tanggal",
|
|
],
|
|
rows.map((r) => [
|
|
r.id,
|
|
r.status,
|
|
r.reason,
|
|
r.amount,
|
|
r.reportedBy,
|
|
r.reportNote,
|
|
r.adminNote ?? "",
|
|
csvDateJakarta(r.createdAt),
|
|
csvDateJakarta(r.reviewedAt),
|
|
csvDateJakarta(r.succeededAt),
|
|
csvDateJakarta(r.failedAt),
|
|
r.reviewedBy?.email ?? "",
|
|
r.booking.id,
|
|
r.booking.user.name,
|
|
r.booking.user.email,
|
|
r.booking.trip.id,
|
|
r.booking.trip.title,
|
|
csvDateJakarta(r.booking.trip.date),
|
|
])
|
|
);
|
|
|
|
const today = new Date().toISOString().slice(0, 10);
|
|
return csvResponse(`refunds-${status ?? "all"}-${today}.csv`, csv);
|
|
}
|