Line data Source code
1 :
2 : /// 구독 플랜 타입
3 : enum SubscriptionPlanType {
4 : free, // 무료 플랜
5 : basic, // 기본 유료 플랜
6 : premium, // 프리미엄 플랜
7 : enterprise // 기업용 플랜
8 : }
9 :
10 : /// 구독 상태
11 : enum SubscriptionStatus {
12 : active, // 활성화 상태
13 : canceled, // 취소됨 (아직 만료 안됨)
14 : expired, // 만료됨
15 : pending, // 결제 대기 중
16 : failed // 결제 실패
17 : }
18 :
19 : /// 구독 모델
20 : class Subscription {
21 : final String id;
22 : final String userId;
23 : final String? clubId;
24 : final SubscriptionPlanType planType;
25 : final SubscriptionStatus status;
26 : final DateTime startDate;
27 : final DateTime endDate;
28 : final double price;
29 : final String currency;
30 : final bool autoRenew;
31 : final Map<String, dynamic>? features;
32 : final String? paymentMethod;
33 : final String? transactionId;
34 : final DateTime createdAt;
35 : final DateTime updatedAt;
36 :
37 3 : Subscription({
38 : required this.id,
39 : required this.userId,
40 : this.clubId,
41 : required this.planType,
42 : required this.status,
43 : required this.startDate,
44 : required this.endDate,
45 : required this.price,
46 : required this.currency,
47 : required this.autoRenew,
48 : this.features,
49 : this.paymentMethod,
50 : this.transactionId,
51 : required this.createdAt,
52 : required this.updatedAt,
53 : });
54 :
55 : /// JSON에서 구독 객체 생성
56 3 : factory Subscription.fromJson(Map<String, dynamic> json) {
57 3 : return Subscription(
58 3 : id: json['id'],
59 3 : userId: json['userId'],
60 3 : clubId: json['clubId'],
61 3 : planType: SubscriptionPlanType.values.firstWhere(
62 18 : (e) => e.toString().split('.').last == json['planType'],
63 1 : orElse: () => SubscriptionPlanType.free,
64 : ),
65 3 : status: SubscriptionStatus.values.firstWhere(
66 18 : (e) => e.toString().split('.').last == json['status'],
67 1 : orElse: () => SubscriptionStatus.expired,
68 : ),
69 6 : startDate: DateTime.parse(json['startDate']),
70 6 : endDate: DateTime.parse(json['endDate']),
71 6 : price: json['price'].toDouble(),
72 3 : currency: json['currency'],
73 3 : autoRenew: json['autoRenew'] ?? false,
74 3 : features: json['features'],
75 3 : paymentMethod: json['paymentMethod'],
76 3 : transactionId: json['transactionId'],
77 6 : createdAt: DateTime.parse(json['createdAt']),
78 6 : updatedAt: DateTime.parse(json['updatedAt']),
79 : );
80 : }
81 :
82 : /// 구독 객체를 JSON으로 변환
83 1 : Map<String, dynamic> toJson() {
84 1 : return {
85 1 : 'id': id,
86 1 : 'userId': userId,
87 1 : 'clubId': clubId,
88 4 : 'planType': planType.toString().split('.').last,
89 4 : 'status': status.toString().split('.').last,
90 2 : 'startDate': startDate.toIso8601String(),
91 2 : 'endDate': endDate.toIso8601String(),
92 1 : 'price': price,
93 1 : 'currency': currency,
94 1 : 'autoRenew': autoRenew,
95 1 : 'features': features,
96 1 : 'paymentMethod': paymentMethod,
97 1 : 'transactionId': transactionId,
98 2 : 'createdAt': createdAt.toIso8601String(),
99 2 : 'updatedAt': updatedAt.toIso8601String(),
100 : };
101 : }
102 :
103 : /// 구독이 활성 상태인지 확인
104 3 : bool get isActive => status == SubscriptionStatus.active;
105 :
106 : /// 구독이 만료되었는지 확인
107 3 : bool get isExpired => status == SubscriptionStatus.expired ||
108 3 : DateTime.now().isAfter(endDate);
109 :
110 : /// 구독 남은 일수 계산
111 1 : int get daysLeft {
112 1 : if (isExpired) return 0;
113 4 : return endDate.difference(DateTime.now()).inDays;
114 : }
115 :
116 : /// 구독 플랜 이름 (한글)
117 1 : String get planName {
118 1 : switch (planType) {
119 1 : case SubscriptionPlanType.free:
120 : return '무료';
121 1 : case SubscriptionPlanType.basic:
122 : return '기본';
123 1 : case SubscriptionPlanType.premium:
124 : return '프리미엄';
125 1 : case SubscriptionPlanType.enterprise:
126 : return '기업용';
127 : }
128 : }
129 : }
130 :
131 : /// 구독 플랜 정보 모델
132 : class SubscriptionPlan {
133 : final SubscriptionPlanType type;
134 : final String name;
135 : final String description;
136 : final double monthlyPrice;
137 : final double yearlyPrice;
138 : final String currency;
139 : final List<String> features;
140 : final int maxMembers;
141 : final int maxEvents;
142 : final bool hasAdvancedStats;
143 : final bool hasCustomization;
144 : final bool hasPriority;
145 :
146 3 : SubscriptionPlan({
147 : required this.type,
148 : required this.name,
149 : required this.description,
150 : required this.monthlyPrice,
151 : required this.yearlyPrice,
152 : required this.currency,
153 : required this.features,
154 : required this.maxMembers,
155 : required this.maxEvents,
156 : required this.hasAdvancedStats,
157 : required this.hasCustomization,
158 : required this.hasPriority,
159 : });
160 :
161 : /// JSON에서 구독 플랜 객체 생성
162 1 : factory SubscriptionPlan.fromJson(Map<String, dynamic> json) {
163 1 : return SubscriptionPlan(
164 1 : type: SubscriptionPlanType.values.firstWhere(
165 6 : (e) => e.toString().split('.').last == json['type'],
166 1 : orElse: () => SubscriptionPlanType.free,
167 : ),
168 1 : name: json['name'],
169 1 : description: json['description'],
170 2 : monthlyPrice: json['monthlyPrice'].toDouble(),
171 2 : yearlyPrice: json['yearlyPrice'].toDouble(),
172 1 : currency: json['currency'],
173 2 : features: List<String>.from(json['features']),
174 1 : maxMembers: json['maxMembers'],
175 1 : maxEvents: json['maxEvents'],
176 1 : hasAdvancedStats: json['hasAdvancedStats'] ?? false,
177 1 : hasCustomization: json['hasCustomization'] ?? false,
178 1 : hasPriority: json['hasPriority'] ?? false,
179 : );
180 : }
181 :
182 : /// 구독 플랜 객체를 JSON으로 변환
183 1 : Map<String, dynamic> toJson() {
184 1 : return {
185 4 : 'type': type.toString().split('.').last,
186 1 : 'name': name,
187 1 : 'description': description,
188 1 : 'monthlyPrice': monthlyPrice,
189 1 : 'yearlyPrice': yearlyPrice,
190 1 : 'currency': currency,
191 1 : 'features': features,
192 1 : 'maxMembers': maxMembers,
193 1 : 'maxEvents': maxEvents,
194 1 : 'hasAdvancedStats': hasAdvancedStats,
195 1 : 'hasCustomization': hasCustomization,
196 1 : 'hasPriority': hasPriority,
197 : };
198 : }
199 :
200 : /// 기본 구독 플랜 목록 반환
201 3 : static List<SubscriptionPlan> getDefaultPlans() {
202 3 : return [
203 3 : SubscriptionPlan(
204 : type: SubscriptionPlanType.free,
205 : name: '무료',
206 : description: '소규모 클럽을 위한 기본 기능',
207 : monthlyPrice: 0,
208 : yearlyPrice: 0,
209 : currency: 'KRW',
210 3 : features: [
211 : '최대 10명 회원 관리',
212 : '기본 점수 기록',
213 : '간단한 통계',
214 : ],
215 : maxMembers: 10,
216 : maxEvents: 5,
217 : hasAdvancedStats: false,
218 : hasCustomization: false,
219 : hasPriority: false,
220 : ),
221 3 : SubscriptionPlan(
222 : type: SubscriptionPlanType.basic,
223 : name: '기본',
224 : description: '중소규모 클럽을 위한 확장 기능',
225 : monthlyPrice: 9900,
226 : yearlyPrice: 99000,
227 : currency: 'KRW',
228 3 : features: [
229 : '최대 30명 회원 관리',
230 : '상세 점수 분석',
231 : '이벤트 관리',
232 : '회원 통계',
233 : ],
234 : maxMembers: 30,
235 : maxEvents: 20,
236 : hasAdvancedStats: true,
237 : hasCustomization: false,
238 : hasPriority: false,
239 : ),
240 3 : SubscriptionPlan(
241 : type: SubscriptionPlanType.premium,
242 : name: '프리미엄',
243 : description: '대규모 클럽을 위한 고급 기능',
244 : monthlyPrice: 19900,
245 : yearlyPrice: 199000,
246 : currency: 'KRW',
247 3 : features: [
248 : '무제한 회원 관리',
249 : '고급 통계 및 분석',
250 : '무제한 이벤트',
251 : '맞춤형 보고서',
252 : '우선 지원',
253 : ],
254 : maxMembers: 100,
255 : maxEvents: 100,
256 : hasAdvancedStats: true,
257 : hasCustomization: true,
258 : hasPriority: true,
259 : ),
260 3 : SubscriptionPlan(
261 : type: SubscriptionPlanType.enterprise,
262 : name: '기업용',
263 : description: '프로 클럽 및 단체를 위한 맞춤형 솔루션',
264 : monthlyPrice: 49900,
265 : yearlyPrice: 499000,
266 : currency: 'KRW',
267 3 : features: [
268 : '무제한 회원 및 이벤트',
269 : '전문가 수준 분석',
270 : '맞춤형 기능',
271 : '전담 지원',
272 : 'API 액세스',
273 : ],
274 : maxMembers: 1000,
275 : maxEvents: 1000,
276 : hasAdvancedStats: true,
277 : hasCustomization: true,
278 : hasPriority: true,
279 : ),
280 : ];
281 : }
282 : }
|