140 lines
3.6 KiB
TypeScript
140 lines
3.6 KiB
TypeScript
import { prisma } from "@/lib/prisma";
|
|
import { Prisma } from "@/app/generated/prisma/client";
|
|
import type { PayoutStatus } from "@/app/generated/prisma/enums";
|
|
|
|
const payoutListInclude = {
|
|
booking: {
|
|
select: {
|
|
id: true,
|
|
amount: true,
|
|
status: true,
|
|
user: { select: { id: true, name: true, email: true } },
|
|
},
|
|
},
|
|
trip: {
|
|
select: { id: true, title: true, date: true, endDate: true, status: true },
|
|
},
|
|
organizer: { select: { id: true, name: true, email: true } },
|
|
processedBy: { select: { id: true, name: true, email: true } },
|
|
} satisfies Prisma.PayoutInclude;
|
|
|
|
export const payoutRepo = {
|
|
async findById(id: string) {
|
|
return prisma.payout.findUnique({
|
|
where: { id },
|
|
include: payoutListInclude,
|
|
});
|
|
},
|
|
|
|
async findByBookingId(bookingId: string, tx?: Prisma.TransactionClient) {
|
|
const client = tx ?? prisma;
|
|
return client.payout.findUnique({ where: { bookingId } });
|
|
},
|
|
|
|
async listByStatus(
|
|
status: PayoutStatus,
|
|
filters?: {
|
|
dateFrom?: Date;
|
|
dateTo?: Date;
|
|
processorEmail?: string;
|
|
}
|
|
) {
|
|
const where: Prisma.PayoutWhereInput = { status };
|
|
if (filters?.dateFrom || filters?.dateTo) {
|
|
where.createdAt = {
|
|
...(filters.dateFrom && { gte: filters.dateFrom }),
|
|
...(filters.dateTo && { lte: filters.dateTo }),
|
|
};
|
|
}
|
|
if (filters?.processorEmail) {
|
|
where.processedBy = { email: filters.processorEmail };
|
|
}
|
|
return prisma.payout.findMany({
|
|
where,
|
|
orderBy: { heldUntil: "asc" },
|
|
include: payoutListInclude,
|
|
});
|
|
},
|
|
|
|
async listForOrganizer(organizerId: string) {
|
|
return prisma.payout.findMany({
|
|
where: { organizerId },
|
|
orderBy: { createdAt: "desc" },
|
|
include: {
|
|
trip: {
|
|
select: { id: true, title: true, date: true, endDate: true, status: true },
|
|
},
|
|
booking: {
|
|
select: {
|
|
id: true,
|
|
amount: true,
|
|
user: { select: { id: true, name: true } },
|
|
},
|
|
},
|
|
},
|
|
});
|
|
},
|
|
|
|
async countByStatus(status: PayoutStatus) {
|
|
return prisma.payout.count({ where: { status } });
|
|
},
|
|
|
|
/** Payout terbaru untuk satu status — dipakai dashboard admin. */
|
|
async listRecent(status: PayoutStatus, limit = 3) {
|
|
return prisma.payout.findMany({
|
|
where: { status },
|
|
orderBy: status === "HELD" ? { heldUntil: "asc" } : { updatedAt: "desc" },
|
|
take: limit,
|
|
select: {
|
|
id: true,
|
|
amount: true,
|
|
heldUntil: true,
|
|
releasedAt: true,
|
|
organizer: { select: { id: true, name: true } },
|
|
trip: { select: { id: true, title: true } },
|
|
},
|
|
});
|
|
},
|
|
|
|
async create(
|
|
data: Pick<
|
|
Prisma.PayoutUncheckedCreateInput,
|
|
| "bookingId"
|
|
| "tripId"
|
|
| "organizerId"
|
|
| "amount"
|
|
| "heldUntil"
|
|
| "bankName"
|
|
| "bankAccountNumber"
|
|
| "bankAccountName"
|
|
>,
|
|
tx?: Prisma.TransactionClient
|
|
) {
|
|
const client = tx ?? prisma;
|
|
return client.payout.create({ data });
|
|
},
|
|
|
|
async update(
|
|
id: string,
|
|
data: Prisma.PayoutUncheckedUpdateInput,
|
|
tx?: Prisma.TransactionClient
|
|
) {
|
|
const client = tx ?? prisma;
|
|
return client.payout.update({ where: { id }, data });
|
|
},
|
|
|
|
/** Cari semua HELD payout yang sudah lewat heldUntil & trip-nya COMPLETED. */
|
|
async findEligibleForRelease(now: Date) {
|
|
return prisma.payout.findMany({
|
|
where: {
|
|
status: "HELD",
|
|
heldUntil: { lte: now },
|
|
trip: { status: "COMPLETED" },
|
|
},
|
|
select: { id: true },
|
|
});
|
|
},
|
|
};
|
|
|
|
export type PayoutWithRelations = Awaited<ReturnType<typeof payoutRepo.findById>>;
|