feat: Add User and UserBalance models with serialization methods
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
This commit is contained in:
91
lib/services/expense_service.dart
Normal file
91
lib/services/expense_service.dart
Normal file
@@ -0,0 +1,91 @@
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user