mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
221 lines
9.9 KiB
TypeScript
221 lines
9.9 KiB
TypeScript
import { PrismaClient, SeatKind } from '@prisma/client';
|
|
import * as bcrypt from 'bcrypt';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
async function main() {
|
|
console.log('🌱 Starting complete seed...\n');
|
|
|
|
// 1. STATIONS
|
|
console.log('📍 Seeding stations...');
|
|
const stationData = [
|
|
{ code: 'SBT', name: 'Sebeta', city: 'Sebeta', countryCode: 'ET', lat: 8.9167, lng: 38.6167 },
|
|
{ code: 'LBU', name: 'Labu', city: 'Labu', countryCode: 'ET', lat: 8.8500, lng: 38.7000 },
|
|
{ code: 'IND', name: 'Indode', city: 'Indode', countryCode: 'ET', lat: 8.7800, lng: 38.8200 },
|
|
{ code: 'BSH', name: 'Bishoftu', city: 'Bishoftu', countryCode: 'ET', lat: 8.7500, lng: 38.9833 },
|
|
{ code: 'MJO', name: 'Mojo', city: 'Mojo', countryCode: 'ET', lat: 8.6000, lng: 39.1200 },
|
|
{ code: 'ADM', name: 'Adama', city: 'Adama', countryCode: 'ET', lat: 8.5400, lng: 39.2675 },
|
|
{ code: 'DDW', name: 'Diredawa', city: 'Diredawa', countryCode: 'ET', lat: 9.5931, lng: 41.8661 },
|
|
{ code: 'NGD', name: 'Nagad', city: 'Nagad', countryCode: 'DJ', timezone: 'Africa/Djibouti', lat: 11.5720, lng: 43.1456 },
|
|
];
|
|
|
|
const stations = [];
|
|
for (const s of stationData) {
|
|
stations.push(await prisma.station.upsert({ where: { code: s.code }, update: {}, create: s }));
|
|
}
|
|
console.log(`✅ ${stations.length} stations\n`);
|
|
|
|
// 2. SEAT CLASSES
|
|
console.log('💺 Seeding seat classes...');
|
|
const scEconomy = await prisma.seatClass.upsert({
|
|
where: { name: 'Economy Regular' },
|
|
update: {},
|
|
create: { name: 'Economy Regular', description: 'Standard economy', basePrice: 25000, isActive: true },
|
|
});
|
|
const scBed = await prisma.seatClass.upsert({
|
|
where: { name: 'Economy Bed' },
|
|
update: {},
|
|
create: { name: 'Economy Bed', description: 'Economy bed', basePrice: 35000, isActive: true },
|
|
});
|
|
console.log(`✅ 2 seat classes\n`);
|
|
|
|
// 3. ROUTES
|
|
console.log('🛤️ Seeding routes...');
|
|
const route1 = await prisma.route.upsert({
|
|
where: { code: 'SBT-NGD' },
|
|
update: {},
|
|
create: { code: 'SBT-NGD', name: 'Sebeta-Nagad Express', effectiveFrom: new Date('2026-01-01'), active: true },
|
|
});
|
|
|
|
await prisma.routeStop.createMany({
|
|
data: [
|
|
{ routeId: route1.id, stationId: stations[0].id, sequence: 1, distanceKm: 0 },
|
|
{ routeId: route1.id, stationId: stations[1].id, sequence: 2, distanceKm: 15 },
|
|
{ routeId: route1.id, stationId: stations[2].id, sequence: 3, distanceKm: 28 },
|
|
{ routeId: route1.id, stationId: stations[3].id, sequence: 4, distanceKm: 45 },
|
|
{ routeId: route1.id, stationId: stations[4].id, sequence: 5, distanceKm: 73 },
|
|
{ routeId: route1.id, stationId: stations[5].id, sequence: 6, distanceKm: 99 },
|
|
{ routeId: route1.id, stationId: stations[6].id, sequence: 7, distanceKm: 378 },
|
|
{ routeId: route1.id, stationId: stations[7].id, sequence: 8, distanceKm: 756 },
|
|
],
|
|
skipDuplicates: true,
|
|
});
|
|
|
|
await prisma.routeFareRule.createMany({
|
|
data: [
|
|
{ routeId: route1.id, seatClassId: scEconomy.id, passengerCategory: 'ADULT', baseFareMinor: 65000, validFrom: new Date('2026-01-01') },
|
|
{ routeId: route1.id, seatClassId: scEconomy.id, passengerCategory: 'CHILD', baseFareMinor: 65000, validFrom: new Date('2026-01-01') },
|
|
{ routeId: route1.id, seatClassId: scBed.id, passengerCategory: 'ADULT', baseFareMinor: 91000, validFrom: new Date('2026-01-01') },
|
|
{ routeId: route1.id, seatClassId: scBed.id, passengerCategory: 'CHILD', baseFareMinor: 91000, validFrom: new Date('2026-01-01') },
|
|
],
|
|
skipDuplicates: true,
|
|
});
|
|
console.log(`✅ 1 route with stops and fares\n`);
|
|
|
|
// 4. TRAINS
|
|
console.log('🚂 Seeding trains...');
|
|
const train = await prisma.train.upsert({
|
|
where: { number: '301' },
|
|
update: {},
|
|
create: { number: '301', name: 'Express 301', description: 'Main Express' },
|
|
});
|
|
console.log(`✅ 1 train\n`);
|
|
|
|
// 5. COACHES & SEATS
|
|
console.log('🚃 Seeding coaches...');
|
|
const coach1 = await prisma.coach.upsert({
|
|
where: { coachNumber: 'C-A1' },
|
|
update: {},
|
|
create: { coachNumber: 'C-A1', label: 'A', seatClassId: scEconomy.id, mode: 'seat', totalUnits: 20 },
|
|
});
|
|
|
|
const existingSeats = await prisma.seat.count({ where: { coachId: coach1.id } });
|
|
if (existingSeats === 0) {
|
|
const seats = [];
|
|
for (let row = 1; row <= 5; row++) {
|
|
for (const col of ['A', 'B', 'C', 'D']) {
|
|
seats.push({
|
|
coachId: coach1.id,
|
|
row,
|
|
col,
|
|
label: `${row}${col}`,
|
|
seatNumber: `A${row}${col}`,
|
|
kind: 'STANDARD' as SeatKind,
|
|
});
|
|
}
|
|
}
|
|
await prisma.seat.createMany({ data: seats });
|
|
}
|
|
console.log(`✅ 1 coach with 20 seats\n`);
|
|
|
|
// 6. SCHEDULE
|
|
console.log('📅 Seeding schedule...');
|
|
const existingSchedules = await prisma.trainSchedule.findMany({ where: { trainId: train.id }, select: { id: true } });
|
|
if (existingSchedules.length > 0) {
|
|
const scheduleIds = existingSchedules.map(s => s.id);
|
|
// Delete in correct order to avoid foreign key constraints
|
|
await prisma.bookingSeat.deleteMany({ where: { booking: { scheduleId: { in: scheduleIds } } } });
|
|
await prisma.booking.deleteMany({ where: { scheduleId: { in: scheduleIds } } });
|
|
await prisma.fareRule.deleteMany({ where: { tripId: { in: scheduleIds } } });
|
|
await prisma.tripStopTime.deleteMany({ where: { scheduleId: { in: scheduleIds } } });
|
|
await prisma.coachAssignment.deleteMany({ where: { scheduleId: { in: scheduleIds } } });
|
|
await prisma.trainSchedule.deleteMany({ where: { trainId: train.id } });
|
|
}
|
|
|
|
const schedule = await prisma.trainSchedule.create({
|
|
data: {
|
|
trainId: train.id,
|
|
routeId: route1.id,
|
|
originStationId: stations[0].id,
|
|
destinationStationId: stations[7].id,
|
|
departureAt: new Date('2026-06-15T06:00:00Z'),
|
|
arrivalAt: new Date('2026-06-15T22:00:00Z'),
|
|
durationMinutes: 960,
|
|
stopsCount: 8,
|
|
},
|
|
});
|
|
|
|
await prisma.coachAssignment.create({
|
|
data: { scheduleId: schedule.id, coachId: coach1.id, positionNumber: 1 },
|
|
});
|
|
|
|
await prisma.tripStopTime.createMany({
|
|
data: [
|
|
{ scheduleId: schedule.id, stationId: stations[0].id, sequence: 1, plannedDepartureAt: new Date('2026-06-15T06:00:00Z'), status: 'UPCOMING' },
|
|
{ scheduleId: schedule.id, stationId: stations[1].id, sequence: 2, plannedArrivalAt: new Date('2026-06-15T07:00:00Z'), plannedDepartureAt: new Date('2026-06-15T07:05:00Z'), status: 'UPCOMING' },
|
|
{ scheduleId: schedule.id, stationId: stations[2].id, sequence: 3, plannedArrivalAt: new Date('2026-06-15T08:00:00Z'), plannedDepartureAt: new Date('2026-06-15T08:05:00Z'), status: 'UPCOMING' },
|
|
{ scheduleId: schedule.id, stationId: stations[3].id, sequence: 4, plannedArrivalAt: new Date('2026-06-15T09:00:00Z'), plannedDepartureAt: new Date('2026-06-15T09:10:00Z'), status: 'UPCOMING' },
|
|
{ scheduleId: schedule.id, stationId: stations[4].id, sequence: 5, plannedArrivalAt: new Date('2026-06-15T10:00:00Z'), plannedDepartureAt: new Date('2026-06-15T10:10:00Z'), status: 'UPCOMING' },
|
|
{ scheduleId: schedule.id, stationId: stations[5].id, sequence: 6, plannedArrivalAt: new Date('2026-06-15T11:00:00Z'), plannedDepartureAt: new Date('2026-06-15T11:15:00Z'), status: 'UPCOMING' },
|
|
{ scheduleId: schedule.id, stationId: stations[6].id, sequence: 7, plannedArrivalAt: new Date('2026-06-15T15:00:00Z'), plannedDepartureAt: new Date('2026-06-15T15:20:00Z'), status: 'UPCOMING' },
|
|
{ scheduleId: schedule.id, stationId: stations[7].id, sequence: 8, plannedArrivalAt: new Date('2026-06-15T22:00:00Z'), status: 'UPCOMING' },
|
|
],
|
|
});
|
|
console.log(`✅ 1 schedule with stops\n`);
|
|
|
|
// 7. USERS
|
|
console.log('👥 Seeding users...');
|
|
const adminHash = await bcrypt.hash('admin123', 10);
|
|
const userHash = await bcrypt.hash('password123', 10);
|
|
|
|
await prisma.user.upsert({
|
|
where: { email: 'admin@edr-platform.com' },
|
|
update: {},
|
|
create: { fullName: 'Admin', email: 'admin@edr-platform.com', phone: '+251900000000', passwordHash: adminHash, role: 'ADMIN' },
|
|
});
|
|
|
|
const user = await prisma.user.upsert({
|
|
where: { email: 'abebe@email.com' },
|
|
update: {},
|
|
create: { fullName: 'Abebe Kebede', email: 'abebe@email.com', phone: '+251912345678', passwordHash: userHash, nationality: 'Ethiopian' },
|
|
});
|
|
|
|
let passenger = await prisma.passenger.findUnique({ where: { userId: user.id } });
|
|
if (!passenger) {
|
|
passenger = await prisma.passenger.create({ data: { userId: user.id } });
|
|
await prisma.loyaltyAccount.create({ data: { passengerId: passenger.id, pointsBalance: 1000, tier: 'BRONZE' } });
|
|
await prisma.walletAccount.create({ data: { passengerId: passenger.id, balanceMinor: 100000 } });
|
|
}
|
|
console.log(`✅ 2 users\n`);
|
|
|
|
// 8. SUPPORTING DATA
|
|
console.log('📦 Seeding supporting data...');
|
|
|
|
await prisma.paymentMethod.upsert({
|
|
where: { type: 'TELEBIRR' },
|
|
update: {},
|
|
create: { type: 'TELEBIRR', displayName: 'Telebirr', region: 'ETHIOPIA', currency: 'ETB', enabled: true, sortOrder: 1 },
|
|
});
|
|
|
|
await prisma.currencyExchangeRate.deleteMany({});
|
|
await prisma.currencyExchangeRate.createMany({
|
|
data: [
|
|
{ fromCurrency: 'ETB', toCurrency: 'ETB', rate: 1.0, effectiveDate: new Date() },
|
|
{ fromCurrency: 'ETB', toCurrency: 'USD', rate: 0.018, effectiveDate: new Date() },
|
|
{ fromCurrency: 'ETB', toCurrency: 'DJF', rate: 3.2, effectiveDate: new Date() },
|
|
],
|
|
});
|
|
console.log(`✅ Payment methods and currencies\n`);
|
|
|
|
console.log('✅ SEED COMPLETE!\n');
|
|
console.log('📋 Summary:');
|
|
console.log(' - 8 Stations');
|
|
console.log(' - 2 Seat Classes');
|
|
console.log(' - 1 Route with 8 stops');
|
|
console.log(' - 1 Train with 1 schedule');
|
|
console.log(' - 1 Coach with 20 seats');
|
|
console.log(' - 2 Users (Admin + Passenger)');
|
|
console.log('\n🔑 Credentials:');
|
|
console.log(' Admin: admin@edr-platform.com / admin123');
|
|
console.log(' User: abebe@email.com / password123');
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error('❌ Error:', e);
|
|
process.exit(1);
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|