mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-08 00:45:41 +00:00
216 lines
5.3 KiB
TypeScript
216 lines
5.3 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;
|
|
}
|
|
|
|
/**
|
|
* Operations changes a pending operation request's shipment day and/or train
|
|
* on the customer's behalf (instead of returning it for changes).
|
|
*/
|
|
export class RescheduleOperationDto {
|
|
@ApiProperty({
|
|
description:
|
|
'The new shipment day (train departure day). ISO date — must have an ' +
|
|
'open departure on the booking route that can carry the cargo.',
|
|
example: '2026-07-15',
|
|
})
|
|
@IsDateString()
|
|
scheduledDate!: string;
|
|
|
|
@ApiPropertyOptional({
|
|
description:
|
|
'EXPORT rail only: the train (schedule id) to ride, from ' +
|
|
'GET /bookings/:id/export-trains for the new day. Required for export ' +
|
|
'rail; ignored for import/domestic/road bookings.',
|
|
})
|
|
@IsOptional()
|
|
@IsUUID()
|
|
trainScheduleId?: string;
|
|
|
|
@ApiPropertyOptional({
|
|
description: 'Optional note to the customer explaining the change.',
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
note?: 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;
|
|
}
|
|
|
|
/** Approve a shared-wagon pairing. The note is optional context for the audit. */
|
|
export class ApproveConsolidationDto {
|
|
@ApiPropertyOptional({
|
|
description: "Optional note recorded with the approval.",
|
|
maxLength: 500,
|
|
})
|
|
@IsOptional()
|
|
@IsString()
|
|
note?: string;
|
|
}
|
|
|
|
/** Reject a shared-wagon pairing. A reason is mandatory — GL has to act on it. */
|
|
export class RejectConsolidationDto {
|
|
@ApiProperty({
|
|
description:
|
|
"Why the pairing is rejected. Sent back to GL on both bookings.",
|
|
maxLength: 500,
|
|
})
|
|
@IsString()
|
|
@MinLength(1)
|
|
reason!: string;
|
|
}
|