feat(bookings): add ad-hoc additional-charge module

New freight.additional_charge table, independent of BookingClearanceCharge
(unbounded per booking, free-text reason). Draft -> send issues an invoice
and notifies the customer in-app/SMS/email; settles via the standard
.invoice.paid event. Adds the Additional charges row-menu entry
next to Cancel booking, permission-gated.

Not included: the Additional Payments tab UI, add-charge modal, portal pay
flow.
This commit is contained in:
Hagernesh
2026-08-20 12:35:19 +00:00
parent 8e2bab27cf
commit 0ceb595714
12 changed files with 622 additions and 1 deletions

View File

@@ -0,0 +1,35 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { IsIn, IsNumber, IsOptional, IsPositive, IsString, Length } from 'class-validator';
export class CreateAdditionalChargeDto {
@ApiProperty({ example: 'Re-weighing fee at Mojo dry port' })
@IsString()
@Length(1, 2000)
reason!: string;
@ApiProperty({ example: 4500 })
@Type(() => Number)
@IsNumber()
@IsPositive()
amount!: number;
@ApiProperty({ example: 'ETB' })
@IsString()
@Length(3, 8)
currency!: string;
/** 'send' issues the invoice + notifies the customer immediately; omit/'draft' just saves it. */
@ApiPropertyOptional({ enum: ['draft', 'send'], default: 'draft' })
@IsOptional()
@IsIn(['draft', 'send'])
action?: 'draft' | 'send';
}
export class CancelAdditionalChargeDto {
@ApiPropertyOptional({ example: 'Raised in error' })
@IsOptional()
@IsString()
@Length(1, 2000)
reason?: string;
}