xpeditis2.0/apps/backend/src/domain/value-objects/surcharge.vo.ts
2025-10-27 20:54:01 +01:00

106 lines
2.6 KiB
TypeScript

import { Money } from './money.vo';
/**
* Surcharge Type Enumeration
* Common maritime shipping surcharges
*/
export enum SurchargeType {
BAF = 'BAF', // Bunker Adjustment Factor
CAF = 'CAF', // Currency Adjustment Factor
PSS = 'PSS', // Peak Season Surcharge
THC = 'THC', // Terminal Handling Charge
OTHER = 'OTHER',
}
/**
* Surcharge Value Object
* Represents additional fees applied to base freight rates
*/
export class Surcharge {
constructor(
public readonly type: SurchargeType,
public readonly amount: Money,
public readonly description?: string
) {
this.validate();
}
private validate(): void {
if (!Object.values(SurchargeType).includes(this.type)) {
throw new Error(`Invalid surcharge type: ${this.type}`);
}
}
/**
* Get human-readable surcharge label
*/
getLabel(): string {
const labels: Record<SurchargeType, string> = {
[SurchargeType.BAF]: 'Bunker Adjustment Factor',
[SurchargeType.CAF]: 'Currency Adjustment Factor',
[SurchargeType.PSS]: 'Peak Season Surcharge',
[SurchargeType.THC]: 'Terminal Handling Charge',
[SurchargeType.OTHER]: 'Other Surcharge',
};
return labels[this.type];
}
equals(other: Surcharge): boolean {
return this.type === other.type && this.amount.isEqualTo(other.amount);
}
toString(): string {
const label = this.description || this.getLabel();
return `${label}: ${this.amount.toString()}`;
}
}
/**
* Collection of surcharges with utility methods
*/
export class SurchargeCollection {
constructor(public readonly surcharges: Surcharge[]) {}
/**
* Calculate total surcharge amount in a specific currency
* Note: This assumes all surcharges are in the same currency
* In production, currency conversion would be needed
*/
getTotalAmount(currency: string): Money {
const relevantSurcharges = this.surcharges.filter(s => s.amount.getCurrency() === currency);
if (relevantSurcharges.length === 0) {
return Money.zero(currency);
}
return relevantSurcharges.reduce(
(total, surcharge) => total.add(surcharge.amount),
Money.zero(currency)
);
}
/**
* Check if collection has any surcharges
*/
isEmpty(): boolean {
return this.surcharges.length === 0;
}
/**
* Get surcharges by type
*/
getByType(type: SurchargeType): Surcharge[] {
return this.surcharges.filter(s => s.type === type);
}
/**
* Get formatted surcharge details for display
*/
getDetails(): string {
if (this.isEmpty()) {
return 'All-in price (no separate surcharges)';
}
return this.surcharges.map(s => s.toString()).join(', ');
}
}