truck type detantion

This commit is contained in:
Hagernesh
2026-07-07 10:02:43 +00:00
parent 48b36a2621
commit 35ccf1bc95
8 changed files with 228 additions and 41 deletions

View File

@@ -154,7 +154,37 @@ export function TruckDetentionModal({ opened, onClose, record }: TruckDetentionM
Still accruing no delivery/return time yet. The amount grows until the vehicle is returned.
</Text>
)}
{preview.tiers && preview.tiers.length > 0 ? (
{preview.groups && preview.groups.length > 1 ? (
<Table withTableBorder withColumnBorders verticalSpacing="xs" fz="xs">
<Table.Thead>
<Table.Tr>
<Table.Th>Truck type</Table.Th>
<Table.Th>Trucks</Table.Th>
<Table.Th>Days</Table.Th>
<Table.Th ta="right">Rate / truck / day</Table.Th>
<Table.Th ta="right">Amount</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{preview.groups.map((g, i) => (
<Table.Tr key={i}>
<Table.Td>
{g.vehicleType ?? 'Unknown'}
{!g.ruleId && (
<Text span size="xs" c="red">
{' '}· no rule
</Text>
)}
</Table.Td>
<Table.Td>{g.truckCount}</Table.Td>
<Table.Td>{g.chargeableDays}</Table.Td>
<Table.Td ta="right">{money(g.ratePerDay, preview.currency)}</Table.Td>
<Table.Td ta="right">{money(g.amount, preview.currency)}</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
) : preview.tiers && preview.tiers.length > 0 ? (
<Table withTableBorder withColumnBorders verticalSpacing="xs" fz="xs">
<Table.Thead>
<Table.Tr>

View File

@@ -37,6 +37,7 @@ import {
FEE_RULE_BASIS_LABELS,
FEE_RULE_TYPES,
FEE_RULE_TYPE_LABELS,
VEHICLE_TYPES,
type FeeRuleBasis,
type FeeRuleType,
} from '@/types/warehouse';
@@ -372,6 +373,7 @@ function FeeRules() {
tradeDirection: '',
cargoTypeCode: '',
containerType: '',
vehicleType: '',
freeDays: 3,
freeHours: 3,
ratePerDay: 0,
@@ -399,6 +401,7 @@ function FeeRules() {
tradeDirection: '',
cargoTypeCode: '',
containerType: '',
vehicleType: '',
freeDays: 3,
freeHours: 3,
ratePerDay: 0,
@@ -469,7 +472,7 @@ function FeeRules() {
ratePerDay: form.ratePerDay,
currency: form.currency || 'USD',
...(isDoubleHandling ? { basis: form.basis } : {}),
...(isTruckDetention ? { freeHours: form.freeHours } : {}),
...(isTruckDetention ? { freeHours: form.freeHours, vehicleType: clean(form.vehicleType) ?? null } : {}),
...(!isDoubleHandling && tiers.length ? { tiers } : {}),
};
@@ -638,6 +641,16 @@ function FeeRules() {
onChange={(value) => setForm((f) => ({ ...f, tradeDirection: selectValue(value) }))}
clearable
/>
{isTruckDetention && (
<Select
label="Truck type"
placeholder="Any truck type"
data={VEHICLE_TYPES.map((v) => ({ value: v, label: v.charAt(0) + v.slice(1).toLowerCase() }))}
value={form.vehicleType || null}
onChange={(value) => setForm((f) => ({ ...f, vehicleType: selectValue(value) }))}
clearable
/>
)}
{isBulkRule && (
<Select
label="Cargo type"

View File

@@ -763,6 +763,10 @@ export const FEE_RULE_BASIS_LABELS: Record<FeeRuleBasis, string> = {
PER_ITEM: 'Per Item',
};
/** Vehicle types a Truck Detention rule can be scoped to (rates differ by truck type). */
export const VEHICLE_TYPES = ['TRUCK', 'VAN', 'CAR', 'BUS', 'TRAILER', 'TANKER', 'FLATBED'] as const;
export type VehicleTypeCode = (typeof VEHICLE_TYPES)[number];
export interface FeeRule {
id: string;
name: string;
@@ -774,6 +778,8 @@ export interface FeeRule {
tradeDirection?: string | null;
cargoTypeCode?: string | null;
containerType?: string | null;
/** Truck detention only: scope by vehicle type (null = any). */
vehicleType?: string | null;
facilityId?: string | null;
warehouseId?: string | null;
yardId?: string | null;
@@ -820,6 +826,16 @@ export interface FeePreview {
billableUnits: number;
amount: number;
tiers?: FeePreviewTier[];
/** Truck detention: per-vehicle-type breakdown. */
groups?: Array<{
vehicleType: string | null;
truckCount: number;
chargeableDays: number;
ratePerDay: number;
amount: number;
ruleId: string | null;
ruleName: string | null;
}>;
}
export interface AllocationPreviewResult {