diff --git a/apps/edr-passenger-api/prisma/seed.ts b/apps/edr-passenger-api/prisma/seed.ts index 2d1cca828..9baaf6433 100644 --- a/apps/edr-passenger-api/prisma/seed.ts +++ b/apps/edr-passenger-api/prisma/seed.ts @@ -1,10 +1,11 @@ import { PrismaClient } from '@prisma/client'; import * as bcrypt from 'bcrypt'; +import { v4 as uuidv4 } from 'uuid'; const prisma = new PrismaClient(); -const EDR_ROUTE_ID = 'route-edr-101'; -const TRAIN_ID = 'EDR-101'; +const EDR_ROUTE_ID = uuidv4(); +const TRAIN_ID = uuidv4(); async function seedSystemUsers() { console.log('šŸ‘„ Seeding system users...'); @@ -128,7 +129,7 @@ async function seedStations() { where: { code: station.code }, update: {}, create: { - id: `station-${station.code.toLowerCase()}`, + id: uuidv4(), ...station, }, }); @@ -296,6 +297,34 @@ async function seedTrips() { schedules.map(s => prisma.trainSchedule.create({ data: s })) ); + // Create TripStopTimes for each schedule + const routeStops = await prisma.routeStop.findMany({ + where: { routeId: route!.id }, + orderBy: { sequence: 'asc' }, + include: { route: true }, + }); + + for (const schedule of createdSchedules) { + const stopTimes = []; + for (const routeStop of routeStops) { + const minutesFromStart = (routeStop.sequence - 1) * 480; // 8 hours per stop + const plannedDepartureAt = new Date(schedule.departureAt.getTime() + minutesFromStart * 60_000); + const plannedArrivalAt = new Date(plannedDepartureAt.getTime() + 30 * 60_000); // 30 min stop + + stopTimes.push({ + scheduleId: schedule.id, + stationId: routeStop.stationId, + sequence: routeStop.sequence, + plannedArrivalAt, + plannedDepartureAt, + }); + } + + await Promise.all( + stopTimes.map(st => prisma.tripStopTime.create({ data: st })) + ); + } + const coachAssignments = []; const liveStatuses = []; @@ -408,11 +437,11 @@ async function seedPaymentMethods() { async function seedNotificationTemplates() { console.log('\nšŸ”” Seeding notification templates...'); const templates = [ - { code: 'BOOKING_CONFIRMED', channel: 'EMAIL', subject: 'Booking Confirmed', bodyTemplate: 'Your booking {{bookingRef}} is confirmed' }, - { code: 'PAYMENT_RECEIVED', channel: 'SMS', bodyTemplate: 'Payment received for {{bookingRef}}' }, - { code: 'TRIP_DEPARTURE', channel: 'PUSH', bodyTemplate: 'Your trip departs in {{minutes}} minutes' }, - { code: 'TRIP_DELAY', channel: 'EMAIL', subject: 'Trip Delayed', bodyTemplate: 'Your trip is delayed by {{delayMinutes}} minutes' }, - { code: 'PROMOTION', channel: 'PUSH', bodyTemplate: 'Get {{percentOff}}% off on {{route}}' }, + { id: uuidv4(), code: 'BOOKING_CONFIRMED', channel: 'EMAIL', subject: 'Booking Confirmed', bodyTemplate: 'Your booking {{bookingRef}} is confirmed' }, + { id: uuidv4(), code: 'PAYMENT_RECEIVED', channel: 'SMS', bodyTemplate: 'Payment received for {{bookingRef}}' }, + { id: uuidv4(), code: 'TRIP_DEPARTURE', channel: 'PUSH', bodyTemplate: 'Your trip departs in {{minutes}} minutes' }, + { id: uuidv4(), code: 'TRIP_DELAY', channel: 'EMAIL', subject: 'Trip Delayed', bodyTemplate: 'Your trip is delayed by {{delayMinutes}} minutes' }, + { id: uuidv4(), code: 'PROMOTION', channel: 'PUSH', bodyTemplate: 'Get {{percentOff}}% off on {{route}}' }, ]; for (const t of templates) { @@ -428,33 +457,31 @@ async function seedNotificationTemplates() { async function seedMenuAndFood() { console.log('\nšŸ½ļø Seeding menu categories and items...'); const beverages = await prisma.menuCategory.upsert({ - where: { id: 'cat-beverages' }, + where: { id: uuidv4() }, update: {}, - create: { id: 'cat-beverages', name: 'Beverages' }, + create: { id: uuidv4(), name: 'Beverages' }, }); const snacks = await prisma.menuCategory.upsert({ - where: { id: 'cat-snacks' }, + where: { id: uuidv4() }, update: {}, - create: { id: 'cat-snacks', name: 'Snacks' }, + create: { id: uuidv4(), name: 'Snacks' }, }); const schedule = await prisma.trainSchedule.findFirst(); if (schedule) { - await prisma.menuItem.upsert({ - where: { id: 'menu-coffee' }, - update: {}, - create: { id: 'menu-coffee', scheduleId: schedule.id, categoryId: beverages.id, name: 'Ethiopian Coffee', priceMinor: 5000 }, - }); - await prisma.menuItem.upsert({ - where: { id: 'menu-juice' }, - update: {}, - create: { id: 'menu-juice', scheduleId: schedule.id, categoryId: beverages.id, name: 'Fresh Juice', priceMinor: 3500 }, - }); - await prisma.menuItem.upsert({ - where: { id: 'menu-sandwich' }, - update: {}, - create: { id: 'menu-sandwich', scheduleId: schedule.id, categoryId: snacks.id, name: 'Sandwich', priceMinor: 8000 }, - }); + const coffeeId = uuidv4(); + const juiceId = uuidv4(); + const sandwichId = uuidv4(); + + await prisma.menuItem.create({ + data: { id: coffeeId, scheduleId: schedule.id, categoryId: beverages.id, name: 'Ethiopian Coffee', priceMinor: 5000 }, + }).catch(() => {}); // ignore if exists + await prisma.menuItem.create({ + data: { id: juiceId, scheduleId: schedule.id, categoryId: beverages.id, name: 'Fresh Juice', priceMinor: 3500 }, + }).catch(() => {}); // ignore if exists + await prisma.menuItem.create({ + data: { id: sandwichId, scheduleId: schedule.id, categoryId: snacks.id, name: 'Sandwich', priceMinor: 8000 }, + }).catch(() => {}); // ignore if exists } console.log(` āœ… Menu categories and items created`); } @@ -462,9 +489,9 @@ async function seedMenuAndFood() { async function seedPromotions() { console.log('\nšŸŽ‰ Seeding promotions...'); const promos = [ - { title: 'Early Bird Discount', code: 'EARLY20', percentOff: 20, validUntil: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) }, - { title: 'Student Discount', code: 'STUDENT15', percentOff: 15, validUntil: new Date(Date.now() + 60 * 24 * 60 * 60 * 1000) }, - { title: 'Group Booking', code: 'GROUP10', amountOffMinor: 10000, validUntil: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) }, + { id: uuidv4(), title: 'Early Bird Discount', code: 'EARLY20', percentOff: 20, validUntil: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) }, + { id: uuidv4(), title: 'Student Discount', code: 'STUDENT15', percentOff: 15, validUntil: new Date(Date.now() + 60 * 24 * 60 * 60 * 1000) }, + { id: uuidv4(), title: 'Group Booking', code: 'GROUP10', amountOffMinor: 10000, validUntil: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) }, ]; for (const p of promos) { @@ -479,26 +506,28 @@ async function seedPromotions() { async function seedFAQ() { console.log('\nā“ Seeding FAQ...'); + const generalId = uuidv4(); + const bookingId = uuidv4(); const general = await prisma.faqCategory.upsert({ - where: { id: 'faq-general' }, + where: { id: generalId }, update: {}, - create: { id: 'faq-general', title: 'General', iconKey: 'help' }, + create: { id: generalId, title: 'General', iconKey: 'help' }, }); const booking = await prisma.faqCategory.upsert({ - where: { id: 'faq-booking' }, + where: { id: bookingId }, update: {}, - create: { id: 'faq-booking', title: 'Booking', iconKey: 'book' }, + create: { id: bookingId, title: 'Booking', iconKey: 'book' }, }); await prisma.faqArticle.upsert({ - where: { id: 'faq-article-1' }, + where: { id: uuidv4() }, update: {}, - create: { id: 'faq-article-1', categoryId: general.id, question: 'What is EDR?', answerMarkdown: 'Ethio-Djibouti Railway' }, + create: { id: uuidv4(), categoryId: general.id, question: 'What is EDR?', answerMarkdown: 'Ethio-Djibouti Railway' }, }); await prisma.faqArticle.upsert({ - where: { id: 'faq-article-2' }, + where: { id: uuidv4() }, update: {}, - create: { id: 'faq-article-2', categoryId: booking.id, question: 'How to book?', answerMarkdown: 'Use the booking system' }, + create: { id: uuidv4(), categoryId: booking.id, question: 'How to book?', answerMarkdown: 'Use the booking system' }, }); console.log(` āœ… FAQ categories and articles created`); }