interface PriceConfig { basePrice: number; kmFlatRate: number; kmFlatRateUpTo: number; pricePerKm: number; kmMultiplier: number; } interface PriceBreakdown { basePrice: number; kmFlatRate: number; kmAdditionalNet: number; kmAdditionalGross: number; kmTotalGross: number; totalPrice: number; distance?: number; } export class PriceCalculator { private static readonly VAT_RATE = 1.19; static calculateKmCharge( distance: number, config: PriceConfig ): { kmTotalGross: number; kmFlatRate: number; kmAdditionalNet: number; kmAdditionalGross: number; } { const { kmFlatRate, kmFlatRateUpTo, pricePerKm, kmMultiplier } = config; if (distance <= kmFlatRateUpTo) { return { kmTotalGross: kmFlatRate, kmFlatRate: kmFlatRate, kmAdditionalNet: 0, kmAdditionalGross: 0, }; } const extraKm = distance - kmFlatRateUpTo; const kmAdditionalNet = extraKm * kmMultiplier * pricePerKm; const kmAdditionalGross = Math.round(kmAdditionalNet * this.VAT_RATE * 100) / 100; const kmTotalGross = Math.round((kmFlatRate + kmAdditionalGross) * 100) / 100; return { kmTotalGross, kmFlatRate, kmAdditionalNet: Math.round(kmAdditionalNet * 100) / 100, kmAdditionalGross, }; } static calculateTotalPrice( basePrice: number, distance: number | null | undefined, config: PriceConfig ): PriceBreakdown { if (!distance || distance <= 0) { return { basePrice, kmFlatRate: 0, kmAdditionalNet: 0, kmAdditionalGross: 0, kmTotalGross: 0, totalPrice: basePrice, }; } const kmCharge = this.calculateKmCharge(distance, config); const totalPrice = Math.round((basePrice + kmCharge.kmTotalGross) * 100) / 100; return { basePrice, kmFlatRate: kmCharge.kmFlatRate, kmAdditionalNet: kmCharge.kmAdditionalNet, kmAdditionalGross: kmCharge.kmAdditionalGross, kmTotalGross: kmCharge.kmTotalGross, totalPrice, distance, }; } static formatPriceBreakdown(breakdown: PriceBreakdown): string { const lines = [ `Grundpreis Fotobox: ${breakdown.basePrice.toFixed(2)}€`, ]; if (breakdown.distance && breakdown.distance > 0) { lines.push(`\nKilometerpauschale (${breakdown.distance.toFixed(1)}km):`); if (breakdown.kmFlatRate > 0) { lines.push(` - Pauschale: ${breakdown.kmFlatRate.toFixed(2)}€`); } if (breakdown.kmAdditionalGross > 0) { lines.push(` - Zusätzlich: ${breakdown.kmAdditionalGross.toFixed(2)}€`); } lines.push(` = Gesamt KM: ${breakdown.kmTotalGross.toFixed(2)}€`); } lines.push(`\nGesamtpreis: ${breakdown.totalPrice.toFixed(2)}€`); return lines.join('\n'); } }