import { prisma } from "@/lib/prisma"; import { Prisma } from "@/app/generated/prisma/client"; const refundListInclude = { booking: { include: { trip: { select: { id: true, title: true, date: true, organizerId: true } }, user: { select: { id: true, name: true, email: true, image: true } }, payments: { orderBy: { createdAt: "desc" }, select: { id: true, provider: true, method: true, amount: true, status: true, paidAt: true, }, }, }, }, payment: { select: { id: true, provider: true, method: true, amount: true, status: true, }, }, reviewedBy: { select: { id: true, name: true, email: true } }, } satisfies Prisma.RefundInclude; export const refundRepo = { async findById(id: string) { return prisma.refund.findUnique({ where: { id }, include: refundListInclude, }); }, async listByStatus( status?: "PENDING" | "APPROVED" | "REJECTED" | "PROCESSING" | "SUCCEEDED" | "FAILED", filters?: { dateFrom?: Date; dateTo?: Date; reviewerEmail?: string; reason?: | "USER_CANCELLATION" | "ORGANIZER_CANCELLED" | "TRIP_ISSUE" | "ADMIN_ADJUSTMENT" | "DISPUTE_RESOLVED"; } ) { const where: Prisma.RefundWhereInput = {}; if (status) where.status = status; if (filters?.dateFrom || filters?.dateTo) { where.createdAt = { ...(filters.dateFrom && { gte: filters.dateFrom }), ...(filters.dateTo && { lte: filters.dateTo }), }; } if (filters?.reviewerEmail) { where.reviewedBy = { email: filters.reviewerEmail }; } if (filters?.reason) { where.reason = filters.reason; } return prisma.refund.findMany({ where, orderBy: { createdAt: "desc" }, include: refundListInclude, }); }, async countByStatus( status: "PENDING" | "APPROVED" | "REJECTED" | "PROCESSING" | "SUCCEEDED" | "FAILED" ) { return prisma.refund.count({ where: { status } }); }, /** Refund terbaru untuk satu status — dipakai dashboard admin. */ async listRecent( status: "PENDING" | "APPROVED" | "REJECTED" | "PROCESSING" | "SUCCEEDED" | "FAILED", limit = 3 ) { return prisma.refund.findMany({ where: { status }, orderBy: { createdAt: "desc" }, take: limit, select: { id: true, amount: true, reason: true, createdAt: true, booking: { select: { user: { select: { id: true, name: true } }, trip: { select: { id: true, title: true } }, }, }, }, }); }, async listByBooking(bookingId: string) { return prisma.refund.findMany({ where: { bookingId }, orderBy: { createdAt: "desc" }, }); }, /** Total nominal yang sudah SUCCEEDED untuk satu booking. Dipakai service untuk * validasi `SUM(SUCCEEDED) + new.amount <= payment.amount`. */ async sumSucceededAmount(bookingId: string, tx?: Prisma.TransactionClient): Promise { const client = tx ?? prisma; const agg = await client.refund.aggregate({ where: { bookingId, status: "SUCCEEDED" }, _sum: { amount: true }, }); return agg._sum.amount ?? 0; }, /** Pending + approved + processing — refund yang "in-flight" (belum settled). * Dipakai untuk cek apakah booking masih punya refund aktif. */ async hasActiveRefund(bookingId: string, tx?: Prisma.TransactionClient): Promise { const client = tx ?? prisma; const count = await client.refund.count({ where: { bookingId, status: { in: ["PENDING", "APPROVED", "PROCESSING"] }, }, }); return count > 0; }, async create( data: Pick< Prisma.RefundUncheckedCreateInput, | "bookingId" | "paymentId" | "amount" | "reason" | "reportedBy" | "reportNote" | "initiatedBy" | "idempotencyKey" >, tx?: Prisma.TransactionClient ) { const client = tx ?? prisma; return client.refund.create({ data }); }, async update( id: string, data: Prisma.RefundUncheckedUpdateInput, tx?: Prisma.TransactionClient ) { const client = tx ?? prisma; return client.refund.update({ where: { id }, data }); }, }; export type RefundWithRelations = Awaited>;