Files
setrip/prisma/backfill-bookings.ts
2026-05-08 20:59:01 +07:00

102 lines
3.0 KiB
TypeScript

/**
* 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();
});