Package passenger numbers and pricing updates

This commit is contained in:
Stephanos A
2026-07-05 18:14:42 +03:00
parent 9e77ca7865
commit afd30c36a0
20 changed files with 537 additions and 105 deletions

View File

@@ -341,8 +341,9 @@ export class BookingsService {
totalMinor: b.totalMinor, currency: b.currency || 'ETB',
displayCurrency: b.displayCurrency, displayTotalMinor: b.displayTotalMinor,
contactEmail: b.contactEmail, contactPhone: b.contactPhone,
bookingType: 'PACKAGE', packageId: b.packageId, isPackageBooking: true,
packageName: b.package?.name, packageCode: b.package?.code,
bookingType: 'PACKAGE', packageId: b.packageId, priceTierId: b.priceTierId,
isPackageBooking: true, packageName: b.package?.name, packageCode: b.package?.code,
tierLabel: b.priceTier?.label ?? null,
returnLegStatus: null, adultCount: b.passengerCount, childCount: 0,
createdAt: b.createdAt, passenger: null,
passengerNames: b.passengers?.map((p: any) => p.passengerName) ?? [],
@@ -372,6 +373,8 @@ export class BookingsService {
schedule: { include: { originStation: true, destinationStation: true, train: true } },
paymentIntent: true,
seats: { include: { seat: true } },
package: { select: { id: true, name: true, code: true } },
priceTier: { select: { id: true, label: true } },
},
}),
this.prisma.booking.count({ where }),
@@ -415,6 +418,10 @@ export class BookingsService {
contactPhone: booking.contactPhone,
bookingType: booking.bookingType,
packageId: booking.packageId ?? null,
priceTierId: (booking as any).priceTierId ?? null,
packageName: (booking as any).package?.name ?? null,
packageCode: (booking as any).package?.code ?? null,
tierLabel: (booking as any).priceTier?.label ?? null,
isPackageBooking: !!booking.packageId,
returnLegStatus: (booking as any).returnLegStatus ?? null,
adultCount: booking.adultCount,
@@ -446,9 +453,11 @@ export class BookingsService {
contactPhone: b.contactPhone,
bookingType: 'PACKAGE',
packageId: b.packageId,
priceTierId: b.priceTierId,
isPackageBooking: true,
packageName: b.package?.name,
packageCode: b.package?.code,
tierLabel: b.priceTier?.label ?? null,
returnLegStatus: null,
adultCount: b.passengerCount,
childCount: 0,
@@ -518,20 +527,18 @@ export class BookingsService {
displayTotalMinor = await this.currencyService.convertAmount(fareCalculation.totalMinor, Currency.ETB, displayCurrency);
}
// Track which child gets free fare (first child encountered)
// Track per-seat fare. For package bookings children pay 10% of adult fare;
// for regular bookings the first child is free.
let freeChildUsed = false;
const passengersWithFares = passengersData.map(p => {
let fareMinor: number;
if (p.category === PassengerCategory.ADULT) {
fareMinor = fareCalculation.baseFareMinor;
} else if (dto.packageId) {
fareMinor = Math.round(fareCalculation.baseFareMinor * 0.1);
} else {
// Child: first child is free, subsequent children pay full fare
if (!freeChildUsed) {
fareMinor = 0;
freeChildUsed = true;
} else {
fareMinor = fareCalculation.baseFareMinor;
}
if (!freeChildUsed) { fareMinor = 0; freeChildUsed = true; }
else fareMinor = fareCalculation.baseFareMinor;
}
return { ...p, fareMinor };
});
@@ -661,34 +668,27 @@ export class BookingsService {
displayTotalMinor = await this.currencyService.convertAmount(totalMinor, Currency.ETB, displayCurrency);
}
// Track which child gets free fare for outbound and return legs
// Track per-seat fare. For package bookings children pay 10% of adult fare;
// for regular bookings the first child is free per leg.
let outboundFreeChildUsed = false;
let returnFreeChildUsed = false;
const passengersWithFares = passengersData.map(p => {
let outboundFareMinor: number;
let returnFareMinor: number;
if (p.category === PassengerCategory.ADULT) {
outboundFareMinor = outboundFare.baseFareMinor;
returnFareMinor = returnFare.baseFareMinor;
} else if (dto.packageId) {
outboundFareMinor = Math.round(outboundFare.baseFareMinor * 0.1);
returnFareMinor = Math.round(returnFare.baseFareMinor * 0.1);
} else {
// Child fare for outbound
if (!outboundFreeChildUsed) {
outboundFareMinor = 0;
outboundFreeChildUsed = true;
} else {
outboundFareMinor = outboundFare.baseFareMinor;
}
// Child fare for return
if (!returnFreeChildUsed) {
returnFareMinor = 0;
returnFreeChildUsed = true;
} else {
returnFareMinor = returnFare.baseFareMinor;
}
if (!outboundFreeChildUsed) { outboundFareMinor = 0; outboundFreeChildUsed = true; }
else outboundFareMinor = outboundFare.baseFareMinor;
if (!returnFreeChildUsed) { returnFareMinor = 0; returnFreeChildUsed = true; }
else returnFareMinor = returnFare.baseFareMinor;
}
return { ...p, outboundFareMinor, returnFareMinor };
});
@@ -1231,16 +1231,20 @@ export class BookingsService {
childCount: number,
) {
const tier = await this.prisma.packagePriceTier.findUniqueOrThrow({ where: { id: priceTierId } });
const passengerCount = adultCount + childCount;
const totalBaseFareMinor = tier.priceMinor * passengerCount;
// For round-trip packages the caller splits the tier price across legs, so
// priceMinor here is already the per-leg amount. Children pay 10% of adult fare.
const childFareMinor = Math.round(tier.priceMinor * 0.1);
const adultFareMinor = tier.priceMinor * adultCount;
const childTotalMinor = childFareMinor * childCount;
const totalBaseFareMinor = adultFareMinor + childTotalMinor;
return {
baseFareMinor: tier.priceMinor,
adultCount,
adultFareMinor: tier.priceMinor * adultCount,
adultFareMinor,
childCount,
freeChildrenCount: 0,
paidChildrenCount: childCount,
childFareMinor: tier.priceMinor * childCount,
childFareMinor: childTotalMinor,
totalBaseFareMinor,
discountMinor: 0,
loyaltyRedemptionMinor: 0,

View File

@@ -144,6 +144,12 @@ export class CreateGuestBookingDto {
@ApiPropertyOptional({ example: 'device-uuid-12345', description: 'Device ID for local storage of passenger details' })
@IsOptional() @IsString() deviceId?: string;
@ApiPropertyOptional({ description: 'Package ID — when set, fare is taken from the package price tier' })
@IsOptional() @IsString() packageId?: string;
@ApiPropertyOptional({ description: 'Package price tier ID — required when packageId is provided' })
@IsOptional() @IsString() priceTierId?: string;
}
export class SavedPassengerProfileDto {

View File

@@ -157,8 +157,10 @@ export class GuestBookingService {
);
const adultFareMinor = baseFareMinor * adultCount;
const paidChildrenCount = Math.max(0, childCount - 1);
const childFareMinor = baseFareMinor * paidChildrenCount;
const isPackageOneway = !!dto.packageId;
const paidChildrenCount = isPackageOneway ? childCount : Math.max(0, childCount - 1);
const childUnitFare = isPackageOneway ? Math.round(baseFareMinor * 0.1) : baseFareMinor;
const childFareMinor = childUnitFare * paidChildrenCount;
const totalBaseFareMinor = adultFareMinor + childFareMinor;
let discountMinor = 0;
@@ -217,6 +219,7 @@ export class GuestBookingService {
displayCurrency,
displayTotalMinor,
bookingType: 'ONE_WAY',
...(dto.packageId ? { packageId: dto.packageId, priceTierId: dto.priceTierId } : {}),
userAgent: dto.deviceId,
contactEmail: firstPassenger.email || null,
contactPhone: firstPassenger.phone || null,
@@ -231,7 +234,7 @@ export class GuestBookingService {
passportCountry: p.passportCountry,
verifaydaVerified: p.verifaydaVerified,
verifaydaData: p.verifaydaData || undefined,
fareMinor: p.category === PassengerCategory.ADULT ? baseFareMinor : (paidChildrenCount > 0 ? baseFareMinor : 0),
fareMinor: p.category === PassengerCategory.ADULT ? baseFareMinor : childUnitFare,
displayCurrency,
})),
},
@@ -258,7 +261,7 @@ export class GuestBookingService {
adultCount,
adultFareMinor,
childCount,
freeChildrenCount: Math.min(childCount, 1),
freeChildrenCount: isPackageOneway ? 0 : Math.min(childCount, 1),
paidChildrenCount,
childFareMinor,
totalBaseFareMinor,
@@ -375,9 +378,12 @@ export class GuestBookingService {
this.getBaseFare(dto.returnScheduleId, returnSeatClassId, returnSegmentRoute, returnFullRoute, primaryNationality, dto.returnOriginStationId, dto.returnDestinationStationId),
]);
const paidChildrenCount = Math.max(0, childCount - 1);
const outboundTotalBase = outboundBaseFare * adultCount + outboundBaseFare * paidChildrenCount;
const returnTotalBase = returnBaseFare * adultCount + returnBaseFare * paidChildrenCount;
const isPackageRoundTrip = !!dto.packageId;
const paidChildrenCount = isPackageRoundTrip ? childCount : Math.max(0, childCount - 1);
const outboundChildUnitFare = isPackageRoundTrip ? Math.round(outboundBaseFare * 0.1) : outboundBaseFare;
const returnChildUnitFare = isPackageRoundTrip ? Math.round(returnBaseFare * 0.1) : returnBaseFare;
const outboundTotalBase = outboundBaseFare * adultCount + outboundChildUnitFare * paidChildrenCount;
const returnTotalBase = returnBaseFare * adultCount + returnChildUnitFare * paidChildrenCount;
const combinedBaseFareMinor = outboundTotalBase + returnTotalBase;
let discountMinor = 0;
@@ -423,6 +429,7 @@ export class GuestBookingService {
returnHoldId: dto.returnHoldId,
returnSeatClassId,
returnLegStatus: 'NEITHER_USED',
...(dto.packageId ? { packageId: dto.packageId, priceTierId: dto.priceTierId } : {}),
userAgent: dto.deviceId,
contactEmail: passengersData[0]?.email || null,
contactPhone: passengersData[0]?.phone || null,
@@ -440,7 +447,7 @@ export class GuestBookingService {
passportCountry: p.passportCountry,
verifaydaVerified: p.verifaydaVerified,
verifaydaData: p.verifaydaData || undefined,
fareMinor: p.category === PassengerCategory.ADULT ? outboundBaseFare : (paidChildrenCount > 0 ? outboundBaseFare : 0),
fareMinor: p.category === PassengerCategory.ADULT ? outboundBaseFare : outboundChildUnitFare,
displayCurrency,
})),
...passengersData.map((p) => ({
@@ -455,7 +462,7 @@ export class GuestBookingService {
passportCountry: p.passportCountry,
verifaydaVerified: p.verifaydaVerified,
verifaydaData: p.verifaydaData || undefined,
fareMinor: p.category === PassengerCategory.ADULT ? returnBaseFare : (paidChildrenCount > 0 ? returnBaseFare : 0),
fareMinor: p.category === PassengerCategory.ADULT ? returnBaseFare : returnChildUnitFare,
displayCurrency,
})),
],
@@ -484,7 +491,7 @@ export class GuestBookingService {
returnBaseFareMinor: returnBaseFare,
adultCount,
childCount,
freeChildrenCount: Math.min(childCount, 1),
freeChildrenCount: isPackageRoundTrip ? 0 : Math.min(childCount, 1),
paidChildrenCount,
combinedBaseFareMinor,
discountMinor,

View File

@@ -329,7 +329,7 @@ export class ConfigurableFareService {
);
if (childRule) {
const freeChildren = Math.min(childCount, childRule.max_free_passengers);
const freeChildren = Math.min(childCount, adultCount);
const paidChildren = Math.max(0, childCount - freeChildren);
if (freeChildren > 0) {

View File

@@ -131,7 +131,7 @@ export class FareEngineService {
const adultCount = dto.adultCount ?? 1;
const childCount = dto.childCount ?? 0;
const freeChildrenCount = Math.min(childCount, adultCount);
const paidChildrenCount = Math.max(0, childCount - 1);
const paidChildrenCount = Math.max(0, childCount - freeChildrenCount);
// Subtotal includes: (distance-based fare + premium + insurance) × passengers
// First child is free, but pays premium and insurance

View File

@@ -118,4 +118,10 @@ export class BookPackageDto {
@ApiProperty({ type: [BookPackagePassengerDto] })
@IsArray() @ValidateNested({ each: true }) @Type(() => BookPackagePassengerDto)
passengers: BookPackagePassengerDto[];
/** Number of adult passengers (≥5 years). Derived from passengers array if omitted. */
@ApiPropertyOptional({ example: 2 }) @IsOptional() @IsInt() @Min(1) adultCount?: number;
/** Number of child passengers (<5 years). Derived from passengers array if omitted. */
@ApiPropertyOptional({ example: 1 }) @IsOptional() @IsInt() @Min(0) childCount?: number;
}

View File

@@ -6,6 +6,32 @@ import { Currency } from '@prisma/client';
import { BookingsService } from '../bookings/bookings.service';
import { GuestBookingService } from '../bookings/guest-booking.service';
/** Package-specific fare rules */
const PKG_MAX_ADULTS = 5;
const PKG_MAX_CHILDREN = 2;
const PKG_CHILD_FARE_RATIO = 0.1;
function calculatePackageFareBreakdown(
priceMinor: number,
isRoundTrip: boolean,
adultCount: number,
childCount: number,
) {
const multiplier = isRoundTrip ? 2 : 1;
const adultFareMinor = priceMinor * multiplier;
const childFareMinor = Math.round(adultFareMinor * PKG_CHILD_FARE_RATIO);
const totalMinor = adultCount * adultFareMinor + childCount * childFareMinor;
return { adultFareMinor, childFareMinor, totalMinor, multiplier };
}
function deriveAge(dateOfBirth: string | Date): number {
const today = new Date();
const dob = new Date(dateOfBirth);
let age = today.getFullYear() - dob.getFullYear();
if (today < new Date(today.getFullYear(), dob.getMonth(), dob.getDate())) age--;
return age;
}
function generateRef(): string {
return 'PKG-' + Array.from({ length: 6 }, () =>
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[Math.floor(Math.random() * 26)],
@@ -41,14 +67,19 @@ export class PackagesService {
const tier = pkg.priceTiers.find(t => t.id === tierId);
if (!tier) throw new NotFoundException('Price tier not found');
const passengerCount = adultCount + childCount;
if (passengerCount < 1) throw new BadRequestException('At least one passenger required');
if (adultCount < 1) throw new BadRequestException('At least one adult passenger required');
if (adultCount > PKG_MAX_ADULTS) throw new BadRequestException(`Maximum ${PKG_MAX_ADULTS} adults allowed per package booking`);
if (childCount > PKG_MAX_CHILDREN) throw new BadRequestException(`Maximum ${PKG_MAX_CHILDREN} children allowed per package booking`);
const passengerCount = adultCount + childCount;
const remaining = tier.availableSeats - tier.bookedSeats;
if (passengerCount > remaining)
throw new BadRequestException(`Only ${remaining} seat(s) remaining in the ${tier.label} tier`);
const totalMinor = tier.priceMinor * passengerCount;
const isRoundTrip = !!pkg.returnScheduleId;
const { adultFareMinor, childFareMinor, totalMinor } = calculatePackageFareBreakdown(
tier.priceMinor, isRoundTrip, adultCount, childCount,
);
// Resolve the seatClassId and coachTypeId that matches this tier's seatType from the outbound schedule coaches
let seatClassId: string | null = null;
@@ -60,7 +91,6 @@ export class PackagesService {
);
if (sc) { seatClassId = sc.id; coachTypeId = a.coach.coachTypeId ?? a.coach.coachType?.id ?? null; break; }
}
// Fallback: use the first coach assignment's coachTypeId if no match found
if (!coachTypeId && pkg.outboundSchedule.coachAssignments.length > 0) {
const first = pkg.outboundSchedule.coachAssignments[0];
coachTypeId = first.coach.coachTypeId ?? first.coach.coachType?.id ?? null;
@@ -77,7 +107,12 @@ export class PackagesService {
adultCount,
childCount,
passengerCount,
pricePerPassengerMinor: tier.priceMinor,
isRoundTrip,
pricePerAdultMinor: adultFareMinor,
pricePerChildMinor: childFareMinor,
childFareNote: `Children pay ${PKG_CHILD_FARE_RATIO * 100}% of adult fare`,
maxAdults: PKG_MAX_ADULTS,
maxChildren: PKG_MAX_CHILDREN,
totalMinor,
currency: tier.currency,
remainingSeats: remaining,
@@ -297,13 +332,30 @@ export class PackagesService {
const tier = pkg.priceTiers.find((t) => t.id === dto.priceTierId);
if (!tier) throw new NotFoundException('Price tier not found');
const passengerCount = dto.passengers.length;
// Derive adult/child counts from the passengers array (dateOfBirth-based)
let adultCount = 0, childCount = 0;
for (const p of dto.passengers) {
if (p.dateOfBirth && deriveAge(p.dateOfBirth) < 5) childCount++;
else adultCount++;
}
// Allow explicit override from mobile app (e.g. when dateOfBirth is not provided per passenger)
if (dto.adultCount !== undefined) adultCount = dto.adultCount;
if (dto.childCount !== undefined) childCount = dto.childCount;
if (adultCount < 1) throw new BadRequestException('At least one adult passenger required');
if (adultCount > PKG_MAX_ADULTS) throw new BadRequestException(`Maximum ${PKG_MAX_ADULTS} adults allowed per package booking`);
if (childCount > PKG_MAX_CHILDREN) throw new BadRequestException(`Maximum ${PKG_MAX_CHILDREN} children allowed per package booking`);
const passengerCount = adultCount + childCount;
const remaining = tier.availableSeats - tier.bookedSeats;
if (passengerCount > remaining) {
throw new BadRequestException(`Only ${remaining} seats remaining in the ${tier.label} tier`);
}
const totalMinor = tier.priceMinor * passengerCount;
const isRoundTrip = !!pkg.returnScheduleId;
const { adultFareMinor, childFareMinor, totalMinor } = calculatePackageFareBreakdown(
tier.priceMinor, isRoundTrip, adultCount, childCount,
);
const displayCurrency = (dto.displayCurrency as Currency) ?? Currency.ETB;
const displayTotalMinor =
displayCurrency !== Currency.ETB
@@ -354,7 +406,21 @@ export class PackagesService {
}),
]);
return booking;
return {
...booking,
fareBreakdown: {
isRoundTrip,
adultCount,
adultFareMinor,
childCount,
childFareMinor,
childFareNote: `Children pay ${PKG_CHILD_FARE_RATIO * 100}% of adult fare`,
totalMinor,
currency: 'ETB',
displayCurrency,
displayTotalMinor,
},
};
}
getMyBookings(passengerId: string) {

View File

@@ -0,0 +1,49 @@
import {
Controller, Get, Post, Put, Delete,
Param, Body, Query, UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation, ApiQuery } from '@nestjs/swagger';
import { IamGuard } from '../../common/iam-adapter';
import { Roles } from '../../common/roles.decorator';
import { SegmentFareService } from './segment-fare.service';
import { CreateSegmentFareDto, UpdateSegmentFareDto } from './segment-fare.dto';
@ApiTags('Admin Segment Fares')
@Controller('admin/segment-fares')
@ApiBearerAuth('IAM-auth')
@UseGuards(IamGuard)
@Roles('ADMIN', 'SUPERVISOR')
export class SegmentFareController {
constructor(private readonly service: SegmentFareService) {}
@Get()
@ApiOperation({ summary: 'List all segment fare rules, optionally filtered by route' })
@ApiQuery({ name: 'routeId', required: false })
findAll(@Query('routeId') routeId?: string) {
return this.service.findAll(routeId);
}
@Get(':id')
@ApiOperation({ summary: 'Get a single segment fare rule' })
findOne(@Param('id') id: string) {
return this.service.findOne(id);
}
@Post()
@ApiOperation({ summary: 'Create a segment fare rule' })
create(@Body() dto: CreateSegmentFareDto) {
return this.service.create(dto);
}
@Put(':id')
@ApiOperation({ summary: 'Update a segment fare rule' })
update(@Param('id') id: string, @Body() dto: UpdateSegmentFareDto) {
return this.service.update(id, dto);
}
@Delete(':id')
@ApiOperation({ summary: 'Delete a segment fare rule' })
remove(@Param('id') id: string) {
return this.service.remove(id);
}
}

View File

@@ -0,0 +1,67 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import {
IsString, IsInt, IsOptional, IsDateString, IsIn, Min,
} from 'class-validator';
export class CreateSegmentFareDto {
@ApiProperty({ example: 'route-uuid' })
@IsString()
routeId: string;
@ApiProperty({ example: 1 })
@IsInt() @Min(0)
originStopSequence: number;
@ApiProperty({ example: 5 })
@IsInt() @Min(1)
destinationStopSequence: number;
@ApiProperty({ example: 'seat-class-uuid' })
@IsString()
seatClassId: string;
@ApiProperty({ example: 35000, description: 'Base fare in minor units (e.g. 350.00 ETB = 35000)' })
@IsInt() @Min(0)
baseFareMinor: number;
@ApiPropertyOptional({ example: 'LOCAL', enum: ['LOCAL', 'INTERNATIONAL'] })
@IsOptional()
@IsIn(['LOCAL', 'INTERNATIONAL'])
nationality?: string;
@ApiPropertyOptional({ example: 'ETB', default: 'ETB' })
@IsOptional()
@IsString()
currency?: string;
@ApiProperty({ example: '2025-01-01T00:00:00.000Z' })
@IsDateString()
validFrom: string;
@ApiPropertyOptional({ example: '2026-12-31T23:59:59.000Z' })
@IsOptional()
@IsDateString()
validUntil?: string;
}
export class UpdateSegmentFareDto {
@ApiPropertyOptional({ example: 40000 })
@IsOptional()
@IsInt() @Min(0)
baseFareMinor?: number;
@ApiPropertyOptional({ example: 'ETB' })
@IsOptional()
@IsString()
currency?: string;
@ApiPropertyOptional({ example: '2025-06-01T00:00:00.000Z' })
@IsOptional()
@IsDateString()
validFrom?: string;
@ApiPropertyOptional({ example: '2026-12-31T23:59:59.000Z' })
@IsOptional()
@IsDateString()
validUntil?: string;
}

View File

@@ -0,0 +1,62 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../common/prisma.service';
import { CreateSegmentFareDto, UpdateSegmentFareDto } from './segment-fare.dto';
@Injectable()
export class SegmentFareService {
constructor(private readonly prisma: PrismaService) {}
findAll(routeId?: string) {
return this.prisma.segmentFareRule.findMany({
where: routeId ? { routeId } : undefined,
include: { seatClass: true, route: { select: { id: true, code: true, name: true } } },
orderBy: [{ routeId: 'asc' }, { originStopSequence: 'asc' }, { destinationStopSequence: 'asc' }],
});
}
async findOne(id: string) {
const rule = await this.prisma.segmentFareRule.findUnique({
where: { id },
include: { seatClass: true, route: { select: { id: true, code: true, name: true } } },
});
if (!rule) throw new NotFoundException(`SegmentFareRule ${id} not found`);
return rule;
}
create(dto: CreateSegmentFareDto) {
return this.prisma.segmentFareRule.create({
data: {
routeId: dto.routeId,
originStopSequence: dto.originStopSequence,
destinationStopSequence: dto.destinationStopSequence,
seatClassId: dto.seatClassId,
baseFareMinor: dto.baseFareMinor,
nationality: dto.nationality ?? null,
currency: dto.currency ?? 'ETB',
validFrom: new Date(dto.validFrom),
validUntil: dto.validUntil ? new Date(dto.validUntil) : null,
},
include: { seatClass: true },
});
}
async update(id: string, dto: UpdateSegmentFareDto) {
await this.findOne(id);
return this.prisma.segmentFareRule.update({
where: { id },
data: {
...(dto.baseFareMinor !== undefined && { baseFareMinor: dto.baseFareMinor }),
...(dto.currency !== undefined && { currency: dto.currency }),
...(dto.validFrom !== undefined && { validFrom: new Date(dto.validFrom) }),
...(dto.validUntil !== undefined && { validUntil: new Date(dto.validUntil) }),
},
include: { seatClass: true },
});
}
async remove(id: string) {
await this.findOne(id);
await this.prisma.segmentFareRule.delete({ where: { id } });
return { deleted: true };
}
}

View File

@@ -3,20 +3,24 @@ import { SegmentsService } from './segments.service';
import { EnhancedSeatsService } from './enhanced-seats.service';
import { TripProgressService } from './trip-progress.service';
import { SegmentSeatsController } from './segments.controller';
import { SegmentFareController } from './segment-fare.controller';
import { SegmentFareService } from './segment-fare.service';
import { PrismaService } from '../../common/prisma.service';
@Module({
controllers: [SegmentSeatsController],
controllers: [SegmentSeatsController, SegmentFareController],
providers: [
SegmentsService,
EnhancedSeatsService,
TripProgressService,
PrismaService
SegmentFareService,
PrismaService,
],
exports: [
SegmentsService,
EnhancedSeatsService,
TripProgressService
]
TripProgressService,
SegmentFareService,
],
})
export class SegmentsModule {}