mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
- Added support for viewing and managing consolidated bookings in BookingRequestDetailPage. - Enhanced BookingRequestsPage to display paired bookings in a single row. - Introduced pairedDecision method in bookings service to handle decisions for both halves of a consolidated pair. - Updated contracts service to include methods for manual consolidation of odd-20ft bookings. - Created new components for selecting and editing consolidation partners. - Added tests for paired decision logic and manual consolidation scenarios. - Updated UI to reflect changes in booking handling and provide user feedback for odd container counts.
161 lines
3.9 KiB
TypeScript
161 lines
3.9 KiB
TypeScript
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
import {
|
|
IsDateString,
|
|
IsIn,
|
|
IsInt,
|
|
IsOptional,
|
|
IsString,
|
|
IsUUID,
|
|
Max,
|
|
Min,
|
|
MinLength,
|
|
} from 'class-validator';
|
|
|
|
export class RequestChangesDto {
|
|
@ApiProperty({ description: 'Staff note explaining what the customer must fix' })
|
|
@IsString()
|
|
@MinLength(1)
|
|
note!: string;
|
|
}
|
|
|
|
export class AcceptIntakeDto {
|
|
@ApiProperty({
|
|
description:
|
|
'How many days the contract stays valid, counted from the accept date. ' +
|
|
'The contract is valid from now through now + validityDays.',
|
|
minimum: 1,
|
|
maximum: 365,
|
|
example: 30,
|
|
})
|
|
@IsInt()
|
|
@Min(1)
|
|
@Max(365)
|
|
validityDays!: number;
|
|
}
|
|
|
|
export class StaffRejectDto {
|
|
@ApiProperty()
|
|
@IsString()
|
|
@MinLength(1)
|
|
reason!: string;
|
|
}
|
|
|
|
export class ApproveStepDto {
|
|
@ApiProperty({ description: 'LINE_STAFF | DIRECTOR | CEO' })
|
|
@IsString()
|
|
requiredRole!: string;
|
|
}
|
|
|
|
export class RejectStepDto {
|
|
@ApiProperty()
|
|
@IsString()
|
|
@MinLength(1)
|
|
reason!: string;
|
|
}
|
|
|
|
export class CancelBookingDto {
|
|
@ApiProperty()
|
|
@IsString()
|
|
@MinLength(1)
|
|
reason!: string;
|
|
}
|
|
|
|
export class RejectBookingDto {
|
|
@ApiPropertyOptional({
|
|
description: 'Optional reason the customer rejected the price estimate',
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
reason?: string;
|
|
}
|
|
|
|
export class ReviewDocumentDto {
|
|
@ApiProperty({ description: 'The document fileKey being reviewed' })
|
|
@IsString()
|
|
@MinLength(1)
|
|
fileKey!: string;
|
|
|
|
@ApiProperty({ enum: ['APPROVED', 'QUERIED'] })
|
|
@IsIn(['APPROVED', 'QUERIED'])
|
|
status!: 'APPROVED' | 'QUERIED';
|
|
|
|
@ApiPropertyOptional({ description: 'Required when querying a document' })
|
|
@IsOptional()
|
|
@IsString()
|
|
note?: string;
|
|
}
|
|
|
|
export class RequestOperationDto {
|
|
@ApiProperty({
|
|
description:
|
|
'The schedule day (train departure day) the customer selects for this ' +
|
|
'shipment. ISO date — the booking enters the batch pool for this route + day.',
|
|
example: '2026-07-15',
|
|
})
|
|
@IsDateString()
|
|
scheduledDate!: string;
|
|
|
|
@ApiPropertyOptional({
|
|
description:
|
|
'EXPORT rail only: the specific train (schedule id) the customer picked ' +
|
|
'from GET /bookings/:id/export-trains. The reserve path locks onto this ' +
|
|
'train instead of earliest-first; 409 if it no longer fits. Ignored for ' +
|
|
'import/domestic/road bookings.',
|
|
})
|
|
@IsOptional()
|
|
@IsUUID()
|
|
trainScheduleId?: string;
|
|
}
|
|
|
|
export class OperationReviewDto {
|
|
@ApiProperty({
|
|
description:
|
|
'The operations decision: ACCEPT enters the batch pool; REQUEST_CHANGES ' +
|
|
'returns it to the customer with a note. The booking price is computed ' +
|
|
'from the contract and cannot be adjusted by staff.',
|
|
enum: ['ACCEPT', 'REQUEST_CHANGES'],
|
|
})
|
|
@IsIn(['ACCEPT', 'REQUEST_CHANGES'])
|
|
decision!: 'ACCEPT' | 'REQUEST_CHANGES';
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Required for REQUEST_CHANGES (what the customer must fix).',
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
note?: string;
|
|
}
|
|
|
|
/**
|
|
* A staff decision applied to BOTH halves of a consolidated pair. The two
|
|
* bookings share a wagon, so they advance or cancel together — never one alone.
|
|
*/
|
|
export class PairedDecisionDto {
|
|
@ApiProperty({
|
|
enum: ["accept", "cancel", "operationAccept", "requestChanges"],
|
|
description: 'Which staff decision to apply to both bookings.',
|
|
})
|
|
@IsIn(["accept", "cancel", "operationAccept", "requestChanges"])
|
|
decision!: "accept" | "cancel" | "operationAccept" | "requestChanges";
|
|
|
|
@ApiPropertyOptional({ description: "Cancellation reason (decision=cancel)." })
|
|
@IsOptional()
|
|
@IsString()
|
|
reason?: string;
|
|
|
|
@ApiPropertyOptional({
|
|
description: "Message to the customer (decision=requestChanges).",
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
note?: string;
|
|
|
|
@ApiPropertyOptional({
|
|
description: "Contract validity window in days (decision=accept).",
|
|
})
|
|
@IsOptional()
|
|
@IsInt()
|
|
@Min(1)
|
|
validityDays?: number;
|
|
}
|