Files
TravelMate/lib/services/expense_service.dart
Dayron 2faf37f145 Enhance model and service documentation with detailed comments and descriptions
- Updated Group, Trip, User, and other model classes to include comprehensive documentation for better understanding and maintainability.
- Improved error handling and logging in services, including AuthService, ErrorService, and StorageService.
- Added validation and business logic explanations in ExpenseService and TripService.
- Refactored method comments to follow a consistent format across the codebase.
- Translated error messages and comments from French to English for consistency.
2025-10-30 15:56:17 +01:00

114 lines
3.8 KiB
Dart

import 'dart:io';
import '../models/expense.dart';
import '../repositories/expense_repository.dart';
import 'error_service.dart';
import 'storage_service.dart';
/// Service for managing expense operations with business logic validation.
///
/// This service provides high-level expense management functionality including
/// validation, receipt image uploading, and coordination with the expense repository.
/// It acts as a business logic layer between the UI and data persistence.
class ExpenseService {
/// Repository for expense data operations.
final ExpenseRepository _expenseRepository;
/// Service for error handling and logging.
final ErrorService _errorService;
/// Service for handling file uploads (receipts).
final StorageService _storageService;
/// Creates a new [ExpenseService] with required dependencies.
///
/// [expenseRepository] is required for data operations.
/// [errorService] and [storageService] have default implementations if not provided.
ExpenseService({
required ExpenseRepository expenseRepository,
ErrorService? errorService,
StorageService? storageService,
}) : _expenseRepository = expenseRepository,
_errorService = errorService ?? ErrorService(),
_storageService = storageService ?? StorageService();
/// Creates an expense with validation and optional receipt image upload.
///
/// Validates the expense data, uploads receipt image if provided, and
/// creates the expense record in the database.
///
/// [expense] - The expense data to create
/// [receiptImage] - Optional receipt image file to upload
///
/// Returns the ID of the created expense.
/// Throws exceptions if validation fails or creation errors occur.
Future<String> createExpenseWithValidation(Expense expense, File? receiptImage) async {
try {
// Business logic validation
_validateExpenseData(expense);
// Upload receipt image if provided
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');
}
}
}