109 lines
3.0 KiB
Dart
109 lines
3.0 KiB
Dart
import 'package:please_pay_me/data/models/json.dart';
|
|
|
|
class Budget {
|
|
const Budget({
|
|
required this.id,
|
|
required this.userId,
|
|
required this.name,
|
|
required this.totalAmount,
|
|
required this.startDate,
|
|
required this.endDate,
|
|
required this.currency,
|
|
required this.isActive,
|
|
});
|
|
|
|
factory Budget.fromJson(Map<String, dynamic> json) {
|
|
return Budget(
|
|
id: asInt(json['id']),
|
|
userId: asInt(json['user_id']),
|
|
name: asString(json['name']),
|
|
totalAmount: asDouble(json['total_amount']),
|
|
startDate: asDate(json['start_date']),
|
|
endDate: asDate(json['end_date']),
|
|
currency: asString(json['currency'], fallback: 'RUB'),
|
|
isActive: asBool(json['is_active']),
|
|
);
|
|
}
|
|
|
|
final int id;
|
|
final int userId;
|
|
final String name;
|
|
final double totalAmount;
|
|
final DateTime startDate;
|
|
final DateTime endDate;
|
|
final String currency;
|
|
final bool isActive;
|
|
}
|
|
|
|
/// Budget plus the server-computed daily envelope math.
|
|
class BudgetStatus {
|
|
const BudgetStatus({
|
|
required this.budget,
|
|
required this.today,
|
|
required this.daysLeft,
|
|
required this.totalSpent,
|
|
required this.remaining,
|
|
required this.dailyLimit,
|
|
required this.spentToday,
|
|
required this.remainingToday,
|
|
required this.isOverDaily,
|
|
required this.isOverBudget,
|
|
required this.isExpired,
|
|
required this.selected,
|
|
});
|
|
|
|
factory BudgetStatus.fromJson(Map<String, dynamic> json) {
|
|
return BudgetStatus(
|
|
budget: Budget.fromJson(asMap(json['budget'])),
|
|
today: asDate(json['today']),
|
|
daysLeft: asInt(json['days_left']),
|
|
totalSpent: asDouble(json['total_spent']),
|
|
remaining: asDouble(json['remaining']),
|
|
dailyLimit: asDouble(json['daily_limit']),
|
|
spentToday: asDouble(json['spent_today']),
|
|
remainingToday: asDouble(json['remaining_today']),
|
|
isOverDaily: asBool(json['is_over_daily']),
|
|
isOverBudget: asBool(json['is_over_budget']),
|
|
isExpired: asBool(json['is_expired']),
|
|
selected: asBool(json['selected']),
|
|
);
|
|
}
|
|
|
|
final Budget budget;
|
|
final DateTime today;
|
|
final int daysLeft;
|
|
final double totalSpent;
|
|
final double remaining;
|
|
final double dailyLimit;
|
|
final double spentToday;
|
|
final double remainingToday;
|
|
final bool isOverDaily;
|
|
final bool isOverBudget;
|
|
final bool isExpired;
|
|
final bool selected;
|
|
|
|
/// 0..1 — share of the budget already spent.
|
|
double get spentProgress {
|
|
if (budget.totalAmount <= 0) return 0;
|
|
return (totalSpent / budget.totalAmount).clamp(0.0, 1.0);
|
|
}
|
|
|
|
/// 0..1 — share of today's envelope already spent.
|
|
double get dailyProgress {
|
|
if (dailyLimit <= 0) return spentToday > 0 ? 1 : 0;
|
|
return (spentToday / dailyLimit).clamp(0.0, 1.0);
|
|
}
|
|
}
|
|
|
|
class BudgetsList {
|
|
const BudgetsList({required this.items});
|
|
|
|
factory BudgetsList.fromJson(Map<String, dynamic> json) {
|
|
return BudgetsList(
|
|
items: asList(json['items']).map(BudgetStatus.fromJson).toList(),
|
|
);
|
|
}
|
|
|
|
final List<BudgetStatus> items;
|
|
}
|