/** * Refund policy hardcoded untuk MVP (PR-R3). Akan jadi data-driven di PR-R5. * * Aturan: hitung persentase refund berdasarkan jarak hari ke tanggal berangkat * (UTC calendar day). Selalu integer rupiah — pakai Math.floor supaya tidak * ada sub-rupiah dan total refund tidak pernah melebihi nominal yang dibayar. * * Tier: * - ≥7 hari sebelum berangkat → 80% refund (organizer ambil 20% admin fee) * - 3–6 hari sebelum berangkat → 50% refund * - <3 hari sebelum berangkat / sudah lewat → 0% (tidak ada refund) */ import { utcStartOfDay } from "@/lib/trip-dates"; export interface RefundTier { /** Minimum jumlah hari sebelum berangkat untuk tier ini. */ minDaysBefore: number; /** Persentase nominal yang di-refund (0–100). */ refundPercentage: number; /** Label untuk UI. */ label: string; } const TIERS: RefundTier[] = [ { minDaysBefore: 7, refundPercentage: 80, label: "≥ 7 hari sebelum berangkat" }, { minDaysBefore: 3, refundPercentage: 50, label: "3–6 hari sebelum berangkat" }, { minDaysBefore: 0, refundPercentage: 0, label: "Kurang dari 3 hari / sudah lewat" }, ]; export function getRefundPolicyTiers(): RefundTier[] { return TIERS; } /** * Jumlah hari kalender UTC dari sekarang ke tanggal berangkat. Negative kalau * tanggal sudah lewat. Pakai start-of-day UTC supaya jam tidak mempengaruhi. */ export function daysUntilDeparture( departureDate: Date, now: Date = new Date() ): number { const todayMs = utcStartOfDay(now).getTime(); const depMs = utcStartOfDay(departureDate).getTime(); const oneDayMs = 24 * 60 * 60 * 1000; return Math.floor((depMs - todayMs) / oneDayMs); } /** Tier aktif untuk jumlah hari yang diberikan. */ export function getTierForDays(days: number): RefundTier { for (const tier of TIERS) { if (days >= tier.minDaysBefore) { return tier; } } return TIERS[TIERS.length - 1]; } /** * Hitung nominal refund (IDR integer) berdasarkan harga booking dan jarak ke * tanggal berangkat. Floor supaya tidak pernah > bookingAmount. */ export function calculateRefundAmount( bookingAmount: number, days: number ): number { if (bookingAmount <= 0) return 0; const tier = getTierForDays(days); return Math.floor((bookingAmount * tier.refundPercentage) / 100); } export interface RefundPreview { days: number; tier: RefundTier; refundAmount: number; bookingAmount: number; } /** Bundle lengkap untuk display di UI — preview cancel booking. */ export function previewRefund( bookingAmount: number, departureDate: Date, now: Date = new Date() ): RefundPreview { const days = daysUntilDeparture(departureDate, now); const tier = getTierForDays(days); return { days, tier, refundAmount: calculateRefundAmount(bookingAmount, days), bookingAmount, }; }