xpeditis2.0/apps/backend/src/domain/value-objects/booking-number.vo.ts
2025-10-20 12:30:08 +02:00

78 lines
1.8 KiB
TypeScript

/**
* BookingNumber Value Object
*
* Represents a unique booking reference number
* Format: WCM-YYYY-XXXXXX (e.g., WCM-2025-ABC123)
* - WCM: WebCargo Maritime prefix
* - YYYY: Current year
* - XXXXXX: 6 alphanumeric characters
*/
import { InvalidBookingNumberException } from '../exceptions/invalid-booking-number.exception';
export class BookingNumber {
private readonly _value: string;
private constructor(value: string) {
this._value = value;
}
get value(): string {
return this._value;
}
/**
* Generate a new booking number
*/
static generate(): BookingNumber {
const year = new Date().getFullYear();
const random = BookingNumber.generateRandomString(6);
const value = `WCM-${year}-${random}`;
return new BookingNumber(value);
}
/**
* Create BookingNumber from string
*/
static fromString(value: string): BookingNumber {
if (!BookingNumber.isValid(value)) {
throw new InvalidBookingNumberException(value);
}
return new BookingNumber(value);
}
/**
* Validate booking number format
*/
static isValid(value: string): boolean {
const pattern = /^WCM-\d{4}-[A-Z0-9]{6}$/;
return pattern.test(value);
}
/**
* Generate random alphanumeric string
*/
private static generateRandomString(length: number): string {
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // Exclude ambiguous chars: 0,O,1,I
let result = '';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
/**
* Equality check
*/
equals(other: BookingNumber): boolean {
return this._value === other._value;
}
/**
* String representation
*/
toString(): string {
return this._value;
}
}