mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 17:10:56 +00:00
- 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.
76 lines
2.9 KiB
TypeScript
76 lines
2.9 KiB
TypeScript
import { BaseEntity } from '@edr/api-common';
|
|
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
|
|
|
import { Booking } from '../../bookings/entities/booking.entity';
|
|
import { TrainSchedule } from '../../train-schedules/entities/train-schedule.entity';
|
|
|
|
export const BOOKING_BATCH_OFFER_STATUSES = ['OFFERED', 'APPLIED', 'EXPIRED'] as const;
|
|
export type BookingBatchOfferStatus = (typeof BOOKING_BATCH_OFFER_STATUSES)[number];
|
|
|
|
/** One reduced container line of a partial offer (per original booking_container row). */
|
|
export interface OfferedLine {
|
|
bookingContainerId: string;
|
|
/** Units of this line that ride the offered train (≤ original quantity). */
|
|
quantity: number;
|
|
wagonsRequired: number;
|
|
totalVgmTons: number;
|
|
}
|
|
|
|
/**
|
|
* A partial-capacity payment offer made by the batch when a booking needs more
|
|
* wagons than the train has left (e.g. needs 20, 3 free). The booking itself is
|
|
* NOT mutated at offer time — paying inside the window accepts the split
|
|
* (BookingSplitService.applySplit reduces the booking to the offered lines and
|
|
* the remainder returns to the contract's quantity cap); letting the deadline
|
|
* pass expires the offer and the booking stays whole.
|
|
*/
|
|
@Entity({ schema: 'freight', name: 'booking_batch_offers' })
|
|
@Index(['bookingId'])
|
|
@Index(['trainScheduleId'])
|
|
@Index(['status'])
|
|
export class BookingBatchOffer extends BaseEntity {
|
|
@Column({ name: 'booking_id', type: 'uuid' })
|
|
bookingId!: string;
|
|
|
|
@ManyToOne(() => Booking, { onDelete: 'CASCADE' })
|
|
@JoinColumn({ name: 'booking_id' })
|
|
booking?: Booking;
|
|
|
|
@Column({ name: 'train_schedule_id', type: 'uuid' })
|
|
trainScheduleId!: string;
|
|
|
|
@ManyToOne(() => TrainSchedule, { onDelete: 'CASCADE' })
|
|
@JoinColumn({ name: 'train_schedule_id' })
|
|
trainSchedule?: TrainSchedule;
|
|
|
|
@Column({ name: 'offered_wagons', type: 'int' })
|
|
offeredWagons!: number;
|
|
|
|
/** Booking's full wagon need at offer time (for messaging / audit). */
|
|
@Column({ name: 'total_wagons', type: 'int' })
|
|
totalWagons!: number;
|
|
|
|
/** Reduced container lines (null for bulk offers — bulk splits by weight). */
|
|
@Column({ name: 'offered_lines', type: 'jsonb', nullable: true })
|
|
offeredLines?: OfferedLine[] | null;
|
|
|
|
@Column({ name: 'offered_weight_tons', type: 'numeric', precision: 12, scale: 3 })
|
|
offeredWeightTons!: number;
|
|
|
|
@Column({ name: 'offered_amount', type: 'numeric', precision: 14, scale: 2 })
|
|
offeredAmount!: number;
|
|
|
|
@Column({ name: 'offered_pricing_breakdown', type: 'jsonb', nullable: true })
|
|
offeredPricingBreakdown?: Record<string, unknown> | null;
|
|
|
|
/** The partial PREPAID invoice generated for the offered part. */
|
|
@Column({ name: 'invoice_id', type: 'uuid', nullable: true })
|
|
invoiceId?: string | null;
|
|
|
|
@Column({ name: 'payment_deadline', type: 'timestamptz' })
|
|
paymentDeadline!: Date;
|
|
|
|
@Column({ name: 'status', type: 'varchar', length: 10, default: 'OFFERED' })
|
|
status!: BookingBatchOfferStatus;
|
|
}
|