refund roadmap pr-1 and pr-2

This commit is contained in:
2026-05-11 13:04:20 +07:00
parent d2b0a780d5
commit 54f4569107
36 changed files with 5750 additions and 19 deletions
+99
View File
@@ -0,0 +1,99 @@
"use server";
import { getServerSession } from "next-auth";
import { revalidatePath } from "next/cache";
import { authOptions } from "@/lib/auth";
import { isAdminEmail } from "@/lib/admin";
import { refundService } from "@/server/services/refund.service";
import { createRefundSchema, refundDecisionSchema } from "./schemas";
async function requireAdmin() {
const session = await getServerSession(authOptions);
if (!session?.user || !isAdminEmail(session.user.email)) {
return null;
}
return session.user;
}
export async function createRefundAction(formData: FormData) {
const admin = await requireAdmin();
if (!admin) return { error: "Tidak memiliki akses admin" };
const parsed = createRefundSchema.safeParse({
bookingId: formData.get("bookingId") as string,
reason: formData.get("reason") as string,
reportedBy: formData.get("reportedBy") as string,
reportNote: formData.get("reportNote") as string,
amount: (formData.get("amount") as string) || undefined,
});
if (!parsed.success) {
return { error: parsed.error.issues[0].message };
}
try {
await refundService.requestRefund({
bookingId: parsed.data.bookingId,
reason: parsed.data.reason,
reportedBy: parsed.data.reportedBy,
reportNote: parsed.data.reportNote,
amount: parsed.data.amount,
initiatedByAdminId: admin.id,
});
revalidatePath("/admin/refunds");
return { success: true };
} catch (err) {
return { error: (err as Error).message };
}
}
export async function decideRefundAction(formData: FormData) {
const admin = await requireAdmin();
if (!admin) return { error: "Tidak memiliki akses admin" };
const parsed = refundDecisionSchema.safeParse({
refundId: formData.get("refundId") as string,
decision: formData.get("decision") as string,
adminNote: (formData.get("adminNote") as string) || undefined,
});
if (!parsed.success) {
return { error: parsed.error.issues[0].message };
}
const { refundId, decision, adminNote } = parsed.data;
const needsNote = decision === "REJECT" || decision === "SUCCEEDED" || decision === "FAILED";
if (needsNote && (!adminNote || !adminNote.trim())) {
return { error: "Catatan/alasan admin wajib diisi untuk tindakan ini" };
}
try {
if (decision === "APPROVE") {
await refundService.approveRefund({
refundId,
adminId: admin.id,
adminNote,
});
} else if (decision === "REJECT") {
await refundService.rejectRefund({
refundId,
adminId: admin.id,
adminNote: adminNote!,
});
} else if (decision === "SUCCEEDED") {
await refundService.markSucceededManual({
refundId,
adminId: admin.id,
adminNote: adminNote!,
});
} else {
await refundService.markFailed({
refundId,
adminId: admin.id,
adminNote: adminNote!,
});
}
revalidatePath("/admin/refunds");
return { success: true };
} catch (err) {
return { error: (err as Error).message };
}
}