Add booking window management and locomotive scheduling features

- Implemented migration to release stuck assigned locomotives.
- Added schedule window phases to train schedules.
- Created booking batch offers table for partial capacity bookings.
- Developed BookingSplitService to handle partial booking offers and splits.
- Introduced BookingWindowService to manage booking window lifecycle and transitions.
- Added BookingBatchOffer entity to represent offers made during booking splits.
- Enhanced locomotive options with warnings for scheduling.
- Created UpcomingWindowsSection component to display upcoming booking windows.
This commit is contained in:
Marshal
2026-07-03 03:36:06 +00:00
parent 18c158fb61
commit 56de90892d
41 changed files with 2480 additions and 124 deletions

View File

@@ -43,6 +43,8 @@ import { AvailableDaysForCargoQueryDto } from "./dto/available-days-for-cargo-qu
import { UpdateTrainSchedulingGlobalRulesDto } from "./dto/update-train-scheduling-global-rules.dto";
import { TrainSchedulingService } from "./train-scheduling.service";
import { BookingBatchService } from "./booking-batch.service";
import { BookingWindowService } from "./booking-window.service";
import { BillingService } from "../billing/billing.service";
@ApiTags("train-scheduling")
@ApiBearerAuth()
@@ -51,8 +53,23 @@ export class TrainSchedulingController {
constructor(
private readonly trainSchedulingService: TrainSchedulingService,
private readonly bookingBatchService: BookingBatchService,
private readonly bookingWindowService: BookingWindowService,
private readonly billingService: BillingService,
) { }
@Get("my-booking-windows")
@ApiOperation({
summary:
"Upcoming/open booking windows on the signed-in customer's active contract lanes",
})
async getMyBookingWindows(@CurrentUser() user: AuthUserPayload) {
const companyId = await this.billingService.resolveCompanyId(
resolveAuthUserId(user),
);
if (!companyId) return [];
return this.trainSchedulingService.getBookingWindowsForCompany(companyId);
}
@Get("global-rules")
@TrainSchedulingView()
@ApiOperation({ summary: "Get global train scheduling rules (singleton)" })
@@ -457,6 +474,17 @@ export class TrainSchedulingController {
return this.trainSchedulingService.getContainerTrainScheduleById(id);
}
@Post("schedules/:id/doc-review-complete")
@TrainSchedulingManage()
@ApiOperation({
summary:
"Staff finished document review early — run the batch/payment phase now (applies to the whole route-day group)",
})
async completeDocReview(@Param("id", ParseUUIDPipe) id: string) {
await this.bookingWindowService.completeDocReview(id);
return this.bookingBatchService.getBatchBoardDetail(id);
}
@Post("bookings/:bookingId/mark-paid")
@TrainSchedulingManage()
@ApiOperation({