Files
2026-09-21 04:06:43 +03:00

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;
}