/** * 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; } }