mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 08:48:11 +00:00
Coaches, seats, schedules, and pricing related updates
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
-- AlterEnum
|
||||
ALTER TYPE "PaymentMethodType" ADD VALUE 'WAAFI';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "FareRule" ADD COLUMN "nationality" TEXT;
|
||||
@@ -1,28 +0,0 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Booking" ADD COLUMN "contactEmail" TEXT,
|
||||
ADD COLUMN "contactPhone" TEXT;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SavedPassengerProfile" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT,
|
||||
"deviceId" TEXT,
|
||||
"passengerName" TEXT NOT NULL,
|
||||
"dateOfBirth" TIMESTAMP(3) NOT NULL,
|
||||
"idDocumentType" "IdDocumentType" NOT NULL,
|
||||
"passportNumber" TEXT,
|
||||
"passportCountry" TEXT,
|
||||
"nationality" TEXT,
|
||||
"phone" TEXT,
|
||||
"email" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "SavedPassengerProfile_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SavedPassengerProfile_userId_idx" ON "SavedPassengerProfile"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SavedPassengerProfile_deviceId_idx" ON "SavedPassengerProfile"("deviceId");
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- A unique constraint covering the columns `[faydaSub]` on the table `User` will be added. If there are existing duplicate values, this will fail.
|
||||
|
||||
*/
|
||||
-- AlterTable
|
||||
ALTER TABLE "passenger"."BookingSeat" ADD COLUMN "faydaSub" TEXT,
|
||||
ADD COLUMN "faydaVerifiedAt" TIMESTAMP(3),
|
||||
ADD COLUMN "faydaVerifiedName" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "passenger"."User" ADD COLUMN "faydaSub" TEXT,
|
||||
ADD COLUMN "faydaVerified" BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN "faydaVerifiedAt" TIMESTAMP(3);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "passenger"."FaydaVerificationSession" (
|
||||
"id" TEXT NOT NULL,
|
||||
"state" TEXT NOT NULL,
|
||||
"codeVerifier" TEXT NOT NULL,
|
||||
"purpose" TEXT NOT NULL DEFAULT 'PURCHASE',
|
||||
"saveToAccount" BOOLEAN NOT NULL DEFAULT false,
|
||||
"status" TEXT NOT NULL DEFAULT 'PENDING',
|
||||
"errorCode" TEXT,
|
||||
"errorDescription" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"completedAt" TIMESTAMP(3),
|
||||
"userId" TEXT,
|
||||
"bookingId" TEXT,
|
||||
|
||||
CONSTRAINT "FaydaVerificationSession_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "FaydaVerificationSession_state_key" ON "passenger"."FaydaVerificationSession"("state");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FaydaVerificationSession_userId_idx" ON "passenger"."FaydaVerificationSession"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FaydaVerificationSession_bookingId_idx" ON "passenger"."FaydaVerificationSession"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FaydaVerificationSession_state_idx" ON "passenger"."FaydaVerificationSession"("state");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FaydaVerificationSession_expiresAt_idx" ON "passenger"."FaydaVerificationSession"("expiresAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_faydaSub_key" ON "passenger"."User"("faydaSub");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "passenger"."FaydaVerificationSession" ADD CONSTRAINT "FaydaVerificationSession_userId_fkey" FOREIGN KEY ("userId") REFERENCES "passenger"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `maskedHint` on the `PaymentMethod` table. All the data in the column will be lost.
|
||||
- You are about to drop the column `userId` on the `PaymentMethod` table. All the data in the column will be lost.
|
||||
- A unique constraint covering the columns `[type]` on the table `PaymentMethod` will be added. If there are existing duplicate values, this will fail.
|
||||
- Added the required column `updatedAt` to the `PaymentMethod` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PaymentRegion" AS ENUM ('ETHIOPIA', 'DJIBOUTI', 'INTERNATIONAL', 'GLOBAL');
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "PaymentMethod_userId_isDefault_idx";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "PaymentMethod" DROP COLUMN "maskedHint",
|
||||
DROP COLUMN "userId",
|
||||
ADD COLUMN "currency" TEXT NOT NULL DEFAULT 'ETB',
|
||||
ADD COLUMN "enabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
ADD COLUMN "region" "PaymentRegion" NOT NULL DEFAULT 'GLOBAL',
|
||||
ADD COLUMN "sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
ADD COLUMN "updatedAt" TIMESTAMP(3) NOT NULL;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "PaymentMethod_type_key" ON "PaymentMethod"("type");
|
||||
@@ -1,3 +0,0 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "FaydaVerificationSession" ADD COLUMN "authCode" TEXT,
|
||||
ADD COLUMN "platform" TEXT NOT NULL DEFAULT 'WEB';
|
||||
@@ -1,2 +0,0 @@
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TrainSchedule" ADD CONSTRAINT "TrainSchedule_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -23,7 +23,10 @@ CREATE TYPE "Currency" AS ENUM ('ETB', 'DJF', 'USD');
|
||||
CREATE TYPE "BookingStatus" AS ENUM ('DRAFT', 'PENDING_PAYMENT', 'CONFIRMED', 'CANCELLED', 'COMPLETED', 'NO_SHOW', 'REFUNDED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PaymentMethodType" AS ENUM ('TELEBIRR', 'CBE_BIRR', 'EBIRR', 'CARD', 'WALLET');
|
||||
CREATE TYPE "PaymentRegion" AS ENUM ('ETHIOPIA', 'DJIBOUTI', 'INTERNATIONAL', 'GLOBAL');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PaymentMethodType" AS ENUM ('TELEBIRR', 'CBE_BIRR', 'EBIRR', 'CARD', 'WALLET', 'WAAFI');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PaymentIntentStatus" AS ENUM ('REQUIRES_ACTION', 'PROCESSING', 'SUCCEEDED', 'FAILED', 'CANCELLED', 'REFUNDED');
|
||||
@@ -55,12 +58,25 @@ CREATE TYPE "FoodOrderStatus" AS ENUM ('PENDING', 'PREPARING', 'READY', 'DELIVER
|
||||
-- CreateEnum
|
||||
CREATE TYPE "DevicePlatform" AS ENUM ('IOS', 'ANDROID', 'WEB');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "CoachType" (
|
||||
"id" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL DEFAULT 'passenger',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "CoachType_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SeatClass" (
|
||||
"id" TEXT NOT NULL,
|
||||
"coachTypeId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"basePrice" INTEGER NOT NULL,
|
||||
"baseFareMinor" INTEGER NOT NULL,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
@@ -86,6 +102,9 @@ CREATE TABLE "User" (
|
||||
"lastLoginAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"faydaVerified" BOOLEAN NOT NULL DEFAULT false,
|
||||
"faydaVerifiedAt" TIMESTAMP(3),
|
||||
"faydaSub" TEXT,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
@@ -211,16 +230,11 @@ CREATE TABLE "TripLiveStatus" (
|
||||
-- CreateTable
|
||||
CREATE TABLE "Coach" (
|
||||
"id" TEXT NOT NULL,
|
||||
"coachNumber" TEXT NOT NULL,
|
||||
"label" TEXT NOT NULL,
|
||||
"seatClassId" TEXT NOT NULL,
|
||||
"coachType" TEXT,
|
||||
"mode" TEXT NOT NULL DEFAULT 'seat',
|
||||
"seatArrangement" TEXT,
|
||||
"bedArrangement" TEXT,
|
||||
"amenities" JSONB,
|
||||
"totalUnits" INTEGER NOT NULL DEFAULT 0,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"coachTypeId" TEXT NOT NULL,
|
||||
"number" TEXT NOT NULL,
|
||||
"arrangement" TEXT NOT NULL DEFAULT '2+2',
|
||||
"capacity" INTEGER NOT NULL DEFAULT 0,
|
||||
"status" TEXT NOT NULL DEFAULT 'ACTIVE',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
@@ -243,10 +257,9 @@ CREATE TABLE "CoachAssignment" (
|
||||
CREATE TABLE "Seat" (
|
||||
"id" TEXT NOT NULL,
|
||||
"coachId" TEXT NOT NULL,
|
||||
"seatNumber" TEXT NOT NULL,
|
||||
"row" INTEGER NOT NULL,
|
||||
"col" TEXT NOT NULL,
|
||||
"label" TEXT NOT NULL,
|
||||
"seatNumber" TEXT,
|
||||
"kind" "SeatKind" NOT NULL DEFAULT 'STANDARD',
|
||||
"status" "SeatStatus" NOT NULL DEFAULT 'AVAILABLE',
|
||||
"heldUntil" TIMESTAMP(3),
|
||||
@@ -254,7 +267,6 @@ CREATE TABLE "Seat" (
|
||||
"isAisle" BOOLEAN NOT NULL DEFAULT false,
|
||||
"bedPosition" TEXT,
|
||||
"premiumFeeMinor" INTEGER NOT NULL DEFAULT 0,
|
||||
"eligibility" TEXT,
|
||||
|
||||
CONSTRAINT "Seat_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
@@ -278,6 +290,7 @@ CREATE TABLE "FareRule" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tripId" TEXT,
|
||||
"route" TEXT,
|
||||
"nationality" TEXT,
|
||||
"seatClassId" TEXT NOT NULL,
|
||||
"baseFareMinor" INTEGER NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'ETB',
|
||||
@@ -303,6 +316,8 @@ CREATE TABLE "Booking" (
|
||||
"displayCurrency" "Currency",
|
||||
"displayTotalMinor" INTEGER,
|
||||
"bookingType" TEXT NOT NULL DEFAULT 'ONE_WAY',
|
||||
"contactEmail" TEXT,
|
||||
"contactPhone" TEXT,
|
||||
"userAgent" TEXT,
|
||||
"source" TEXT NOT NULL DEFAULT 'WEB',
|
||||
"promoCode" TEXT,
|
||||
@@ -327,6 +342,9 @@ CREATE TABLE "BookingSeat" (
|
||||
"passportCountry" TEXT,
|
||||
"verifaydaVerified" BOOLEAN NOT NULL DEFAULT false,
|
||||
"verifaydaData" JSONB,
|
||||
"faydaVerifiedAt" TIMESTAMP(3),
|
||||
"faydaSub" TEXT,
|
||||
"faydaVerifiedName" TEXT,
|
||||
"seatLabelSnapshot" TEXT,
|
||||
"fareMinor" INTEGER,
|
||||
"displayCurrency" "Currency",
|
||||
@@ -338,13 +356,16 @@ CREATE TABLE "BookingSeat" (
|
||||
-- CreateTable
|
||||
CREATE TABLE "PaymentMethod" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"type" "PaymentMethodType" NOT NULL,
|
||||
"displayName" TEXT NOT NULL,
|
||||
"maskedHint" TEXT,
|
||||
"region" "PaymentRegion" NOT NULL DEFAULT 'GLOBAL',
|
||||
"currency" TEXT NOT NULL DEFAULT 'ETB',
|
||||
"providerId" TEXT,
|
||||
"isDefault" BOOLEAN NOT NULL DEFAULT false,
|
||||
"enabled" BOOLEAN NOT NULL DEFAULT true,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "PaymentMethod_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
@@ -423,6 +444,16 @@ CREATE TABLE "Ticket" (
|
||||
CONSTRAINT "Ticket_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TicketSeat" (
|
||||
"id" TEXT NOT NULL,
|
||||
"ticketId" TEXT NOT NULL,
|
||||
"seatId" TEXT NOT NULL,
|
||||
"seatIndex" INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
CONSTRAINT "TicketSeat_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LoyaltyAccount" (
|
||||
"id" TEXT NOT NULL,
|
||||
@@ -1016,8 +1047,51 @@ CREATE TABLE "VerifaydaVerification" (
|
||||
CONSTRAINT "VerifaydaVerification_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SavedPassengerProfile" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT,
|
||||
"deviceId" TEXT,
|
||||
"passengerName" TEXT NOT NULL,
|
||||
"dateOfBirth" TIMESTAMP(3) NOT NULL,
|
||||
"idDocumentType" "IdDocumentType" NOT NULL,
|
||||
"passportNumber" TEXT,
|
||||
"passportCountry" TEXT,
|
||||
"nationality" TEXT,
|
||||
"phone" TEXT,
|
||||
"email" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "SavedPassengerProfile_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FaydaVerificationSession" (
|
||||
"id" TEXT NOT NULL,
|
||||
"state" TEXT NOT NULL,
|
||||
"codeVerifier" TEXT NOT NULL,
|
||||
"purpose" TEXT NOT NULL DEFAULT 'PURCHASE',
|
||||
"platform" TEXT NOT NULL DEFAULT 'WEB',
|
||||
"saveToAccount" BOOLEAN NOT NULL DEFAULT false,
|
||||
"status" TEXT NOT NULL DEFAULT 'PENDING',
|
||||
"errorCode" TEXT,
|
||||
"errorDescription" TEXT,
|
||||
"authCode" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"completedAt" TIMESTAMP(3),
|
||||
"userId" TEXT,
|
||||
"bookingId" TEXT,
|
||||
|
||||
CONSTRAINT "FaydaVerificationSession_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "SeatClass_name_key" ON "SeatClass"("name");
|
||||
CREATE INDEX "SeatClass_coachTypeId_idx" ON "SeatClass"("coachTypeId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "SeatClass_coachTypeId_name_key" ON "SeatClass"("coachTypeId", "name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
@@ -1025,6 +1099,9 @@ CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_phone_key" ON "User"("phone");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_faydaSub_key" ON "User"("faydaSub");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Session_token_key" ON "Session"("token");
|
||||
|
||||
@@ -1053,7 +1130,10 @@ CREATE UNIQUE INDEX "TripStopTime_scheduleId_sequence_key" ON "TripStopTime"("sc
|
||||
CREATE UNIQUE INDEX "TripLiveStatus_scheduleId_key" ON "TripLiveStatus"("scheduleId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Coach_coachNumber_key" ON "Coach"("coachNumber");
|
||||
CREATE UNIQUE INDEX "Coach_number_key" ON "Coach"("number");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Coach_coachTypeId_idx" ON "Coach"("coachTypeId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CoachAssignment_scheduleId_idx" ON "CoachAssignment"("scheduleId");
|
||||
@@ -1062,11 +1142,14 @@ CREATE INDEX "CoachAssignment_scheduleId_idx" ON "CoachAssignment"("scheduleId")
|
||||
CREATE UNIQUE INDEX "CoachAssignment_scheduleId_positionNumber_key" ON "CoachAssignment"("scheduleId", "positionNumber");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Seat_coachId_row_col_key" ON "Seat"("coachId", "row", "col");
|
||||
CREATE INDEX "Seat_coachId_idx" ON "Seat"("coachId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Seat_coachId_seatNumber_key" ON "Seat"("coachId", "seatNumber");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Seat_coachId_row_col_key" ON "Seat"("coachId", "row", "col");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SeatHold_expiresAt_idx" ON "SeatHold"("expiresAt");
|
||||
|
||||
@@ -1077,7 +1160,7 @@ CREATE UNIQUE INDEX "Booking_bookingRef_key" ON "Booking"("bookingRef");
|
||||
CREATE INDEX "Booking_passengerId_status_idx" ON "Booking"("passengerId", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PaymentMethod_userId_isDefault_idx" ON "PaymentMethod"("userId", "isDefault");
|
||||
CREATE UNIQUE INDEX "PaymentMethod_type_key" ON "PaymentMethod"("type");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "PaymentIntent_bookingId_key" ON "PaymentIntent"("bookingId");
|
||||
@@ -1100,6 +1183,12 @@ CREATE UNIQUE INDEX "PaymentWebhookEvent_provider_externalEventId_key" ON "Payme
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Ticket_bookingId_key" ON "Ticket"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TicketSeat_ticketId_idx" ON "TicketSeat"("ticketId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TicketSeat_seatId_idx" ON "TicketSeat"("seatId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "LoyaltyAccount_passengerId_key" ON "LoyaltyAccount"("passengerId");
|
||||
|
||||
@@ -1202,6 +1291,30 @@ CREATE INDEX "VerifaydaVerification_nationalId_idx" ON "VerifaydaVerification"("
|
||||
-- CreateIndex
|
||||
CREATE INDEX "VerifaydaVerification_bookingId_idx" ON "VerifaydaVerification"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SavedPassengerProfile_userId_idx" ON "SavedPassengerProfile"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SavedPassengerProfile_deviceId_idx" ON "SavedPassengerProfile"("deviceId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "FaydaVerificationSession_state_key" ON "FaydaVerificationSession"("state");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FaydaVerificationSession_userId_idx" ON "FaydaVerificationSession"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FaydaVerificationSession_bookingId_idx" ON "FaydaVerificationSession"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FaydaVerificationSession_state_idx" ON "FaydaVerificationSession"("state");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FaydaVerificationSession_expiresAt_idx" ON "FaydaVerificationSession"("expiresAt");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SeatClass" ADD CONSTRAINT "SeatClass_coachTypeId_fkey" FOREIGN KEY ("coachTypeId") REFERENCES "CoachType"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Session" ADD CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
@@ -1214,6 +1327,9 @@ ALTER TABLE "TravelerProfile" ADD CONSTRAINT "TravelerProfile_passengerId_fkey"
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TrainSchedule" ADD CONSTRAINT "TrainSchedule_trainId_fkey" FOREIGN KEY ("trainId") REFERENCES "Train"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TrainSchedule" ADD CONSTRAINT "TrainSchedule_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TrainSchedule" ADD CONSTRAINT "TrainSchedule_originStationId_fkey" FOREIGN KEY ("originStationId") REFERENCES "Station"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
@@ -1230,7 +1346,7 @@ ALTER TABLE "TripStopTime" ADD CONSTRAINT "TripStopTime_stationId_fkey" FOREIGN
|
||||
ALTER TABLE "TripLiveStatus" ADD CONSTRAINT "TripLiveStatus_scheduleId_fkey" FOREIGN KEY ("scheduleId") REFERENCES "TrainSchedule"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Coach" ADD CONSTRAINT "Coach_seatClassId_fkey" FOREIGN KEY ("seatClassId") REFERENCES "SeatClass"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "Coach" ADD CONSTRAINT "Coach_coachTypeId_fkey" FOREIGN KEY ("coachTypeId") REFERENCES "CoachType"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CoachAssignment" ADD CONSTRAINT "CoachAssignment_scheduleId_fkey" FOREIGN KEY ("scheduleId") REFERENCES "TrainSchedule"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -1265,6 +1381,12 @@ ALTER TABLE "PaymentRefund" ADD CONSTRAINT "PaymentRefund_paymentIntentId_fkey"
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Ticket" ADD CONSTRAINT "Ticket_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TicketSeat" ADD CONSTRAINT "TicketSeat_ticketId_fkey" FOREIGN KEY ("ticketId") REFERENCES "Ticket"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TicketSeat" ADD CONSTRAINT "TicketSeat_seatId_fkey" FOREIGN KEY ("seatId") REFERENCES "Seat"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "LoyaltyAccount" ADD CONSTRAINT "LoyaltyAccount_passengerId_fkey" FOREIGN KEY ("passengerId") REFERENCES "Passenger"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
@@ -1363,3 +1485,6 @@ ALTER TABLE "SeatBlock" ADD CONSTRAINT "SeatBlock_seatId_fkey" FOREIGN KEY ("sea
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FraudAlert" ADD CONSTRAINT "FraudAlert_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FaydaVerificationSession" ADD CONSTRAINT "FaydaVerificationSession_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,28 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "SegmentFareRule" (
|
||||
"id" TEXT NOT NULL,
|
||||
"routeId" TEXT NOT NULL,
|
||||
"originStopSequence" INTEGER NOT NULL,
|
||||
"destinationStopSequence" INTEGER NOT NULL,
|
||||
"seatClassId" TEXT NOT NULL,
|
||||
"baseFareMinor" INTEGER NOT NULL,
|
||||
"nationality" TEXT,
|
||||
"currency" TEXT NOT NULL DEFAULT 'ETB',
|
||||
"validFrom" TIMESTAMP(3) NOT NULL,
|
||||
"validUntil" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "SegmentFareRule_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SegmentFareRule_routeId_seatClassId_idx" ON "SegmentFareRule"("routeId", "seatClassId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "SegmentFareRule_routeId_originStopSequence_destinationStopS_key" ON "SegmentFareRule"("routeId", "originStopSequence", "destinationStopSequence", "seatClassId", "nationality");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SegmentFareRule" ADD CONSTRAINT "SegmentFareRule_routeId_fkey" FOREIGN KEY ("routeId") REFERENCES "Route"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SegmentFareRule" ADD CONSTRAINT "SegmentFareRule_seatClassId_fkey" FOREIGN KEY ("seatClassId") REFERENCES "SeatClass"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -1,30 +0,0 @@
|
||||
-- Add contact fields to Booking table
|
||||
ALTER TABLE "passenger"."Booking"
|
||||
ADD COLUMN "contactEmail" TEXT,
|
||||
ADD COLUMN "contactPhone" TEXT;
|
||||
|
||||
-- Create SavedPassengerProfile table
|
||||
CREATE TABLE "passenger"."SavedPassengerProfile" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT,
|
||||
"deviceId" TEXT,
|
||||
"passengerName" TEXT NOT NULL,
|
||||
"dateOfBirth" TIMESTAMP(3) NOT NULL,
|
||||
"idDocumentType" "passenger"."IdDocumentType" NOT NULL,
|
||||
"passportNumber" TEXT,
|
||||
"passportCountry" TEXT,
|
||||
"nationality" TEXT,
|
||||
"phone" TEXT,
|
||||
"email" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "SavedPassengerProfile_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- Create indexes
|
||||
CREATE INDEX "SavedPassengerProfile_userId_idx" ON "passenger"."SavedPassengerProfile"("userId");
|
||||
CREATE INDEX "SavedPassengerProfile_deviceId_idx" ON "passenger"."SavedPassengerProfile"("deviceId");
|
||||
|
||||
-- Add comment
|
||||
COMMENT ON TABLE "passenger"."SavedPassengerProfile" IS 'Stores passenger details for quick rebooking (by userId or deviceId)';
|
||||
@@ -70,17 +70,34 @@ enum Currency {
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
model SeatClass {
|
||||
model CoachType {
|
||||
id String @id @default(uuid())
|
||||
name String @unique
|
||||
description String?
|
||||
basePrice Int
|
||||
isActive Boolean @default(true)
|
||||
code String
|
||||
name String
|
||||
type String @default("passenger") // 'passenger', 'sleeper', 'dining', 'baggage'
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
coaches Coach[]
|
||||
seatClasses SeatClass[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
model SeatClass {
|
||||
id String @id @default(uuid())
|
||||
coachTypeId String
|
||||
name String
|
||||
description String?
|
||||
baseFareMinor Int
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
coachType CoachType @relation(fields: [coachTypeId], references: [id])
|
||||
fareRules FareRule[]
|
||||
routeFareRules RouteFareRule[]
|
||||
segmentFares SegmentFareRule[]
|
||||
@@unique([coachTypeId, name])
|
||||
@@index([coachTypeId])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
@@ -385,21 +402,17 @@ model TripLiveStatus {
|
||||
|
||||
model Coach {
|
||||
id String @id @default(uuid())
|
||||
coachNumber String @unique
|
||||
label String
|
||||
seatClassId String
|
||||
coachType String?
|
||||
mode String @default("seat") // 'seat', 'bed', 'convertible'
|
||||
seatArrangement String?
|
||||
bedArrangement String?
|
||||
amenities Json?
|
||||
totalUnits Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
coachTypeId String
|
||||
number String @unique
|
||||
arrangement String @default("2+2") // e.g., '2+2', '3+2', '2+2+2'
|
||||
capacity Int @default(0) // Total seats/beds
|
||||
status String @default("ACTIVE") // 'ACTIVE', 'MAINTENANCE', 'INACTIVE'
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
seatClass SeatClass @relation(fields: [seatClassId], references: [id])
|
||||
coachType CoachType @relation(fields: [coachTypeId], references: [id])
|
||||
seats Seat[]
|
||||
assignments CoachAssignment[]
|
||||
@@index([coachTypeId])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
@@ -422,10 +435,9 @@ model CoachAssignment {
|
||||
model Seat {
|
||||
id String @id @default(uuid())
|
||||
coachId String
|
||||
seatNumber String // Auto-generated: e.g., '1', '2', '3' (unique per coach)
|
||||
row Int
|
||||
col String
|
||||
label String
|
||||
seatNumber String?
|
||||
kind SeatKind @default(STANDARD)
|
||||
status SeatStatus @default(AVAILABLE)
|
||||
heldUntil DateTime?
|
||||
@@ -433,13 +445,13 @@ model Seat {
|
||||
isAisle Boolean @default(false)
|
||||
bedPosition String? // 'lower', 'middle', 'upper'
|
||||
premiumFeeMinor Int @default(0)
|
||||
eligibility String?
|
||||
coach Coach @relation(fields: [coachId], references: [id])
|
||||
bookingSeats BookingSeat[]
|
||||
blocks SeatBlock[]
|
||||
ticketSeats TicketSeat[]
|
||||
@@unique([coachId, row, col])
|
||||
@@unique([coachId, seatNumber])
|
||||
@@unique([coachId, row, col])
|
||||
@@index([coachId])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
@@ -978,6 +990,7 @@ model Route {
|
||||
createdAt DateTime @default(now())
|
||||
stops RouteStop[]
|
||||
fareRules RouteFareRule[]
|
||||
segmentFares SegmentFareRule[]
|
||||
schedules TrainSchedule[]
|
||||
|
||||
@@schema("passenger")
|
||||
@@ -1017,6 +1030,26 @@ model RouteFareRule {
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
model SegmentFareRule {
|
||||
id String @id @default(uuid())
|
||||
routeId String
|
||||
originStopSequence Int
|
||||
destinationStopSequence Int
|
||||
seatClassId String
|
||||
baseFareMinor Int
|
||||
nationality String? // Optional: Ethiopian, Djiboutian, Other
|
||||
currency String @default("ETB")
|
||||
validFrom DateTime
|
||||
validUntil DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
route Route @relation(fields: [routeId], references: [id], onDelete: Cascade)
|
||||
seatClass SeatClass @relation(fields: [seatClassId], references: [id])
|
||||
@@unique([routeId, originStopSequence, destinationStopSequence, seatClassId, nationality])
|
||||
@@index([routeId, seatClassId])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
model Agent {
|
||||
id String @id @default(uuid())
|
||||
userId String @unique
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
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);
|
||||
const bookingIds = (
|
||||
await prisma.booking.findMany({ where: { scheduleId: { in: scheduleIds } }, select: { id: true } })
|
||||
).map(b => b.id);
|
||||
// Delete booking children in FK-safe order before deleting the bookings themselves
|
||||
await prisma.foodOrderItem.deleteMany({ where: { order: { bookingId: { in: bookingIds } } } });
|
||||
await prisma.foodOrder.deleteMany({ where: { bookingId: { in: bookingIds } } });
|
||||
await prisma.paymentIntent.deleteMany({ where: { bookingId: { in: bookingIds } } });
|
||||
await prisma.ticket.deleteMany({ where: { bookingId: { in: bookingIds } } });
|
||||
await prisma.agentBooking.deleteMany({ where: { bookingId: { in: bookingIds } } });
|
||||
await prisma.bookingModification.deleteMany({ where: { bookingId: { in: bookingIds } } });
|
||||
await prisma.bookingCancellation.deleteMany({ where: { bookingId: { in: bookingIds } } });
|
||||
await prisma.baggageBooking.deleteMany({ where: { bookingId: { in: bookingIds } } });
|
||||
await prisma.bookingSeat.deleteMany({ where: { bookingId: { in: bookingIds } } });
|
||||
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();
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user