mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-08 22:58:17 +00:00
feat: enhance booking flow with multi-route support and onboarding document integration
- Introduced multi-route functionality in the booking process, allowing users to add additional routes for general contracts. - Updated the StepDocuments component to display onboarding documents automatically attached to bookings. - Refactored Step4Route to manage extra routes and quantities dynamically. - Improved Step8Review to reflect the new onboarding document handling and updated submission readiness checks. - Added new API endpoints and services for managing contract route lines and rejecting bookings. - Removed the allowConsolidation field from the booking model as it is now managed by the system. - Created migrations for the new contract route lines table and updated related entities.
This commit is contained in:
@@ -53,6 +53,30 @@ export class CreateBookingContainerDto {
|
||||
vgmPerUnitTons!: number;
|
||||
}
|
||||
|
||||
export class CreateContractRouteDto {
|
||||
@ApiProperty({ format: 'uuid', description: 'FK to yards.id (origin)' })
|
||||
@IsUUID()
|
||||
originYardId!: string;
|
||||
|
||||
@ApiProperty({ format: 'uuid', description: 'FK to yards.id (destination)' })
|
||||
@IsUUID()
|
||||
destinationYardId!: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
format: 'uuid',
|
||||
description: 'Container type for CONTAINER contracts; omit for BULK',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsUUID()
|
||||
containerTypeId?: string;
|
||||
|
||||
@ApiProperty({ description: 'Contracted quantity for this route', minimum: 1 })
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@Transform(({ value }) => Number(value))
|
||||
quantity!: number;
|
||||
}
|
||||
|
||||
export class CreateBookingDto {
|
||||
/** Class-level freight shape check (not a request field). */
|
||||
@Validate(BookingFreightShapeConstraint)
|
||||
@@ -161,6 +185,21 @@ export class CreateBookingDto {
|
||||
@IsUUID()
|
||||
destinationYardId!: string;
|
||||
|
||||
/**
|
||||
* GENERAL_CONTRACT only: the routes this contract reserves quantity across.
|
||||
* Each entry has its own origin/destination and quantity; the first entry also
|
||||
* matches the booking's originYardId/destinationYardId. Omitted for one-time
|
||||
* bookings, which use the single origin/destination above.
|
||||
*/
|
||||
@ApiPropertyOptional({ type: [CreateContractRouteDto] })
|
||||
@ValidateIf((o) => o.bookingType === 'GENERAL_CONTRACT')
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@ArrayMinSize(1)
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateContractRouteDto)
|
||||
routes?: CreateContractRouteDto[];
|
||||
|
||||
@ApiProperty({ enum: TRADE_DIRECTIONS })
|
||||
@IsIn([...TRADE_DIRECTIONS])
|
||||
tradeDirection!: string;
|
||||
@@ -233,10 +272,4 @@ export class CreateBookingDto {
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreateBookingContainerDto)
|
||||
containers?: CreateBookingContainerDto[];
|
||||
|
||||
@ApiPropertyOptional({ default: false })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Transform(({ value }) => value === 'true' || value === true)
|
||||
allowConsolidation?: boolean;
|
||||
}
|
||||
|
||||
@@ -96,11 +96,6 @@ export class FilterBookingDto {
|
||||
@IsIn([...PAYMENT_STATUSES])
|
||||
paymentStatus?: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => value === 'true' || value === true)
|
||||
allowConsolidation?: boolean;
|
||||
|
||||
@ApiPropertyOptional({ description: 'true | false — filter paired consolidation' })
|
||||
@IsOptional()
|
||||
consolidationPaired?: string;
|
||||
|
||||
@@ -7,9 +7,22 @@ export class PriceLineItemDto {
|
||||
@ApiProperty()
|
||||
description!: string;
|
||||
|
||||
/** Computed line total (unitAmount × quantity). Retained for totals elsewhere. */
|
||||
@ApiProperty()
|
||||
amount!: number;
|
||||
|
||||
/** Price for a single unit of this charge (e.g. one 20ft container, one ton). */
|
||||
@ApiProperty()
|
||||
unitAmount!: number;
|
||||
|
||||
/** Unit the rate is charged per: PER_CONTAINER | PER_TON | PER_WAGON | PER_KM | FLAT. */
|
||||
@ApiProperty()
|
||||
unit!: string;
|
||||
|
||||
/** How many units this charge applies to (containers, tons, wagons; 1 for FLAT). */
|
||||
@ApiProperty()
|
||||
quantity!: number;
|
||||
|
||||
@ApiProperty()
|
||||
currency!: string;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, MinLength } from 'class-validator';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { IsOptional, IsString, MinLength } from 'class-validator';
|
||||
|
||||
export class RequestChangesDto {
|
||||
@ApiProperty({ description: 'Staff note explaining what the customer must fix' })
|
||||
@@ -34,3 +34,12 @@ export class CancelBookingDto {
|
||||
@MinLength(1)
|
||||
reason!: string;
|
||||
}
|
||||
|
||||
export class RejectBookingDto {
|
||||
@ApiPropertyOptional({
|
||||
description: 'Optional reason the customer rejected the price estimate',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user