src/lanes/dto/create-tariff.dto.ts
A lane tariff. Every monetary field must be > 0 so an admin cannot accidentally save a negative rate that would invert revenue.
At least ONE of the rate fields (ratePerTrip / ratePerKm / ratePerTon) must be set — otherwise the tariff has no economic meaning.
effectiveTo, when present, must be strictly after effectiveFrom.
The cross-field check is enforced in the service layer because
class-validator does not have a clean built-in for date ordering.
Properties |
|
| Optional currency |
Type : string
|
Decorators :
@ApiPropertyOptional({example: 'KES', description: 'ISO-4217 currency code'})
|
|
Defined in src/lanes/dto/create-tariff.dto.ts:69
|
| effectiveFrom |
Type : string
|
Decorators :
@ApiProperty({example: '2026-01-01T00:00:00Z'})
|
|
Defined in src/lanes/dto/create-tariff.dto.ts:73
|
| Optional effectiveTo |
Type : string
|
Decorators :
@ApiPropertyOptional({example: '2026-12-31T23:59:59Z'})
|
|
Defined in src/lanes/dto/create-tariff.dto.ts:81
|
| Optional minCharge |
Type : number
|
Decorators :
@ApiPropertyOptional({example: 15000, description: 'Minimum charge regardless of distance/weight'})
|
|
Defined in src/lanes/dto/create-tariff.dto.ts:63
|
| Optional ratePerKm |
Type : number
|
Decorators :
@ApiPropertyOptional({example: 120, description: 'Variable rate per km'})
|
|
Defined in src/lanes/dto/create-tariff.dto.ts:47
|
| Optional ratePerTon |
Type : number
|
Decorators :
@ApiPropertyOptional({example: 3500, description: 'Variable rate per ton'})
|
|
Defined in src/lanes/dto/create-tariff.dto.ts:55
|
| Optional ratePerTrip |
Type : number
|
Decorators :
@ApiPropertyOptional({example: 50000, description: 'Flat rate per trip'})
|
|
Defined in src/lanes/dto/create-tariff.dto.ts:39
|
| Optional vehicleType |
Type : VehicleType
|
Decorators :
@ApiPropertyOptional({enum: VehicleType})
|
|
Defined in src/lanes/dto/create-tariff.dto.ts:31
|
import {
IsOptional,
IsNumber,
IsString,
IsEnum,
IsDateString,
IsPositive,
Max,
Length,
ValidateIf,
} from 'class-validator';
import { Type } from 'class-transformer';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { VehicleType } from '@prisma/client';
/**
* A lane tariff. Every monetary field must be > 0 so an admin cannot
* accidentally save a negative rate that would invert revenue.
*
* At least ONE of the rate fields (ratePerTrip / ratePerKm / ratePerTon)
* must be set — otherwise the tariff has no economic meaning.
*
* `effectiveTo`, when present, must be strictly after `effectiveFrom`.
* The cross-field check is enforced in the service layer because
* class-validator does not have a clean built-in for date ordering.
*/
export class CreateTariffDto {
@ApiPropertyOptional({ enum: VehicleType })
@IsOptional()
@IsEnum(VehicleType)
vehicleType?: VehicleType;
@ApiPropertyOptional({ example: 50000, description: 'Flat rate per trip' })
@IsOptional()
@Type(() => Number)
@IsNumber({ maxDecimalPlaces: 4 })
@IsPositive({ message: 'ratePerTrip must be greater than 0' })
@Max(100_000_000, { message: 'ratePerTrip is unrealistically large' })
ratePerTrip?: number;
@ApiPropertyOptional({ example: 120, description: 'Variable rate per km' })
@IsOptional()
@Type(() => Number)
@IsNumber({ maxDecimalPlaces: 4 })
@IsPositive({ message: 'ratePerKm must be greater than 0' })
@Max(1_000_000, { message: 'ratePerKm is unrealistically large' })
ratePerKm?: number;
@ApiPropertyOptional({ example: 3500, description: 'Variable rate per ton' })
@IsOptional()
@Type(() => Number)
@IsNumber({ maxDecimalPlaces: 4 })
@IsPositive({ message: 'ratePerTon must be greater than 0' })
@Max(10_000_000, { message: 'ratePerTon is unrealistically large' })
ratePerTon?: number;
@ApiPropertyOptional({ example: 15000, description: 'Minimum charge regardless of distance/weight' })
@IsOptional()
@Type(() => Number)
@IsNumber({ maxDecimalPlaces: 4 })
@IsPositive({ message: 'minCharge must be greater than 0' })
@Max(100_000_000, { message: 'minCharge is unrealistically large' })
minCharge?: number;
@ApiPropertyOptional({ example: 'KES', description: 'ISO-4217 currency code' })
@IsOptional()
@IsString()
@Length(3, 3, { message: 'currency must be a 3-letter ISO 4217 code' })
currency?: string;
@ApiProperty({ example: '2026-01-01T00:00:00Z' })
@IsDateString({}, { message: 'effectiveFrom must be a valid ISO date' })
effectiveFrom: string;
@ApiPropertyOptional({ example: '2026-12-31T23:59:59Z' })
@IsOptional()
@IsDateString({}, { message: 'effectiveTo must be a valid ISO date' })
// Class-validator can't compare two dates declaratively without a custom
// decorator; the service layer does the strict ordering check.
@ValidateIf((o) => !!o.effectiveTo)
effectiveTo?: string;
}