feat: Implement BalanceRepository for group balance calculations feat: Create ExpenseRepository for managing expenses feat: Add services for handling expenses and storage operations fix: Update import paths for models in repositories and services refactor: Rename CountContent to AccountContent in HomePage chore: Add StorageService for image upload and management
91 lines
2.8 KiB
Dart
91 lines
2.8 KiB
Dart
import 'dart:io';
|
|
import '../models/expense.dart';
|
|
import '../repositories/expense_repository.dart';
|
|
import 'error_service.dart';
|
|
import 'storage_service.dart'; // Pour upload des reçus
|
|
|
|
class ExpenseService {
|
|
final ExpenseRepository _expenseRepository;
|
|
final ErrorService _errorService;
|
|
final StorageService _storageService;
|
|
|
|
ExpenseService({
|
|
required ExpenseRepository expenseRepository,
|
|
ErrorService? errorService,
|
|
StorageService? storageService,
|
|
}) : _expenseRepository = expenseRepository,
|
|
_errorService = errorService ?? ErrorService(),
|
|
_storageService = storageService ?? StorageService();
|
|
|
|
// Création avec validation et upload d'image
|
|
Future<String> createExpenseWithValidation(Expense expense, File? receiptImage) async {
|
|
try {
|
|
// Validation métier
|
|
_validateExpenseData(expense);
|
|
|
|
// Upload du reçu si présent
|
|
String? receiptUrl;
|
|
if (receiptImage != null) {
|
|
receiptUrl = await _storageService.uploadReceiptImage(
|
|
expense.groupId,
|
|
receiptImage,
|
|
);
|
|
}
|
|
|
|
// Créer l'expense avec l'URL du reçu
|
|
final expenseWithReceipt = expense.copyWith(receiptUrl: receiptUrl);
|
|
|
|
return await _expenseRepository.createExpense(expenseWithReceipt);
|
|
} catch (e) {
|
|
_errorService.logError('ExpenseService', 'Erreur création expense: $e');
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
// Mise à jour avec validation
|
|
Future<void> updateExpenseWithValidation(Expense expense, File? newReceiptImage) async {
|
|
try {
|
|
_validateExpenseData(expense);
|
|
|
|
// Gérer le nouvel upload si nécessaire
|
|
String? receiptUrl = expense.receiptUrl;
|
|
if (newReceiptImage != null) {
|
|
receiptUrl = await _storageService.uploadReceiptImage(
|
|
expense.groupId,
|
|
newReceiptImage,
|
|
);
|
|
}
|
|
|
|
final expenseWithReceipt = expense.copyWith(
|
|
receiptUrl: receiptUrl,
|
|
editedAt: DateTime.now(),
|
|
isEdited: true,
|
|
);
|
|
|
|
await _expenseRepository.updateExpense(expenseWithReceipt);
|
|
} catch (e) {
|
|
_errorService.logError('ExpenseService', 'Erreur update expense: $e');
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
// Validation des données
|
|
void _validateExpenseData(Expense expense) {
|
|
if (expense.description.trim().isEmpty) {
|
|
throw Exception('La description est requise');
|
|
}
|
|
|
|
if (expense.amount <= 0) {
|
|
throw Exception('Le montant doit être positif');
|
|
}
|
|
|
|
if (expense.splits.isEmpty) {
|
|
throw Exception('Au moins un participant est requis');
|
|
}
|
|
|
|
final totalSplits = expense.splits.fold(0.0, (sum, split) => sum + split.amount);
|
|
if ((totalSplits - expense.amountInEur).abs() > 0.01) {
|
|
throw Exception('La somme des répartitions ne correspond pas au montant total');
|
|
}
|
|
}
|
|
} |