feat: Add logger service and improve expense dialog with enhanced receipt management and calculation logic.

This commit is contained in:
Van Leemput Dayron
2025-11-28 12:54:54 +01:00
parent cad9d42128
commit fd710b8cb8
35 changed files with 2148 additions and 1296 deletions

View File

@@ -32,6 +32,7 @@
/// - [Settlement] for individual payment recommendations
/// - [UserBalance] for per-user balance information
library;
import '../models/group_balance.dart';
import '../models/expense.dart';
import '../models/group_statistics.dart';
@@ -59,7 +60,10 @@ class BalanceService {
try {
return await _balanceRepository.calculateGroupBalance(groupId);
} catch (e) {
_errorService.logError('BalanceService', 'Erreur calcul balance groupe: $e');
_errorService.logError(
'BalanceService',
'Erreur calcul balance groupe: $e',
);
rethrow;
}
}
@@ -80,7 +84,9 @@ class BalanceService {
/// Stream de la balance en temps réel
Stream<GroupBalance> getGroupBalanceStream(String groupId) {
return _expenseRepository.getExpensesStream(groupId).asyncMap((expenses) async {
return _expenseRepository.getExpensesStream(groupId).asyncMap((
expenses,
) async {
try {
final userBalances = calculateUserBalances(expenses);
final settlements = optimizeSettlements(userBalances);
@@ -145,7 +151,7 @@ class BalanceService {
/// Optimiser les règlements (algorithme avancé)
List<Settlement> optimizeSettlements(List<UserBalance> balances) {
final settlements = <Settlement>[];
// Filtrer les utilisateurs avec une balance significative (> 0.01€)
final creditors = balances
.where((b) => b.shouldReceive && b.balance > 0.01)
@@ -164,10 +170,10 @@ class BalanceService {
// Utiliser des copies mutables pour les calculs
final creditorsRemaining = Map<String, double>.fromEntries(
creditors.map((c) => MapEntry(c.userId, c.balance))
creditors.map((c) => MapEntry(c.userId, c.balance)),
);
final debtorsRemaining = Map<String, double>.fromEntries(
debtors.map((d) => MapEntry(d.userId, -d.balance))
debtors.map((d) => MapEntry(d.userId, -d.balance)),
);
// Algorithme glouton optimisé
@@ -185,16 +191,19 @@ class BalanceService {
);
if (settlementAmount > 0.01) {
settlements.add(Settlement(
fromUserId: debtor.userId,
fromUserName: debtor.userName,
toUserId: creditor.userId,
toUserName: creditor.userName,
amount: settlementAmount,
));
settlements.add(
Settlement(
fromUserId: debtor.userId,
fromUserName: debtor.userName,
toUserId: creditor.userId,
toUserName: creditor.userName,
amount: settlementAmount,
),
);
// Mettre à jour les montants restants
creditorsRemaining[creditor.userId] = creditRemaining - settlementAmount;
creditorsRemaining[creditor.userId] =
creditRemaining - settlementAmount;
debtorsRemaining[debtor.userId] = debtRemaining - settlementAmount;
}
}
@@ -204,7 +213,10 @@ class BalanceService {
}
/// Calculer le montant optimal pour un règlement
double _calculateOptimalSettlementAmount(double creditAmount, double debtAmount) {
double _calculateOptimalSettlementAmount(
double creditAmount,
double debtAmount,
) {
final amount = [creditAmount, debtAmount].reduce((a, b) => a < b ? a : b);
// Arrondir à 2 décimales
return (amount * 100).round() / 100;
@@ -213,36 +225,50 @@ class BalanceService {
/// Valider les règlements calculés
List<Settlement> _validateSettlements(List<Settlement> settlements) {
// Supprimer les règlements trop petits
final validSettlements = settlements
.where((s) => s.amount > 0.01)
.toList();
final validSettlements = settlements.where((s) => s.amount > 0.01).toList();
// Log pour debug en cas de problème
final totalSettlements = validSettlements.fold(0.0, (sum, s) => sum + s.amount);
_errorService.logInfo('BalanceService',
'Règlements calculés: ${validSettlements.length}, Total: ${totalSettlements.toStringAsFixed(2)}');
final totalSettlements = validSettlements.fold(
0.0,
(sum, s) => sum + s.amount,
);
_errorService.logInfo(
'BalanceService',
'Règlements calculés: ${validSettlements.length}, Total: ${totalSettlements.toStringAsFixed(2)}',
);
return validSettlements;
}
/// Calculer la dette entre deux utilisateurs spécifiques
double calculateDebtBetweenUsers(String groupId, String userId1, String userId2) {
double calculateDebtBetweenUsers(
String groupId,
String userId1,
String userId2,
) {
// Cette méthode pourrait être utile pour des fonctionnalités avancées
// comme "Combien me doit X ?" ou "Combien je dois à Y ?"
return 0.0; // TODO: Implémenter si nécessaire
// On peut utiliser optimizeSettlements pour avoir la réponse précise
// Cependant, cela nécessite d'avoir les dépenses.
// Comme cette méthode est synchrone et ne prend pas les dépenses en entrée,
// elle est difficile à implémenter correctement sans changer sa signature.
// Pour l'instant, on retourne 0.0 car elle n'est pas utilisée.
return 0.0;
}
/// Analyser les tendances de dépenses par catégorie
Map<String, double> analyzeCategorySpending(List<Expense> expenses) {
final categoryTotals = <String, double>{};
for (final expense in expenses) {
if (expense.isArchived) continue;
final categoryName = expense.category.displayName;
categoryTotals[categoryName] = (categoryTotals[categoryName] ?? 0) + expense.amountInEur;
categoryTotals[categoryName] =
(categoryTotals[categoryName] ?? 0) + expense.amountInEur;
}
return categoryTotals;
}
@@ -253,9 +279,12 @@ class BalanceService {
}
final nonArchivedExpenses = expenses.where((e) => !e.isArchived).toList();
final totalAmount = nonArchivedExpenses.fold(0.0, (sum, e) => sum + e.amountInEur);
final totalAmount = nonArchivedExpenses.fold(
0.0,
(sum, e) => sum + e.amountInEur,
);
final averageAmount = totalAmount / nonArchivedExpenses.length;
final categorySpending = analyzeCategorySpending(nonArchivedExpenses);
final topCategory = categorySpending.entries
.reduce((a, b) => a.value > b.value ? a : b)
@@ -279,11 +308,14 @@ class BalanceService {
try {
// Ici vous pourriez enregistrer le règlement en base
// ou créer une transaction de règlement
// Pour l'instant, on pourrait juste recalculer
await Future.delayed(const Duration(milliseconds: 100));
_errorService.logSuccess('BalanceService', 'Règlement marqué comme effectué');
_errorService.logSuccess(
'BalanceService',
'Règlement marqué comme effectué',
);
} catch (e) {
_errorService.logError('BalanceService', 'Erreur mark settlement: $e');
rethrow;
@@ -312,4 +344,4 @@ class _UserBalanceCalculator {
balance: _totalPaid - _totalOwed,
);
}
}
}