/// 결제 주기에 따른 비용 변환 유틸리티 class BillingCostUtil { /// 결제 주기별 비용을 월 비용으로 변환 /// /// [amount]: 입력된 비용 /// [billingCycle]: 결제 주기 ('monthly', 'yearly', 'quarterly', 'half-yearly' 등) /// /// Returns: 월 환산 비용 static double convertToMonthlyCost(double amount, String billingCycle) { final normalizedCycle = _normalizeBillingCycle(billingCycle); switch (normalizedCycle) { case 'monthly': return amount; case 'yearly': return amount / 12; case 'quarterly': return amount / 3; case 'half-yearly': return amount / 6; case 'weekly': return amount * 4.33; // 평균 주당 4.33주 default: return amount; // 알 수 없는 주기는 그대로 반환 } } /// 월 비용을 결제 주기별 비용으로 역변환 /// /// [monthlyCost]: 월 비용 /// [billingCycle]: 결제 주기 /// /// Returns: 해당 주기의 실제 결제 금액 static double convertFromMonthlyCost(double monthlyCost, String billingCycle) { final normalizedCycle = _normalizeBillingCycle(billingCycle); switch (normalizedCycle) { case 'monthly': return monthlyCost; case 'yearly': return monthlyCost * 12; case 'quarterly': return monthlyCost * 3; case 'half-yearly': return monthlyCost * 6; case 'weekly': return monthlyCost / 4.33; default: return monthlyCost; } } /// 결제 주기를 정규화된 영어 키값으로 변환 static String _normalizeBillingCycle(String cycle) { switch (cycle.toLowerCase()) { case 'monthly': case '월간': case '매월': case '月間': case '月付': case '每月': case '毎月': return 'monthly'; case 'yearly': case 'annual': case 'annually': case '연간': case '매년': case '年間': case '年付': case '每年': return 'yearly'; case 'quarterly': case 'quarter': case '분기별': case '분기': case '季付': case '季度付': case '四半期': case '每季度': return 'quarterly'; case 'half-yearly': case 'half yearly': case 'semiannual': case 'semi-annual': case '반기별': case '半年付': case '半年払い': case '半年ごと': case '每半年': return 'half-yearly'; case 'weekly': case '주간': case '週間': case '周付': case '每周': return 'weekly'; default: return 'monthly'; } } /// 결제 주기의 배수 반환 (월 기준) /// /// 예: yearly = 12, quarterly = 3 static double getBillingCycleMultiplier(String billingCycle) { final normalizedCycle = _normalizeBillingCycle(billingCycle); switch (normalizedCycle) { case 'monthly': return 1.0; case 'yearly': return 12.0; case 'quarterly': return 3.0; case 'half-yearly': return 6.0; case 'weekly': return 1 / 4.33; default: return 1.0; } } /// 다음 결제일에서 이전 결제일 계산 /// /// [nextBillingDate]: 다음 결제 예정일 /// [billingCycle]: 결제 주기 /// /// Returns: 이전 결제일 (마지막으로 결제가 발생한 날짜) static DateTime getLastBillingDate( DateTime nextBillingDate, String billingCycle) { final normalizedCycle = _normalizeBillingCycle(billingCycle); switch (normalizedCycle) { case 'yearly': return DateTime( nextBillingDate.year - 1, nextBillingDate.month, nextBillingDate.day, ); case 'half-yearly': return DateTime( nextBillingDate.month <= 6 ? nextBillingDate.year - 1 : nextBillingDate.year, nextBillingDate.month <= 6 ? nextBillingDate.month + 6 : nextBillingDate.month - 6, nextBillingDate.day, ); case 'quarterly': return DateTime( nextBillingDate.month <= 3 ? nextBillingDate.year - 1 : nextBillingDate.year, nextBillingDate.month <= 3 ? nextBillingDate.month + 9 : nextBillingDate.month - 3, nextBillingDate.day, ); case 'monthly': return DateTime( nextBillingDate.month == 1 ? nextBillingDate.year - 1 : nextBillingDate.year, nextBillingDate.month == 1 ? 12 : nextBillingDate.month - 1, nextBillingDate.day, ); case 'weekly': return nextBillingDate.subtract(const Duration(days: 7)); default: return DateTime( nextBillingDate.month == 1 ? nextBillingDate.year - 1 : nextBillingDate.year, nextBillingDate.month == 1 ? 12 : nextBillingDate.month - 1, nextBillingDate.day, ); } } /// 특정 월에 결제가 발생하는지 확인 /// /// [nextBillingDate]: 다음 결제 예정일 /// [billingCycle]: 결제 주기 /// [targetYear]: 확인할 연도 /// [targetMonth]: 확인할 월 (1-12) /// /// Returns: 해당 월에 결제가 발생하면 true static bool hasBillingInMonth( DateTime nextBillingDate, String billingCycle, int targetYear, int targetMonth, ) { final normalizedCycle = _normalizeBillingCycle(billingCycle); // 주간 결제는 매주 발생하므로 항상 true if (normalizedCycle == 'weekly') { return true; } // 월간 결제는 매월 발생하므로 항상 true if (normalizedCycle == 'monthly') { return true; } // 결제 주기에 따른 개월 수 final cycleMonths = _getCycleMonths(normalizedCycle); // 결제 발생 월 계산 (nextBillingDate 기준으로 역산) final billingMonth = nextBillingDate.month; // 대상 월이 결제 발생 월과 일치하는지 확인 // 예: 연간 결제(1월), targetMonth = 1 → true // 예: 연간 결제(1월), targetMonth = 2 → false for (int i = 0; i < 12; i += cycleMonths) { final checkMonth = ((billingMonth - 1 + i) % 12) + 1; if (checkMonth == targetMonth) { return true; } } return false; } /// 결제 주기별 개월 수 반환 static int _getCycleMonths(String normalizedCycle) { switch (normalizedCycle) { case 'yearly': return 12; case 'half-yearly': return 6; case 'quarterly': return 3; case 'monthly': return 1; default: return 1; } } }