/** * Backfill Booking + Payment dari TripParticipant lama. * * Idempotent — jalan ulang aman. Skip baris yang sudah punya Booking. * * Mapping: * - participant.status === "CANCELLED" → Booking CANCELLED, no Payment * - participant.status === "PENDING" → Booking PENDING, no Payment * - participant.status === "CONFIRMED" + free → Booking PAID, no Payment * - participant.status === "CONFIRMED" + paid: * - paymentConfirmedAt set → Booking PAID, Payment PAID (paidAt = paymentConfirmedAt) * - markedPaidAt set, no confirm → Booking AWAITING_PAY, Payment AWAITING * - neither → Booking AWAITING_PAY, no Payment * * Jalankan: `npx tsx prisma/backfill-bookings.ts` */ import { PrismaClient, Prisma } from "../app/generated/prisma/client"; import { PrismaPg } from "@prisma/adapter-pg"; const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL!, }); const prisma = new PrismaClient({ adapter }); async function main() { const participants = await prisma.tripParticipant.findMany({ include: { trip: { select: { price: true } }, booking: { select: { id: true } }, }, orderBy: { createdAt: "asc" }, }); let createdBookings = 0; let createdPayments = 0; let skipped = 0; for (const p of participants) { if (p.booking) { skipped++; continue; } const isFree = p.trip.price <= 0; let bookingStatus: Prisma.BookingCreateInput["status"]; if (p.status === "CANCELLED") { bookingStatus = "CANCELLED"; } else if (p.status === "PENDING") { bookingStatus = "PENDING"; } else if (isFree) { bookingStatus = "PAID"; } else if (p.paymentConfirmedAt) { bookingStatus = "PAID"; } else { bookingStatus = "AWAITING_PAY"; } const booking = await prisma.booking.create({ data: { tripId: p.tripId, userId: p.userId, participantId: p.id, amount: p.trip.price, status: bookingStatus, }, }); createdBookings++; // Payment row hanya kalau ada jejak pembayaran manual if (!isFree && (p.markedPaidAt || p.paymentConfirmedAt)) { const paymentStatus: Prisma.PaymentCreateInput["status"] = p.paymentConfirmedAt ? "PAID" : "AWAITING"; await prisma.payment.create({ data: { bookingId: booking.id, provider: "MANUAL", externalOrderId: `manual-${booking.id}`, amount: p.trip.price, status: paymentStatus, method: "manual_transfer", paidAt: p.paymentConfirmedAt ?? null, }, }); createdPayments++; } } console.log( `✅ Backfill selesai. Booking dibuat: ${createdBookings}, Payment dibuat: ${createdPayments}, dilewati (sudah ada): ${skipped}` ); } main() .catch((e) => { console.error("❌ Backfill gagal:", e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });