Initial commit - app-padrao-1.0
This commit is contained in:
87
lib/features/finances/data/models/transaction_model.dart
Normal file
87
lib/features/finances/data/models/transaction_model.dart
Normal file
@@ -0,0 +1,87 @@
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
part 'transaction_model.g.dart';
|
||||
|
||||
@HiveType(typeId: 3)
|
||||
enum TransactionType {
|
||||
@HiveField(0)
|
||||
revenue, // Receita
|
||||
@HiveField(1)
|
||||
expense, // Despesa
|
||||
}
|
||||
|
||||
@HiveType(typeId: 4)
|
||||
class TransactionModel extends HiveObject {
|
||||
@HiveField(0)
|
||||
final String id;
|
||||
|
||||
@HiveField(1)
|
||||
final String userId;
|
||||
|
||||
@HiveField(2)
|
||||
final TransactionType type;
|
||||
|
||||
@HiveField(3)
|
||||
final double amount;
|
||||
|
||||
@HiveField(4)
|
||||
final String description;
|
||||
|
||||
@HiveField(5)
|
||||
final DateTime dueDate;
|
||||
|
||||
@HiveField(6)
|
||||
final DateTime? paidDate;
|
||||
|
||||
@HiveField(7)
|
||||
final bool isPaid;
|
||||
|
||||
@HiveField(8)
|
||||
final String? haircutId; // Vinculado a um corte (receita automática)
|
||||
|
||||
@HiveField(9)
|
||||
final DateTime createdAt;
|
||||
|
||||
TransactionModel({
|
||||
required this.id,
|
||||
required this.userId,
|
||||
required this.type,
|
||||
required this.amount,
|
||||
required this.description,
|
||||
required this.dueDate,
|
||||
this.paidDate,
|
||||
required this.isPaid,
|
||||
this.haircutId,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
bool get isFromHaircut => haircutId != null;
|
||||
|
||||
bool get isOverdue => !isPaid && dueDate.isBefore(DateTime.now());
|
||||
|
||||
TransactionModel copyWith({
|
||||
String? id,
|
||||
String? userId,
|
||||
TransactionType? type,
|
||||
double? amount,
|
||||
String? description,
|
||||
DateTime? dueDate,
|
||||
DateTime? paidDate,
|
||||
bool? isPaid,
|
||||
String? haircutId,
|
||||
DateTime? createdAt,
|
||||
}) {
|
||||
return TransactionModel(
|
||||
id: id ?? this.id,
|
||||
userId: userId ?? this.userId,
|
||||
type: type ?? this.type,
|
||||
amount: amount ?? this.amount,
|
||||
description: description ?? this.description,
|
||||
dueDate: dueDate ?? this.dueDate,
|
||||
paidDate: paidDate ?? this.paidDate,
|
||||
isPaid: isPaid ?? this.isPaid,
|
||||
haircutId: haircutId ?? this.haircutId,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
107
lib/features/finances/data/models/transaction_model.g.dart
Normal file
107
lib/features/finances/data/models/transaction_model.g.dart
Normal file
@@ -0,0 +1,107 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'transaction_model.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// TypeAdapterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class TransactionModelAdapter extends TypeAdapter<TransactionModel> {
|
||||
@override
|
||||
final int typeId = 4;
|
||||
|
||||
@override
|
||||
TransactionModel read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return TransactionModel(
|
||||
id: fields[0] as String,
|
||||
userId: fields[1] as String,
|
||||
type: fields[2] as TransactionType,
|
||||
amount: fields[3] as double,
|
||||
description: fields[4] as String,
|
||||
dueDate: fields[5] as DateTime,
|
||||
paidDate: fields[6] as DateTime?,
|
||||
isPaid: fields[7] as bool,
|
||||
haircutId: fields[8] as String?,
|
||||
createdAt: fields[9] as DateTime,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, TransactionModel obj) {
|
||||
writer
|
||||
..writeByte(10)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
..write(obj.userId)
|
||||
..writeByte(2)
|
||||
..write(obj.type)
|
||||
..writeByte(3)
|
||||
..write(obj.amount)
|
||||
..writeByte(4)
|
||||
..write(obj.description)
|
||||
..writeByte(5)
|
||||
..write(obj.dueDate)
|
||||
..writeByte(6)
|
||||
..write(obj.paidDate)
|
||||
..writeByte(7)
|
||||
..write(obj.isPaid)
|
||||
..writeByte(8)
|
||||
..write(obj.haircutId)
|
||||
..writeByte(9)
|
||||
..write(obj.createdAt);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is TransactionModelAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
|
||||
class TransactionTypeAdapter extends TypeAdapter<TransactionType> {
|
||||
@override
|
||||
final int typeId = 3;
|
||||
|
||||
@override
|
||||
TransactionType read(BinaryReader reader) {
|
||||
switch (reader.readByte()) {
|
||||
case 0:
|
||||
return TransactionType.revenue;
|
||||
case 1:
|
||||
return TransactionType.expense;
|
||||
default:
|
||||
return TransactionType.revenue;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, TransactionType obj) {
|
||||
switch (obj) {
|
||||
case TransactionType.revenue:
|
||||
writer.writeByte(0);
|
||||
break;
|
||||
case TransactionType.expense:
|
||||
writer.writeByte(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is TransactionTypeAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:barber_app/core/database/database_service.dart';
|
||||
import 'package:barber_app/features/finances/data/models/transaction_model.dart';
|
||||
|
||||
class TransactionRepository {
|
||||
final _uuid = const Uuid();
|
||||
|
||||
String? get _currentUserId => DatabaseService.getCurrentUserId();
|
||||
|
||||
// Criar transação de receita a partir de um corte
|
||||
Future<TransactionModel?> createRevenueFromHaircut({
|
||||
required String haircutId,
|
||||
required double amount,
|
||||
required String clientName,
|
||||
required String serviceType,
|
||||
bool isPaid = true,
|
||||
}) async {
|
||||
if (_currentUserId == null) return null;
|
||||
|
||||
final transaction = TransactionModel(
|
||||
id: _uuid.v4(),
|
||||
userId: _currentUserId!,
|
||||
type: TransactionType.revenue,
|
||||
amount: amount,
|
||||
description: '$serviceType - $clientName',
|
||||
dueDate: DateTime.now(),
|
||||
isPaid: isPaid,
|
||||
paidDate: isPaid ? DateTime.now() : null,
|
||||
haircutId: haircutId,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
await DatabaseService.transactionsBoxInstance.put(
|
||||
transaction.id,
|
||||
transaction,
|
||||
);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// Criar despesa
|
||||
Future<TransactionModel?> createExpense({
|
||||
required double amount,
|
||||
required String description,
|
||||
required DateTime dueDate,
|
||||
bool isPaid = false,
|
||||
}) async {
|
||||
if (_currentUserId == null) return null;
|
||||
|
||||
final transaction = TransactionModel(
|
||||
id: _uuid.v4(),
|
||||
userId: _currentUserId!,
|
||||
type: TransactionType.expense,
|
||||
amount: amount,
|
||||
description: description.trim(),
|
||||
dueDate: dueDate,
|
||||
isPaid: isPaid,
|
||||
paidDate: isPaid ? DateTime.now() : null,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
await DatabaseService.transactionsBoxInstance.put(
|
||||
transaction.id,
|
||||
transaction,
|
||||
);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// Criar receita manual
|
||||
Future<TransactionModel?> createRevenue({
|
||||
required double amount,
|
||||
required String description,
|
||||
required DateTime dueDate,
|
||||
bool isPaid = false,
|
||||
}) async {
|
||||
if (_currentUserId == null) return null;
|
||||
|
||||
final transaction = TransactionModel(
|
||||
id: _uuid.v4(),
|
||||
userId: _currentUserId!,
|
||||
type: TransactionType.revenue,
|
||||
amount: amount,
|
||||
description: description.trim(),
|
||||
dueDate: dueDate,
|
||||
isPaid: isPaid,
|
||||
paidDate: isPaid ? DateTime.now() : null,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
await DatabaseService.transactionsBoxInstance.put(
|
||||
transaction.id,
|
||||
transaction,
|
||||
);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// Listar todas as transações
|
||||
List<TransactionModel> getAllTransactions() {
|
||||
if (_currentUserId == null) return [];
|
||||
return DatabaseService.transactionsBoxInstance.values
|
||||
.where((t) => t.userId == _currentUserId)
|
||||
.toList()
|
||||
..sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
||||
}
|
||||
|
||||
// Receitas
|
||||
List<TransactionModel> getRevenues() {
|
||||
return getAllTransactions()
|
||||
.where((t) => t.type == TransactionType.revenue)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Despesas
|
||||
List<TransactionModel> getExpenses() {
|
||||
return getAllTransactions()
|
||||
.where((t) => t.type == TransactionType.expense)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// Pendentes a receber
|
||||
double getPendingReceivables() {
|
||||
return getRevenues()
|
||||
.where((t) => !t.isPaid)
|
||||
.fold(0.0, (sum, t) => sum + t.amount);
|
||||
}
|
||||
|
||||
// Pendentes a pagar
|
||||
double getPendingPayables() {
|
||||
return getExpenses()
|
||||
.where((t) => !t.isPaid)
|
||||
.fold(0.0, (sum, t) => sum + t.amount);
|
||||
}
|
||||
|
||||
// Total recebido (pago)
|
||||
double getTotalReceived() {
|
||||
return getRevenues()
|
||||
.where((t) => t.isPaid)
|
||||
.fold(0.0, (sum, t) => sum + t.amount);
|
||||
}
|
||||
|
||||
// Total pago
|
||||
double getTotalPaid() {
|
||||
return getExpenses()
|
||||
.where((t) => t.isPaid)
|
||||
.fold(0.0, (sum, t) => sum + t.amount);
|
||||
}
|
||||
|
||||
// Dashboard Helpers
|
||||
|
||||
List<double> getLast7DaysRevenue() {
|
||||
final now = DateTime.now();
|
||||
final List<double> dailyRevenue = List.filled(7, 0.0);
|
||||
|
||||
// Obtém todas as transações
|
||||
final allTransactions =
|
||||
getAllTransactions(); // Use o helper que filtra pelo usuário
|
||||
if (allTransactions.isEmpty) return dailyRevenue;
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
final targetDate = now.subtract(Duration(days: 6 - i));
|
||||
|
||||
final dayRevenue = allTransactions
|
||||
.where(
|
||||
(t) =>
|
||||
t.type == TransactionType.revenue &&
|
||||
t.dueDate.year == targetDate.year &&
|
||||
t.dueDate.month == targetDate.month &&
|
||||
t.dueDate.day == targetDate.day,
|
||||
)
|
||||
.fold(0.0, (sum, t) => sum + t.amount);
|
||||
|
||||
dailyRevenue[i] = dayRevenue;
|
||||
}
|
||||
|
||||
return dailyRevenue;
|
||||
}
|
||||
|
||||
// Saldo
|
||||
double getBalance() {
|
||||
return getTotalReceived() - getTotalPaid();
|
||||
}
|
||||
|
||||
// Marcar como pago
|
||||
Future<TransactionModel?> markAsPaid(String id) async {
|
||||
final transaction = DatabaseService.transactionsBoxInstance.get(id);
|
||||
if (transaction == null) return null;
|
||||
|
||||
final updated = transaction.copyWith(
|
||||
isPaid: true,
|
||||
paidDate: DateTime.now(),
|
||||
);
|
||||
|
||||
await DatabaseService.transactionsBoxInstance.put(id, updated);
|
||||
return updated;
|
||||
}
|
||||
|
||||
// Deletar transação
|
||||
Future<void> deleteTransaction(String id) async {
|
||||
await DatabaseService.transactionsBoxInstance.delete(id);
|
||||
}
|
||||
|
||||
// Transações do mês
|
||||
List<TransactionModel> getMonthTransactions() {
|
||||
final now = DateTime.now();
|
||||
final monthStart = DateTime(now.year, now.month, 1);
|
||||
|
||||
return getAllTransactions()
|
||||
.where((t) => t.createdAt.isAfter(monthStart))
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<void> addTransaction(TransactionModel transaction) async {
|
||||
await DatabaseService.transactionsBoxInstance.put(
|
||||
transaction.id,
|
||||
transaction,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user