xpeditis2.0/apps/backend/src/domain/entities/carrier.entity.ts
2025-10-27 20:54:01 +01:00

185 lines
4.0 KiB
TypeScript

/**
* Carrier Entity
*
* Represents a shipping carrier (e.g., Maersk, MSC, CMA CGM)
*
* Business Rules:
* - Carrier code must be unique
* - SCAC code must be valid (4 uppercase letters)
* - API configuration is optional (for carriers with API integration)
*/
export interface CarrierApiConfig {
baseUrl: string;
apiKey?: string;
clientId?: string;
clientSecret?: string;
timeout: number; // in milliseconds
retryAttempts: number;
circuitBreakerThreshold: number;
}
export interface CarrierProps {
id: string;
name: string;
code: string; // Unique carrier code (e.g., 'MAERSK', 'MSC')
scac: string; // Standard Carrier Alpha Code
logoUrl?: string;
website?: string;
apiConfig?: CarrierApiConfig;
isActive: boolean;
supportsApi: boolean; // True if carrier has API integration
createdAt: Date;
updatedAt: Date;
}
export class Carrier {
private readonly props: CarrierProps;
private constructor(props: CarrierProps) {
this.props = props;
}
/**
* Factory method to create a new Carrier
*/
static create(props: Omit<CarrierProps, 'createdAt' | 'updatedAt'>): Carrier {
const now = new Date();
// Validate SCAC code
if (!Carrier.isValidSCAC(props.scac)) {
throw new Error('Invalid SCAC code format. Must be 4 uppercase letters.');
}
// Validate carrier code
if (!Carrier.isValidCarrierCode(props.code)) {
throw new Error(
'Invalid carrier code format. Must be uppercase letters and underscores only.'
);
}
// Validate API config if carrier supports API
if (props.supportsApi && !props.apiConfig) {
throw new Error('Carriers with API support must have API configuration.');
}
return new Carrier({
...props,
createdAt: now,
updatedAt: now,
});
}
/**
* Factory method to reconstitute from persistence
*/
static fromPersistence(props: CarrierProps): Carrier {
return new Carrier(props);
}
/**
* Validate SCAC code format
*/
private static isValidSCAC(scac: string): boolean {
const scacPattern = /^[A-Z]{4}$/;
return scacPattern.test(scac);
}
/**
* Validate carrier code format
*/
private static isValidCarrierCode(code: string): boolean {
const codePattern = /^[A-Z_]+$/;
return codePattern.test(code);
}
// Getters
get id(): string {
return this.props.id;
}
get name(): string {
return this.props.name;
}
get code(): string {
return this.props.code;
}
get scac(): string {
return this.props.scac;
}
get logoUrl(): string | undefined {
return this.props.logoUrl;
}
get website(): string | undefined {
return this.props.website;
}
get apiConfig(): CarrierApiConfig | undefined {
return this.props.apiConfig ? { ...this.props.apiConfig } : undefined;
}
get isActive(): boolean {
return this.props.isActive;
}
get supportsApi(): boolean {
return this.props.supportsApi;
}
get createdAt(): Date {
return this.props.createdAt;
}
get updatedAt(): Date {
return this.props.updatedAt;
}
// Business methods
hasApiIntegration(): boolean {
return this.props.supportsApi && !!this.props.apiConfig;
}
updateApiConfig(apiConfig: CarrierApiConfig): void {
if (!this.props.supportsApi) {
throw new Error('Cannot update API config for carrier without API support.');
}
this.props.apiConfig = { ...apiConfig };
this.props.updatedAt = new Date();
}
updateLogoUrl(logoUrl: string): void {
this.props.logoUrl = logoUrl;
this.props.updatedAt = new Date();
}
updateWebsite(website: string): void {
this.props.website = website;
this.props.updatedAt = new Date();
}
deactivate(): void {
this.props.isActive = false;
this.props.updatedAt = new Date();
}
activate(): void {
this.props.isActive = true;
this.props.updatedAt = new Date();
}
/**
* Convert to plain object for persistence
*/
toObject(): CarrierProps {
return {
...this.props,
apiConfig: this.props.apiConfig ? { ...this.props.apiConfig } : undefined,
};
}
}