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:
205
lib/models/expense.dart
Normal file
205
lib/models/expense.dart
Normal file
@@ -0,0 +1,205 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'expense_split.dart';
|
||||
|
||||
enum ExpenseCurrency {
|
||||
eur('€', 'EUR'),
|
||||
usd('\$', 'USD'),
|
||||
gbp('£', 'GBP');
|
||||
|
||||
const ExpenseCurrency(this.symbol, this.code);
|
||||
final String symbol;
|
||||
final String code;
|
||||
}
|
||||
|
||||
enum ExpenseCategory {
|
||||
restaurant('Restaurant', Icons.restaurant),
|
||||
transport('Transport', Icons.directions_car),
|
||||
accommodation('Hébergement', Icons.hotel),
|
||||
entertainment('Loisirs', Icons.local_activity),
|
||||
shopping('Shopping', Icons.shopping_bag),
|
||||
other('Autre', Icons.category);
|
||||
|
||||
const ExpenseCategory(this.displayName, this.icon);
|
||||
final String displayName;
|
||||
final IconData icon;
|
||||
}
|
||||
|
||||
class Expense extends Equatable {
|
||||
final String id;
|
||||
final String groupId;
|
||||
final String description;
|
||||
final double amount;
|
||||
final ExpenseCurrency currency;
|
||||
final double amountInEur; // Montant converti en EUR
|
||||
final ExpenseCategory category;
|
||||
final String paidById;
|
||||
final String paidByName;
|
||||
final DateTime date;
|
||||
final DateTime createdAt;
|
||||
final DateTime? editedAt;
|
||||
final bool isEdited;
|
||||
final bool isArchived;
|
||||
final String? receiptUrl;
|
||||
final List<ExpenseSplit> splits;
|
||||
|
||||
const Expense({
|
||||
required this.id,
|
||||
required this.groupId,
|
||||
required this.description,
|
||||
required this.amount,
|
||||
required this.currency,
|
||||
required this.amountInEur,
|
||||
required this.category,
|
||||
required this.paidById,
|
||||
required this.paidByName,
|
||||
required this.date,
|
||||
required this.createdAt,
|
||||
this.editedAt,
|
||||
this.isEdited = false,
|
||||
this.isArchived = false,
|
||||
this.receiptUrl,
|
||||
required this.splits,
|
||||
});
|
||||
|
||||
factory Expense.fromMap(Map<String, dynamic> map, String id) {
|
||||
return Expense(
|
||||
id: id,
|
||||
groupId: map['groupId'] ?? '',
|
||||
description: map['description'] ?? '',
|
||||
amount: (map['amount'] as num?)?.toDouble() ?? 0.0,
|
||||
currency: ExpenseCurrency.values.firstWhere(
|
||||
(c) => c.code == map['currency'],
|
||||
orElse: () => ExpenseCurrency.eur,
|
||||
),
|
||||
amountInEur: (map['amountInEur'] as num?)?.toDouble() ?? 0.0,
|
||||
category: ExpenseCategory.values.firstWhere(
|
||||
(c) => c.name == map['category'],
|
||||
orElse: () => ExpenseCategory.other,
|
||||
),
|
||||
paidById: map['paidById'] ?? '',
|
||||
paidByName: map['paidByName'] ?? '',
|
||||
date: _parseDateTime(map['date']),
|
||||
createdAt: _parseDateTime(map['createdAt']),
|
||||
editedAt: map['editedAt'] != null ? _parseDateTime(map['editedAt']) : null,
|
||||
isEdited: map['isEdited'] ?? false,
|
||||
isArchived: map['isArchived'] ?? false,
|
||||
receiptUrl: map['receiptUrl'],
|
||||
splits: (map['splits'] as List?)
|
||||
?.map((s) => ExpenseSplit.fromMap(s))
|
||||
.toList() ?? [],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'groupId': groupId,
|
||||
'description': description,
|
||||
'amount': amount,
|
||||
'currency': currency.code,
|
||||
'amountInEur': amountInEur,
|
||||
'category': category.name,
|
||||
'paidById': paidById,
|
||||
'paidByName': paidByName,
|
||||
'date': Timestamp.fromDate(date),
|
||||
'createdAt': Timestamp.fromDate(createdAt),
|
||||
'editedAt': editedAt != null ? Timestamp.fromDate(editedAt!) : null,
|
||||
'isEdited': isEdited,
|
||||
'isArchived': isArchived,
|
||||
'receiptUrl': receiptUrl,
|
||||
'splits': splits.map((s) => s.toMap()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
static DateTime _parseDateTime(dynamic value) {
|
||||
if (value is Timestamp) return value.toDate();
|
||||
if (value is String) return DateTime.parse(value);
|
||||
if (value is DateTime) return value;
|
||||
return DateTime.now();
|
||||
}
|
||||
|
||||
Expense copyWith({
|
||||
String? id,
|
||||
String? groupId,
|
||||
String? description,
|
||||
double? amount,
|
||||
ExpenseCurrency? currency,
|
||||
double? amountInEur,
|
||||
ExpenseCategory? category,
|
||||
String? paidById,
|
||||
String? paidByName,
|
||||
DateTime? date,
|
||||
DateTime? createdAt,
|
||||
DateTime? editedAt,
|
||||
bool? isEdited,
|
||||
bool? isArchived,
|
||||
String? receiptUrl,
|
||||
List<ExpenseSplit>? splits,
|
||||
}) {
|
||||
return Expense(
|
||||
id: id ?? this.id,
|
||||
groupId: groupId ?? this.groupId,
|
||||
description: description ?? this.description,
|
||||
amount: amount ?? this.amount,
|
||||
currency: currency ?? this.currency,
|
||||
amountInEur: amountInEur ?? this.amountInEur,
|
||||
category: category ?? this.category,
|
||||
paidById: paidById ?? this.paidById,
|
||||
paidByName: paidByName ?? this.paidByName,
|
||||
date: date ?? this.date,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
editedAt: editedAt ?? this.editedAt,
|
||||
isEdited: isEdited ?? this.isEdited,
|
||||
isArchived: isArchived ?? this.isArchived,
|
||||
receiptUrl: receiptUrl ?? this.receiptUrl,
|
||||
splits: splits ?? this.splits,
|
||||
);
|
||||
}
|
||||
|
||||
Expense copyWithEdit({
|
||||
String? description,
|
||||
double? amount,
|
||||
ExpenseCurrency? currency,
|
||||
double? amountInEur,
|
||||
ExpenseCategory? category,
|
||||
List<ExpenseSplit>? splits,
|
||||
String? receiptUrl,
|
||||
}) {
|
||||
return copyWith(
|
||||
description: description,
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
amountInEur: amountInEur,
|
||||
category: category,
|
||||
splits: splits,
|
||||
receiptUrl: receiptUrl,
|
||||
editedAt: DateTime.now(),
|
||||
isEdited: true,
|
||||
);
|
||||
}
|
||||
|
||||
// Marquer comme archivé
|
||||
Expense copyWithArchived() {
|
||||
return copyWith(
|
||||
isArchived: true,
|
||||
);
|
||||
}
|
||||
|
||||
// Ajouter/mettre à jour l'URL du reçu
|
||||
Expense copyWithReceipt(String receiptUrl) {
|
||||
return copyWith(
|
||||
receiptUrl: receiptUrl,
|
||||
);
|
||||
}
|
||||
|
||||
// Mettre à jour les splits
|
||||
Expense copyWithSplits(List<ExpenseSplit> newSplits) {
|
||||
return copyWith(
|
||||
splits: newSplits,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id];
|
||||
}
|
||||
Reference in New Issue
Block a user