mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 09:58:12 +00:00
Booking and pricing related updates
This commit is contained in:
@@ -1,28 +1,52 @@
|
||||
-- Fix missing columns from 20260617 migration (failed due to missing schema prefix)
|
||||
-- Create passenger schema if it doesn't exist
|
||||
CREATE SCHEMA IF NOT EXISTS passenger;
|
||||
|
||||
-- Move all enums from public to passenger schema
|
||||
DO $$
|
||||
DECLARE
|
||||
e text;
|
||||
BEGIN
|
||||
FOR e IN
|
||||
SELECT typname FROM pg_type
|
||||
JOIN pg_namespace ON pg_namespace.oid = pg_type.typnamespace
|
||||
WHERE pg_namespace.nspname = 'public' AND pg_type.typtype = 'e'
|
||||
LOOP
|
||||
EXECUTE format('ALTER TYPE public.%I SET SCHEMA passenger', e);
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- Move all tables from public to passenger schema
|
||||
DO $$
|
||||
DECLARE
|
||||
t text;
|
||||
BEGIN
|
||||
FOR t IN
|
||||
SELECT tablename FROM pg_tables
|
||||
WHERE schemaname = 'public' AND tablename NOT IN ('_prisma_migrations')
|
||||
LOOP
|
||||
EXECUTE format('ALTER TABLE public.%I SET SCHEMA passenger', t);
|
||||
END LOOP;
|
||||
END $$;
|
||||
|
||||
-- Add missing columns to Booking
|
||||
ALTER TABLE "passenger"."Booking"
|
||||
ADD COLUMN IF NOT EXISTS "returnScheduleId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnOriginStationId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnDestinationStationId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnHoldId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnSeatClassId" TEXT;
|
||||
ADD COLUMN IF NOT EXISTS "returnSeatClassId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "leg2ScheduleId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "leg2OriginStationId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "leg2DestinationStationId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "leg2SeatClassId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnLeg2ScheduleId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnLeg2OriginStationId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnLeg2DestStationId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnLeg2SeatClassId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "outboundBoardedAt" TIMESTAMP(3),
|
||||
ADD COLUMN IF NOT EXISTS "returnBoardedAt" TIMESTAMP(3);
|
||||
|
||||
ALTER TABLE "passenger"."SeatClass" ALTER COLUMN "baseFareMinor" SET DEFAULT 0;
|
||||
ALTER TABLE "passenger"."Ticket" ALTER COLUMN "status" SET DEFAULT 'ACTIVE';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "Booking_bookingType_idx" ON "passenger"."Booking"("bookingType");
|
||||
|
||||
-- Transit leg-2 columns (never migrated)
|
||||
ALTER TABLE "passenger"."Booking"
|
||||
ADD COLUMN IF NOT EXISTS "leg2ScheduleId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "leg2OriginStationId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "leg2DestinationStationId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "leg2SeatClassId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnLeg2ScheduleId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnLeg2OriginStationId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnLeg2DestStationId" TEXT,
|
||||
ADD COLUMN IF NOT EXISTS "returnLeg2SeatClassId" TEXT;
|
||||
|
||||
-- ReturnLegStatus enum + columns (from 20260625 migration, may have also failed)
|
||||
-- Add ReturnLegStatus enum and column
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE "passenger"."ReturnLegStatus" AS ENUM (
|
||||
'NOT_APPLICABLE', 'BOTH_USED', 'OUTBOUND_ONLY', 'INBOUND_ONLY', 'NEITHER_USED'
|
||||
@@ -30,9 +54,15 @@ DO $$ BEGIN
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
ALTER TABLE "passenger"."Booking"
|
||||
ADD COLUMN IF NOT EXISTS "returnLegStatus" "passenger"."ReturnLegStatus" NOT NULL DEFAULT 'NOT_APPLICABLE',
|
||||
ADD COLUMN IF NOT EXISTS "outboundBoardedAt" TIMESTAMP(3),
|
||||
ADD COLUMN IF NOT EXISTS "returnBoardedAt" TIMESTAMP(3);
|
||||
ADD COLUMN IF NOT EXISTS "returnLegStatus" "passenger"."ReturnLegStatus" NOT NULL DEFAULT 'NOT_APPLICABLE';
|
||||
|
||||
ALTER TABLE "passenger"."GateValidationLog"
|
||||
ADD COLUMN IF NOT EXISTS "leg" TEXT;
|
||||
-- Add missing columns to other tables
|
||||
ALTER TABLE "passenger"."GateValidationLog" ADD COLUMN IF NOT EXISTS "leg" TEXT;
|
||||
ALTER TABLE "passenger"."BookingSeat" ADD COLUMN IF NOT EXISTS "leg" INTEGER NOT NULL DEFAULT 1;
|
||||
ALTER TABLE "passenger"."BookingSeat" ADD COLUMN IF NOT EXISTS "scheduleId" TEXT;
|
||||
ALTER TABLE "passenger"."Ticket" ADD COLUMN IF NOT EXISTS "boardedAt" TIMESTAMP(3);
|
||||
|
||||
ALTER TABLE "passenger"."SeatClass" ALTER COLUMN "baseFareMinor" SET DEFAULT 0;
|
||||
ALTER TABLE "passenger"."Ticket" ALTER COLUMN "status" SET DEFAULT 'ACTIVE';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "Booking_bookingType_idx" ON "passenger"."Booking"("bookingType");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
provider = "prisma-client-js"
|
||||
previewFeatures = ["multiSchema"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
@@ -79,7 +80,6 @@ model CoachType {
|
||||
updatedAt DateTime @updatedAt
|
||||
coaches Coach[]
|
||||
seatClasses SeatClass[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -116,11 +116,11 @@ enum BookingStatus {
|
||||
}
|
||||
|
||||
enum ReturnLegStatus {
|
||||
NOT_APPLICABLE // one-way booking
|
||||
BOTH_USED // passenger used both legs
|
||||
OUTBOUND_ONLY // return leg not used (no-show on return)
|
||||
INBOUND_ONLY // outbound leg not used, return leg used
|
||||
NEITHER_USED // neither leg boarded yet
|
||||
NOT_APPLICABLE
|
||||
BOTH_USED
|
||||
OUTBOUND_ONLY
|
||||
INBOUND_ONLY
|
||||
NEITHER_USED
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
@@ -269,7 +269,6 @@ model User {
|
||||
fraudAlerts FraudAlert[]
|
||||
|
||||
faydaVerificationSessions FaydaVerificationSession[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -283,7 +282,6 @@ model Session {
|
||||
lastActivityAt DateTime @default(now())
|
||||
createdAt DateTime @default(now())
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -315,7 +313,6 @@ model TravelerProfile {
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
passenger Passenger @relation(fields: [passengerId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -350,7 +347,6 @@ model Train {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
schedules TrainSchedule[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -412,7 +408,6 @@ model TripLiveStatus {
|
||||
platformLabel String?
|
||||
updatedAt DateTime @updatedAt
|
||||
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -500,7 +495,6 @@ model FareRule {
|
||||
validFrom DateTime
|
||||
validUntil DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -584,7 +578,6 @@ model BookingSeat {
|
||||
displayFareMinor Int?
|
||||
booking Booking @relation(fields: [bookingId], references: [id])
|
||||
seat Seat @relation(fields: [seatId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -600,7 +593,6 @@ model PaymentMethod {
|
||||
sortOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -661,7 +653,6 @@ model PaymentRefund {
|
||||
status String
|
||||
createdAt DateTime @default(now())
|
||||
paymentIntent PaymentIntent @relation(fields: [paymentIntentId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -681,7 +672,6 @@ model Ticket {
|
||||
booking Booking @relation(fields: [bookingId], references: [id])
|
||||
validationLogs GateValidationLog[]
|
||||
seats TicketSeat[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -709,7 +699,6 @@ model LoyaltyAccount {
|
||||
passenger Passenger @relation(fields: [passengerId], references: [id])
|
||||
ledger LoyaltyLedgerEntry[]
|
||||
rewards LoyaltyReward[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -722,7 +711,6 @@ model LoyaltyLedgerEntry {
|
||||
balanceAfter Int
|
||||
createdAt DateTime @default(now())
|
||||
account LoyaltyAccount @relation(fields: [accountId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -734,7 +722,6 @@ model LoyaltyReward {
|
||||
available Boolean @default(true)
|
||||
description String?
|
||||
account LoyaltyAccount @relation(fields: [accountId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -763,7 +750,6 @@ model WalletLedgerEntry {
|
||||
relatedBookingId String?
|
||||
createdAt DateTime @default(now())
|
||||
wallet WalletAccount @relation(fields: [walletId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -778,7 +764,6 @@ model Notification {
|
||||
metadata Json?
|
||||
createdAt DateTime @default(now())
|
||||
passenger Passenger @relation(fields: [passengerId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -794,7 +779,6 @@ model Promotion {
|
||||
deepLink String?
|
||||
active Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -808,7 +792,6 @@ model StationCrowdSignal {
|
||||
observedAt DateTime?
|
||||
updatedAt DateTime @updatedAt
|
||||
station Station @relation(fields: [stationId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -820,7 +803,6 @@ model WeatherAlert {
|
||||
message String
|
||||
validUntil DateTime
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -828,7 +810,6 @@ model MenuCategory {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
items MenuItem[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -843,7 +824,6 @@ model MenuItem {
|
||||
availableUntil DateTime?
|
||||
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
||||
category MenuCategory @relation(fields: [categoryId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -858,7 +838,6 @@ model FoodOrder {
|
||||
createdAt DateTime @default(now())
|
||||
booking Booking @relation(fields: [bookingId], references: [id])
|
||||
items FoodOrderItem[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -871,7 +850,6 @@ model FoodOrderItem {
|
||||
unitPriceMinor Int?
|
||||
lineTotalMinor Int
|
||||
order FoodOrder @relation(fields: [orderId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -880,7 +858,6 @@ model FaqCategory {
|
||||
title String
|
||||
iconKey String?
|
||||
articles FaqArticle[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -891,7 +868,6 @@ model FaqArticle {
|
||||
answerMarkdown String
|
||||
rank Int @default(0)
|
||||
category FaqCategory @relation(fields: [categoryId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -902,7 +878,6 @@ model SupportConversation {
|
||||
status SupportConversationStatus @default(OPEN)
|
||||
createdAt DateTime @default(now())
|
||||
messages SupportMessage[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -914,7 +889,6 @@ model SupportMessage {
|
||||
attachments Json?
|
||||
createdAt DateTime @default(now())
|
||||
conversation SupportConversation @relation(fields: [conversationId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -934,7 +908,6 @@ model UserPreferences {
|
||||
darkMode Boolean @default(false)
|
||||
language String @default("en")
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -947,7 +920,6 @@ model Device {
|
||||
trusted Boolean @default(false)
|
||||
lastSeenAt DateTime @default(now())
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -961,7 +933,6 @@ model SavedRoute {
|
||||
tripCount Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
passenger Passenger @relation(fields: [passengerId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -973,7 +944,6 @@ model Journey {
|
||||
currency String @default("ETB")
|
||||
createdAt DateTime @default(now())
|
||||
journeySegments JourneySegment[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -988,7 +958,6 @@ model JourneySegment {
|
||||
arrivalStationId String
|
||||
journey Journey @relation(fields: [journeyId], references: [id])
|
||||
schedule TrainSchedule @relation(fields: [scheduleId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -1032,7 +1001,6 @@ model Route {
|
||||
fareRules RouteFareRule[]
|
||||
segmentFares SegmentFareRule[]
|
||||
schedules TrainSchedule[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -1102,7 +1070,6 @@ model Agent {
|
||||
bookings AgentBooking[]
|
||||
shifts AgentShift[]
|
||||
commissions AgentCommission[]
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -1117,7 +1084,6 @@ model AgentBooking {
|
||||
createdAt DateTime @default(now())
|
||||
agent Agent @relation(fields: [agentId], references: [id])
|
||||
booking Booking @relation(fields: [bookingId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -1177,7 +1143,6 @@ model BookingCancellation {
|
||||
processedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
booking Booking @relation(fields: [bookingId], references: [id])
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -1205,7 +1170,6 @@ model BaggageAllowance {
|
||||
excessFeePerKg Int
|
||||
currency String @default("ETB")
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -1249,7 +1213,6 @@ model NotificationTemplate {
|
||||
bodyTemplate String
|
||||
active Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
@@ -1288,7 +1251,6 @@ model FraudRule {
|
||||
config Json?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@schema("passenger")
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ async function seedRoute() {
|
||||
create: { routeId: route.id, stationId: station!.id, sequence: i + 1, distanceKm: routeDistancesKm[i] },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const returnRoute = await prisma.route.upsert({
|
||||
where: { code: 'Route-102' },
|
||||
update: {},
|
||||
@@ -317,7 +317,7 @@ async function seedTrips() {
|
||||
const now = new Date();
|
||||
const tomorrow = new Date(now);
|
||||
tomorrow.setDate(now.getDate() + 1);
|
||||
|
||||
|
||||
const schedules = [];
|
||||
|
||||
for (let d = 0; d < 5; d++) {
|
||||
@@ -403,7 +403,7 @@ async function seedTrips() {
|
||||
|
||||
const coachAssignments = [];
|
||||
const liveStatuses = [];
|
||||
|
||||
|
||||
for (const schedule of createdSchedules) {
|
||||
for (let p = 0; p < coaches.length; p++) {
|
||||
coachAssignments.push({
|
||||
@@ -418,12 +418,12 @@ async function seedTrips() {
|
||||
progressPercent: 0,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
await Promise.all([
|
||||
...coachAssignments.map(ca => prisma.coachAssignment.create({ data: ca })),
|
||||
...liveStatuses.map(ls => prisma.tripLiveStatus.create({ data: ls })),
|
||||
]);
|
||||
|
||||
|
||||
console.log(` ✅ Train with ${createdSchedules.length} upcoming trips created`);
|
||||
}
|
||||
|
||||
@@ -453,7 +453,7 @@ async function seedFareRules() {
|
||||
validFrom,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
await Promise.all(
|
||||
fareRules.map(fr => prisma.routeFareRule.create({ data: fr }))
|
||||
);
|
||||
@@ -518,7 +518,7 @@ async function seedSegmentFares() {
|
||||
include: { stops: { orderBy: { sequence: 'asc' } } },
|
||||
});
|
||||
const seatClasses = await prisma.seatClass.findMany();
|
||||
const validFrom = new Date('2024-01-01');
|
||||
const validFrom = new Date('2026-01-01');
|
||||
|
||||
if (route && route.stops.length > 2) {
|
||||
for (const sc of seatClasses) {
|
||||
@@ -531,7 +531,7 @@ async function seedSegmentFares() {
|
||||
baseFareMinor: Math.floor(sc.baseFareMinor * 0.4),
|
||||
validFrom,
|
||||
},
|
||||
}).catch(() => {});
|
||||
}).catch(() => { });
|
||||
|
||||
await prisma.segmentFareRule.create({
|
||||
data: {
|
||||
@@ -542,7 +542,7 @@ async function seedSegmentFares() {
|
||||
baseFareMinor: Math.floor(sc.baseFareMinor * 0.6),
|
||||
validFrom,
|
||||
},
|
||||
}).catch(() => {});
|
||||
}).catch(() => { });
|
||||
}
|
||||
console.log(` ✅ ${seatClasses.length * 2} segment fare rules created`);
|
||||
}
|
||||
@@ -586,16 +586,16 @@ async function seedMenuAndFood() {
|
||||
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: 50 },
|
||||
}).catch(() => {}); // ignore if exists
|
||||
}).catch(() => { }); // ignore if exists
|
||||
await prisma.menuItem.create({
|
||||
data: { id: juiceId, scheduleId: schedule.id, categoryId: beverages.id, name: 'Fresh Juice', priceMinor: 35 },
|
||||
}).catch(() => {}); // ignore if exists
|
||||
}).catch(() => { }); // ignore if exists
|
||||
await prisma.menuItem.create({
|
||||
data: { id: sandwichId, scheduleId: schedule.id, categoryId: snacks.id, name: 'Sandwich', priceMinor: 80 },
|
||||
}).catch(() => {}); // ignore if exists
|
||||
}).catch(() => { }); // ignore if exists
|
||||
}
|
||||
console.log(` ✅ Menu categories and items created`);
|
||||
}
|
||||
@@ -682,6 +682,9 @@ async function main() {
|
||||
|
||||
const steps: Array<[string, () => Promise<unknown>]> = [
|
||||
['system users', seedSystemUsers],
|
||||
['fare rules', seedFareRules],
|
||||
['segment fares', seedSegmentFares],
|
||||
['currency', seedCurrency]
|
||||
];
|
||||
|
||||
let failed = 0;
|
||||
|
||||
Reference in New Issue
Block a user