/// Entité métier Budget /// /// Représente un budget prévisionnel (mensuel/annuel) avec suivi réalisé library budget; import 'package:equatable/equatable.dart'; /// Période du budget enum BudgetPeriod { /// Budget mensuel monthly, /// Budget trimestriel quarterly, /// Budget semestriel semiannual, /// Budget annuel annual, } /// Statut du budget enum BudgetStatus { /// Brouillon (en cours de création) draft, /// Actif active, /// Clos (période terminée) closed, /// Annulé cancelled, } /// Catégorie budgétaire enum BudgetCategory { /// Cotisations/contributions contributions, /// Épargne savings, /// Solidarité solidarity, /// Événements events, /// Fonctionnement (frais généraux) operational, /// Investissements investments, /// Autres other, } /// Entité Budget class Budget extends Equatable { final String id; final String name; final String? description; final String organizationId; final BudgetPeriod period; final int year; final int? month; final BudgetStatus status; final List lines; final double totalPlanned; final double totalRealized; final String currency; final String createdBy; final DateTime createdAt; final DateTime? approvedAt; final String? approvedBy; final DateTime startDate; final DateTime endDate; final Map? metadata; const Budget({ required this.id, required this.name, this.description, required this.organizationId, required this.period, required this.year, this.month, required this.status, this.lines = const [], required this.totalPlanned, this.totalRealized = 0, this.currency = 'XOF', required this.createdBy, required this.createdAt, this.approvedAt, this.approvedBy, required this.startDate, required this.endDate, this.metadata, }); /// Taux de réalisation (%) double get realizationRate { if (totalPlanned == 0) return 0; return (totalRealized / totalPlanned) * 100; } /// Écart (réalisé - prévu) double get variance => totalRealized - totalPlanned; /// Taux d'écart (%) double get varianceRate { if (totalPlanned == 0) return 0; return (variance / totalPlanned) * 100; } /// Vérifie si le budget est dépassé bool get isOverBudget => totalRealized > totalPlanned; /// Vérifie si le budget est actif bool get isActive => status == BudgetStatus.active; /// Vérifie si la période est en cours bool get isCurrentPeriod { final now = DateTime.now(); return now.isAfter(startDate) && now.isBefore(endDate); } /// Copie avec modifications Budget copyWith({ String? id, String? name, String? description, String? organizationId, BudgetPeriod? period, int? year, int? month, BudgetStatus? status, List? lines, double? totalPlanned, double? totalRealized, String? currency, String? createdBy, DateTime? createdAt, DateTime? approvedAt, String? approvedBy, DateTime? startDate, DateTime? endDate, Map? metadata, }) { return Budget( id: id ?? this.id, name: name ?? this.name, description: description ?? this.description, organizationId: organizationId ?? this.organizationId, period: period ?? this.period, year: year ?? this.year, month: month ?? this.month, status: status ?? this.status, lines: lines ?? this.lines, totalPlanned: totalPlanned ?? this.totalPlanned, totalRealized: totalRealized ?? this.totalRealized, currency: currency ?? this.currency, createdBy: createdBy ?? this.createdBy, createdAt: createdAt ?? this.createdAt, approvedAt: approvedAt ?? this.approvedAt, approvedBy: approvedBy ?? this.approvedBy, startDate: startDate ?? this.startDate, endDate: endDate ?? this.endDate, metadata: metadata ?? this.metadata, ); } @override List get props => [ id, name, description, organizationId, period, year, month, status, lines, totalPlanned, totalRealized, currency, createdBy, createdAt, approvedAt, approvedBy, startDate, endDate, metadata, ]; } /// Ligne budgétaire class BudgetLine extends Equatable { final String id; final BudgetCategory category; final String name; final String? description; final double amountPlanned; final double amountRealized; final String? notes; const BudgetLine({ required this.id, required this.category, required this.name, this.description, required this.amountPlanned, this.amountRealized = 0, this.notes, }); /// Taux de réalisation (%) double get realizationRate { if (amountPlanned == 0) return 0; return (amountRealized / amountPlanned) * 100; } /// Écart double get variance => amountRealized - amountPlanned; /// Vérifie si la ligne est dépassée bool get isOverBudget => amountRealized > amountPlanned; @override List get props => [ id, category, name, description, amountPlanned, amountRealized, notes, ]; }