Initial upload: fin65-mobile

This commit is contained in:
Abderrahim-Mouhcine
2026-08-16 19:59:55 +01:00
commit 46558a5ec8
242 changed files with 16334 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
class Account {
final int id;
final String name;
final String type;
final String currency;
final double initialBalance;
final double appBalance;
final bool isActive;
Account({
required this.id,
required this.name,
required this.type,
required this.currency,
required this.initialBalance,
required this.appBalance,
required this.isActive,
});
factory Account.fromJson(Map<String, dynamic> json) {
return Account(
id: json['id'] as int,
name: json['name'] as String,
type: json['type'] as String,
currency: json['currency'] as String? ?? 'MAD',
initialBalance: (json['initial_balance'] as num? ?? 0).toDouble(),
appBalance: (json['app_balance'] as num? ?? 0).toDouble(),
isActive: json['is_active'] is int
? (json['is_active'] as int) == 1
: json['is_active'] as bool? ?? true,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'type': type,
'currency': currency,
'initial_balance': initialBalance,
'app_balance': appBalance,
'is_active': isActive,
};
}
Map<String, dynamic> toDbMap() {
return {
'id': id,
'name': name,
'type': type,
'currency': currency,
'initial_balance': initialBalance,
'app_balance': appBalance,
'is_active': isActive ? 1 : 0,
'updated_at': DateTime.now().toIso8601String(),
};
}
factory Account.fromDbMap(Map<String, dynamic> map) {
return Account(
id: map['id'] as int,
name: map['name'] as String,
type: map['type'] as String,
currency: map['currency'] as String? ?? 'MAD',
initialBalance: (map['initial_balance'] as num? ?? 0).toDouble(),
appBalance: (map['app_balance'] as num? ?? 0).toDouble(),
isActive: (map['is_active'] as int? ?? 1) == 1,
);
}
Account copyWith({
int? id,
String? name,
String? type,
String? currency,
double? initialBalance,
double? appBalance,
bool? isActive,
}) {
return Account(
id: id ?? this.id,
name: name ?? this.name,
type: type ?? this.type,
currency: currency ?? this.currency,
initialBalance: initialBalance ?? this.initialBalance,
appBalance: appBalance ?? this.appBalance,
isActive: isActive ?? this.isActive,
);
}
}
+50
View File
@@ -0,0 +1,50 @@
class Category {
final int id;
final String name;
final String type;
final int? parentId;
Category({
required this.id,
required this.name,
required this.type,
this.parentId,
});
factory Category.fromJson(Map<String, dynamic> json) {
return Category(
id: json['id'] as int,
name: json['name'] as String,
type: json['type'] as String,
parentId: json['parent_id'] as int?,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'type': type,
'parent_id': parentId,
};
}
Map<String, dynamic> toDbMap() {
return {
'id': id,
'name': name,
'type': type,
'parent_id': parentId,
'updated_at': DateTime.now().toIso8601String(),
};
}
factory Category.fromDbMap(Map<String, dynamic> map) {
return Category(
id: map['id'] as int,
name: map['name'] as String,
type: map['type'] as String,
parentId: map['parent_id'] as int?,
);
}
}
+223
View File
@@ -0,0 +1,223 @@
import 'account.dart';
class ReconciliationStatus {
final int accountId;
final String accountName;
final double appBalance;
final bool checkedToday;
final double? realBalance;
final double? difference;
ReconciliationStatus({
required this.accountId,
required this.accountName,
required this.appBalance,
required this.checkedToday,
this.realBalance,
this.difference,
});
factory ReconciliationStatus.fromJson(Map<String, dynamic> json) {
return ReconciliationStatus(
accountId: json['account_id'] as int,
accountName: json['account_name'] as String,
appBalance: (json['app_balance'] as num? ?? 0).toDouble(),
checkedToday: json['checked_today'] is int
? (json['checked_today'] as int) == 1
: json['checked_today'] as bool? ?? false,
realBalance: (json['real_balance'] as num?)?.toDouble(),
difference: (json['difference'] as num?)?.toDouble(),
);
}
Map<String, dynamic> toJson() {
return {
'account_id': accountId,
'account_name': accountName,
'app_balance': appBalance,
'checked_today': checkedToday,
'real_balance': realBalance,
'difference': difference,
};
}
ReconciliationStatus copyWith({
double? appBalance,
bool? checkedToday,
double? realBalance,
double? difference,
}) {
return ReconciliationStatus(
accountId: accountId,
accountName: accountName,
appBalance: appBalance ?? this.appBalance,
checkedToday: checkedToday ?? this.checkedToday,
realBalance: realBalance ?? this.realBalance,
difference: difference ?? this.difference,
);
}
}
class DashboardData {
final String month;
final double totalBalance;
final double availableAfterReserves;
final double monthlyIncome;
final double monthlyExpenses;
final double monthlyBalance;
final double provisionsCurrentTotal;
final double provisionsTargetTotal;
final double monthlyChargesRemainingTotal;
final double monthlyTransferRemainingTotal;
final double monthlyProvisionOperationRemainingTotal;
// Nouveaux champs backend : échéancier / opérations prévues ponctuelles.
final double scheduledExpensesRemainingTotal;
final double scheduledIncomeRemainingTotal;
final double scheduledTransferRemainingTotal;
final double scheduledProvisionRemainingTotal;
final double scheduledNetRemainingTotal;
final double projectedMonthBalance;
final List<Account> accounts;
final List<ReconciliationStatus> reconciliationsToday;
DashboardData({
required this.month,
required this.totalBalance,
required this.availableAfterReserves,
required this.monthlyIncome,
required this.monthlyExpenses,
required this.monthlyBalance,
required this.provisionsCurrentTotal,
required this.provisionsTargetTotal,
required this.monthlyChargesRemainingTotal,
required this.monthlyTransferRemainingTotal,
required this.monthlyProvisionOperationRemainingTotal,
required this.scheduledExpensesRemainingTotal,
required this.scheduledIncomeRemainingTotal,
required this.scheduledTransferRemainingTotal,
required this.scheduledProvisionRemainingTotal,
required this.scheduledNetRemainingTotal,
required this.projectedMonthBalance,
required this.accounts,
required this.reconciliationsToday,
});
double get plannedExpensesTotal =>
monthlyChargesRemainingTotal + scheduledExpensesRemainingTotal;
double get plannedTransfersTotal =>
monthlyTransferRemainingTotal + scheduledTransferRemainingTotal;
double get plannedProvisionsTotal =>
monthlyProvisionOperationRemainingTotal + scheduledProvisionRemainingTotal;
bool get hasScheduledInfo =>
scheduledExpensesRemainingTotal != 0 ||
scheduledIncomeRemainingTotal != 0 ||
scheduledTransferRemainingTotal != 0 ||
scheduledProvisionRemainingTotal != 0;
factory DashboardData.fromJson(Map<String, dynamic> json) {
final availableRaw = json['available_after_reserves'] ?? json['total_balance'] ?? 0;
final monthlyBalance = (json['monthly_balance'] as num? ?? 0).toDouble();
final scheduledIncome = (json['scheduled_income_remaining_total'] as num? ?? 0).toDouble();
final scheduledExpenses = (json['scheduled_expenses_remaining_total'] as num? ?? 0).toDouble();
return DashboardData(
month: json['month'] as String? ?? '',
totalBalance: (json['total_balance'] as num? ?? 0).toDouble(),
availableAfterReserves: (availableRaw as num).toDouble(),
monthlyIncome: (json['monthly_income'] as num? ?? 0).toDouble(),
monthlyExpenses: (json['monthly_expenses'] as num? ?? 0).toDouble(),
monthlyBalance: monthlyBalance,
provisionsCurrentTotal: (json['provisions_current_total'] as num? ?? 0).toDouble(),
provisionsTargetTotal: (json['provisions_target_total'] as num? ?? 0).toDouble(),
monthlyChargesRemainingTotal: (json['monthly_charges_remaining_total'] as num? ?? 0).toDouble(),
monthlyTransferRemainingTotal: (json['monthly_transfer_remaining_total'] as num? ?? 0).toDouble(),
monthlyProvisionOperationRemainingTotal: (json['monthly_provision_operation_remaining_total'] as num? ?? 0).toDouble(),
scheduledExpensesRemainingTotal: scheduledExpenses,
scheduledIncomeRemainingTotal: scheduledIncome,
scheduledTransferRemainingTotal: (json['scheduled_transfer_remaining_total'] as num? ?? 0).toDouble(),
scheduledProvisionRemainingTotal: (json['scheduled_provision_remaining_total'] as num? ?? 0).toDouble(),
scheduledNetRemainingTotal: (json['scheduled_net_remaining_total'] as num? ?? (scheduledIncome - scheduledExpenses)).toDouble(),
projectedMonthBalance: (json['projected_month_balance'] as num? ?? (monthlyBalance + scheduledIncome - scheduledExpenses)).toDouble(),
accounts: (json['accounts'] as List<dynamic>? ?? [])
.map((e) => Account.fromJson(e as Map<String, dynamic>))
.toList(),
reconciliationsToday: (json['reconciliations_today'] as List<dynamic>? ?? [])
.map((e) => ReconciliationStatus.fromJson(e as Map<String, dynamic>))
.toList(),
);
}
Map<String, dynamic> toJson() {
return {
'month': month,
'total_balance': totalBalance,
'available_after_reserves': availableAfterReserves,
'monthly_income': monthlyIncome,
'monthly_expenses': monthlyExpenses,
'monthly_balance': monthlyBalance,
'provisions_current_total': provisionsCurrentTotal,
'provisions_target_total': provisionsTargetTotal,
'monthly_charges_remaining_total': monthlyChargesRemainingTotal,
'monthly_transfer_remaining_total': monthlyTransferRemainingTotal,
'monthly_provision_operation_remaining_total': monthlyProvisionOperationRemainingTotal,
'scheduled_expenses_remaining_total': scheduledExpensesRemainingTotal,
'scheduled_income_remaining_total': scheduledIncomeRemainingTotal,
'scheduled_transfer_remaining_total': scheduledTransferRemainingTotal,
'scheduled_provision_remaining_total': scheduledProvisionRemainingTotal,
'scheduled_net_remaining_total': scheduledNetRemainingTotal,
'projected_month_balance': projectedMonthBalance,
'accounts': accounts.map((e) => e.toJson()).toList(),
'reconciliations_today': reconciliationsToday.map((e) => e.toJson()).toList(),
};
}
DashboardData copyWith({
String? month,
double? totalBalance,
double? availableAfterReserves,
double? monthlyIncome,
double? monthlyExpenses,
double? monthlyBalance,
double? provisionsCurrentTotal,
double? provisionsTargetTotal,
double? monthlyChargesRemainingTotal,
double? monthlyTransferRemainingTotal,
double? monthlyProvisionOperationRemainingTotal,
double? scheduledExpensesRemainingTotal,
double? scheduledIncomeRemainingTotal,
double? scheduledTransferRemainingTotal,
double? scheduledProvisionRemainingTotal,
double? scheduledNetRemainingTotal,
double? projectedMonthBalance,
List<Account>? accounts,
List<ReconciliationStatus>? reconciliationsToday,
}) {
return DashboardData(
month: month ?? this.month,
totalBalance: totalBalance ?? this.totalBalance,
availableAfterReserves: availableAfterReserves ?? this.availableAfterReserves,
monthlyIncome: monthlyIncome ?? this.monthlyIncome,
monthlyExpenses: monthlyExpenses ?? this.monthlyExpenses,
monthlyBalance: monthlyBalance ?? this.monthlyBalance,
provisionsCurrentTotal: provisionsCurrentTotal ?? this.provisionsCurrentTotal,
provisionsTargetTotal: provisionsTargetTotal ?? this.provisionsTargetTotal,
monthlyChargesRemainingTotal: monthlyChargesRemainingTotal ?? this.monthlyChargesRemainingTotal,
monthlyTransferRemainingTotal: monthlyTransferRemainingTotal ?? this.monthlyTransferRemainingTotal,
monthlyProvisionOperationRemainingTotal: monthlyProvisionOperationRemainingTotal ?? this.monthlyProvisionOperationRemainingTotal,
scheduledExpensesRemainingTotal: scheduledExpensesRemainingTotal ?? this.scheduledExpensesRemainingTotal,
scheduledIncomeRemainingTotal: scheduledIncomeRemainingTotal ?? this.scheduledIncomeRemainingTotal,
scheduledTransferRemainingTotal: scheduledTransferRemainingTotal ?? this.scheduledTransferRemainingTotal,
scheduledProvisionRemainingTotal: scheduledProvisionRemainingTotal ?? this.scheduledProvisionRemainingTotal,
scheduledNetRemainingTotal: scheduledNetRemainingTotal ?? this.scheduledNetRemainingTotal,
projectedMonthBalance: projectedMonthBalance ?? this.projectedMonthBalance,
accounts: accounts ?? this.accounts,
reconciliationsToday: reconciliationsToday ?? this.reconciliationsToday,
);
}
}
+30
View File
@@ -0,0 +1,30 @@
import 'dart:convert';
class PendingOperation {
final int id;
final String operationType;
final Map<String, dynamic> payload;
final DateTime createdAt;
final String status;
final String? error;
PendingOperation({
required this.id,
required this.operationType,
required this.payload,
required this.createdAt,
required this.status,
this.error,
});
factory PendingOperation.fromDbMap(Map<String, dynamic> map) {
return PendingOperation(
id: map['id'] as int,
operationType: map['operation_type'] as String,
payload: jsonDecode(map['payload_json'] as String) as Map<String, dynamic>,
createdAt: DateTime.parse(map['created_at'] as String),
status: map['status'] as String? ?? 'pending',
error: map['error'] as String?,
);
}
}
+120
View File
@@ -0,0 +1,120 @@
class TransactionItem {
final int id;
final String label;
final double amount;
final String type;
final int accountId;
final int? targetAccountId;
final int? categoryId;
final int? provisionId;
final DateTime date;
final String? note;
final bool isPending;
final int? localOperationId;
TransactionItem({
required this.id,
required this.label,
required this.amount,
required this.type,
required this.accountId,
required this.date,
this.targetAccountId,
this.categoryId,
this.provisionId,
this.note,
this.isPending = false,
this.localOperationId,
});
factory TransactionItem.fromJson(Map<String, dynamic> json) {
return TransactionItem(
id: json['id'] as int,
label: json['label'] as String,
amount: (json['amount'] as num? ?? 0).toDouble(),
type: json['type'] as String,
accountId: json['account_id'] as int,
targetAccountId: json['target_account_id'] as int?,
categoryId: json['category_id'] as int?,
provisionId: json['provision_id'] as int?,
date: DateTime.parse(json['date'] as String),
note: json['note'] as String?,
isPending: json['is_pending'] is int
? (json['is_pending'] as int) == 1
: json['is_pending'] as bool? ?? false,
localOperationId: json['local_operation_id'] as int?,
);
}
factory TransactionItem.fromPending({
required int localOperationId,
required Map<String, dynamic> payload,
}) {
return TransactionItem(
id: -localOperationId,
label: payload['label'] as String? ?? 'Opération mobile',
amount: (payload['amount'] as num? ?? 0).toDouble(),
type: payload['type'] as String? ?? 'expense',
accountId: payload['account_id'] as int,
targetAccountId: payload['target_account_id'] as int?,
categoryId: payload['category_id'] as int?,
provisionId: payload['provision_id'] as int?,
date: DateTime.tryParse(payload['date'] as String? ?? '') ?? DateTime.now(),
note: payload['note'] as String?,
isPending: true,
localOperationId: localOperationId,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'label': label,
'amount': amount,
'type': type,
'account_id': accountId,
'target_account_id': targetAccountId,
'category_id': categoryId,
'provision_id': provisionId,
'date': date.toIso8601String(),
'note': note,
'is_pending': isPending,
'local_operation_id': localOperationId,
};
}
Map<String, dynamic> toDbMap() {
return {
'id': id,
'label': label,
'amount': amount,
'type': type,
'account_id': accountId,
'target_account_id': targetAccountId,
'category_id': categoryId,
'provision_id': provisionId,
'date': date.toIso8601String(),
'note': note,
'is_pending': isPending ? 1 : 0,
'local_operation_id': localOperationId,
'updated_at': DateTime.now().toIso8601String(),
};
}
factory TransactionItem.fromDbMap(Map<String, dynamic> map) {
return TransactionItem(
id: map['id'] as int,
label: map['label'] as String,
amount: (map['amount'] as num? ?? 0).toDouble(),
type: map['type'] as String,
accountId: map['account_id'] as int,
targetAccountId: map['target_account_id'] as int?,
categoryId: map['category_id'] as int?,
provisionId: map['provision_id'] as int?,
date: DateTime.parse(map['date'] as String),
note: map['note'] as String?,
isPending: (map['is_pending'] as int? ?? 0) == 1,
localOperationId: map['local_operation_id'] as int?,
);
}
}