Initial commit: unionflow-mobile-apps
Application Flutter complète (sans build artifacts). Signed-off-by: lions dev Team
This commit is contained in:
244
lib/features/finance_workflow/domain/entities/budget.dart
Normal file
244
lib/features/finance_workflow/domain/entities/budget.dart
Normal file
@@ -0,0 +1,244 @@
|
||||
/// Entité métier Budget
|
||||
///
|
||||
/// Représente un budget prévisionnel (mensuel/annuel) avec suivi réalisé
|
||||
library budget;
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Période du budget
|
||||
enum BudgetPeriod {
|
||||
/// Budget mensuel
|
||||
monthly,
|
||||
|
||||
/// Budget trimestriel
|
||||
quarterly,
|
||||
|
||||
/// Budget semestriel
|
||||
semiannual,
|
||||
|
||||
/// Budget annuel
|
||||
annual,
|
||||
}
|
||||
|
||||
/// Statut du budget
|
||||
enum BudgetStatus {
|
||||
/// Brouillon (en cours de création)
|
||||
draft,
|
||||
|
||||
/// Actif
|
||||
active,
|
||||
|
||||
/// Clos (période terminée)
|
||||
closed,
|
||||
|
||||
/// Annulé
|
||||
cancelled,
|
||||
}
|
||||
|
||||
/// Catégorie budgétaire
|
||||
enum BudgetCategory {
|
||||
/// Cotisations/contributions
|
||||
contributions,
|
||||
|
||||
/// Épargne
|
||||
savings,
|
||||
|
||||
/// Solidarité
|
||||
solidarity,
|
||||
|
||||
/// Événements
|
||||
events,
|
||||
|
||||
/// Fonctionnement (frais généraux)
|
||||
operational,
|
||||
|
||||
/// Investissements
|
||||
investments,
|
||||
|
||||
/// Autres
|
||||
other,
|
||||
}
|
||||
|
||||
/// Entité Budget
|
||||
class Budget extends Equatable {
|
||||
final String id;
|
||||
final String name;
|
||||
final String? description;
|
||||
final String organizationId;
|
||||
final BudgetPeriod period;
|
||||
final int year;
|
||||
final int? month;
|
||||
final BudgetStatus status;
|
||||
final List<BudgetLine> lines;
|
||||
final double totalPlanned;
|
||||
final double totalRealized;
|
||||
final String currency;
|
||||
final String createdBy;
|
||||
final DateTime createdAt;
|
||||
final DateTime? approvedAt;
|
||||
final String? approvedBy;
|
||||
final DateTime startDate;
|
||||
final DateTime endDate;
|
||||
final Map<String, dynamic>? metadata;
|
||||
|
||||
const Budget({
|
||||
required this.id,
|
||||
required this.name,
|
||||
this.description,
|
||||
required this.organizationId,
|
||||
required this.period,
|
||||
required this.year,
|
||||
this.month,
|
||||
required this.status,
|
||||
this.lines = const [],
|
||||
required this.totalPlanned,
|
||||
this.totalRealized = 0,
|
||||
this.currency = 'XOF',
|
||||
required this.createdBy,
|
||||
required this.createdAt,
|
||||
this.approvedAt,
|
||||
this.approvedBy,
|
||||
required this.startDate,
|
||||
required this.endDate,
|
||||
this.metadata,
|
||||
});
|
||||
|
||||
/// Taux de réalisation (%)
|
||||
double get realizationRate {
|
||||
if (totalPlanned == 0) return 0;
|
||||
return (totalRealized / totalPlanned) * 100;
|
||||
}
|
||||
|
||||
/// Écart (réalisé - prévu)
|
||||
double get variance => totalRealized - totalPlanned;
|
||||
|
||||
/// Taux d'écart (%)
|
||||
double get varianceRate {
|
||||
if (totalPlanned == 0) return 0;
|
||||
return (variance / totalPlanned) * 100;
|
||||
}
|
||||
|
||||
/// Vérifie si le budget est dépassé
|
||||
bool get isOverBudget => totalRealized > totalPlanned;
|
||||
|
||||
/// Vérifie si le budget est actif
|
||||
bool get isActive => status == BudgetStatus.active;
|
||||
|
||||
/// Vérifie si la période est en cours
|
||||
bool get isCurrentPeriod {
|
||||
final now = DateTime.now();
|
||||
return now.isAfter(startDate) && now.isBefore(endDate);
|
||||
}
|
||||
|
||||
/// Copie avec modifications
|
||||
Budget copyWith({
|
||||
String? id,
|
||||
String? name,
|
||||
String? description,
|
||||
String? organizationId,
|
||||
BudgetPeriod? period,
|
||||
int? year,
|
||||
int? month,
|
||||
BudgetStatus? status,
|
||||
List<BudgetLine>? lines,
|
||||
double? totalPlanned,
|
||||
double? totalRealized,
|
||||
String? currency,
|
||||
String? createdBy,
|
||||
DateTime? createdAt,
|
||||
DateTime? approvedAt,
|
||||
String? approvedBy,
|
||||
DateTime? startDate,
|
||||
DateTime? endDate,
|
||||
Map<String, dynamic>? metadata,
|
||||
}) {
|
||||
return Budget(
|
||||
id: id ?? this.id,
|
||||
name: name ?? this.name,
|
||||
description: description ?? this.description,
|
||||
organizationId: organizationId ?? this.organizationId,
|
||||
period: period ?? this.period,
|
||||
year: year ?? this.year,
|
||||
month: month ?? this.month,
|
||||
status: status ?? this.status,
|
||||
lines: lines ?? this.lines,
|
||||
totalPlanned: totalPlanned ?? this.totalPlanned,
|
||||
totalRealized: totalRealized ?? this.totalRealized,
|
||||
currency: currency ?? this.currency,
|
||||
createdBy: createdBy ?? this.createdBy,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
approvedAt: approvedAt ?? this.approvedAt,
|
||||
approvedBy: approvedBy ?? this.approvedBy,
|
||||
startDate: startDate ?? this.startDate,
|
||||
endDate: endDate ?? this.endDate,
|
||||
metadata: metadata ?? this.metadata,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
organizationId,
|
||||
period,
|
||||
year,
|
||||
month,
|
||||
status,
|
||||
lines,
|
||||
totalPlanned,
|
||||
totalRealized,
|
||||
currency,
|
||||
createdBy,
|
||||
createdAt,
|
||||
approvedAt,
|
||||
approvedBy,
|
||||
startDate,
|
||||
endDate,
|
||||
metadata,
|
||||
];
|
||||
}
|
||||
|
||||
/// Ligne budgétaire
|
||||
class BudgetLine extends Equatable {
|
||||
final String id;
|
||||
final BudgetCategory category;
|
||||
final String name;
|
||||
final String? description;
|
||||
final double amountPlanned;
|
||||
final double amountRealized;
|
||||
final String? notes;
|
||||
|
||||
const BudgetLine({
|
||||
required this.id,
|
||||
required this.category,
|
||||
required this.name,
|
||||
this.description,
|
||||
required this.amountPlanned,
|
||||
this.amountRealized = 0,
|
||||
this.notes,
|
||||
});
|
||||
|
||||
/// Taux de réalisation (%)
|
||||
double get realizationRate {
|
||||
if (amountPlanned == 0) return 0;
|
||||
return (amountRealized / amountPlanned) * 100;
|
||||
}
|
||||
|
||||
/// Écart
|
||||
double get variance => amountRealized - amountPlanned;
|
||||
|
||||
/// Vérifie si la ligne est dépassée
|
||||
bool get isOverBudget => amountRealized > amountPlanned;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
category,
|
||||
name,
|
||||
description,
|
||||
amountPlanned,
|
||||
amountRealized,
|
||||
notes,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/// Entité métier Audit Log Financier
|
||||
///
|
||||
/// Représente une entrée d'audit trail pour traçabilité financière complète
|
||||
library financial_audit_log;
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Type d'opération auditée
|
||||
enum AuditOperation {
|
||||
/// Création
|
||||
create,
|
||||
|
||||
/// Lecture/consultation
|
||||
read,
|
||||
|
||||
/// Mise à jour
|
||||
update,
|
||||
|
||||
/// Suppression
|
||||
delete,
|
||||
|
||||
/// Approbation
|
||||
approve,
|
||||
|
||||
/// Rejet
|
||||
reject,
|
||||
|
||||
/// Validation
|
||||
validate,
|
||||
|
||||
/// Annulation
|
||||
cancel,
|
||||
|
||||
/// Export
|
||||
export,
|
||||
}
|
||||
|
||||
/// Type d'entité auditée
|
||||
enum AuditEntityType {
|
||||
/// Contribution/cotisation
|
||||
contribution,
|
||||
|
||||
/// Transaction épargne
|
||||
savingsTransaction,
|
||||
|
||||
/// Approbation
|
||||
approval,
|
||||
|
||||
/// Budget
|
||||
budget,
|
||||
|
||||
/// Dépense solidarité
|
||||
solidarity,
|
||||
|
||||
/// Paiement
|
||||
payment,
|
||||
|
||||
/// Autre
|
||||
other,
|
||||
}
|
||||
|
||||
/// Niveau de sévérité
|
||||
enum AuditSeverity {
|
||||
/// Information
|
||||
info,
|
||||
|
||||
/// Avertissement
|
||||
warning,
|
||||
|
||||
/// Erreur
|
||||
error,
|
||||
|
||||
/// Critique (anomalie détectée)
|
||||
critical,
|
||||
}
|
||||
|
||||
/// Entité Audit Log Financier
|
||||
class FinancialAuditLog extends Equatable {
|
||||
final String id;
|
||||
final AuditOperation operation;
|
||||
final AuditEntityType entityType;
|
||||
final String entityId;
|
||||
final String userId;
|
||||
final String userName;
|
||||
final String userRole;
|
||||
final String? organizationId;
|
||||
final AuditSeverity severity;
|
||||
final String description;
|
||||
final Map<String, dynamic>? dataBefore;
|
||||
final Map<String, dynamic>? dataAfter;
|
||||
final double? amountBefore;
|
||||
final double? amountAfter;
|
||||
final String? ipAddress;
|
||||
final String? userAgent;
|
||||
final DateTime timestamp;
|
||||
final Map<String, dynamic>? metadata;
|
||||
|
||||
const FinancialAuditLog({
|
||||
required this.id,
|
||||
required this.operation,
|
||||
required this.entityType,
|
||||
required this.entityId,
|
||||
required this.userId,
|
||||
required this.userName,
|
||||
required this.userRole,
|
||||
this.organizationId,
|
||||
this.severity = AuditSeverity.info,
|
||||
required this.description,
|
||||
this.dataBefore,
|
||||
this.dataAfter,
|
||||
this.amountBefore,
|
||||
this.amountAfter,
|
||||
this.ipAddress,
|
||||
this.userAgent,
|
||||
required this.timestamp,
|
||||
this.metadata,
|
||||
});
|
||||
|
||||
/// Vérifie si c'est une opération de modification de montant
|
||||
bool get isAmountChanged =>
|
||||
amountBefore != null &&
|
||||
amountAfter != null &&
|
||||
amountBefore != amountAfter;
|
||||
|
||||
/// Écart de montant
|
||||
double? get amountDifference {
|
||||
if (amountBefore == null || amountAfter == null) return null;
|
||||
return amountAfter! - amountBefore!;
|
||||
}
|
||||
|
||||
/// Vérifie si c'est une anomalie critique
|
||||
bool get isCritical => severity == AuditSeverity.critical;
|
||||
|
||||
/// Vérifie si c'est une opération sensible
|
||||
bool get isSensitiveOperation =>
|
||||
operation == AuditOperation.delete ||
|
||||
operation == AuditOperation.approve ||
|
||||
operation == AuditOperation.reject ||
|
||||
operation == AuditOperation.cancel;
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
operation,
|
||||
entityType,
|
||||
entityId,
|
||||
userId,
|
||||
userName,
|
||||
userRole,
|
||||
organizationId,
|
||||
severity,
|
||||
description,
|
||||
dataBefore,
|
||||
dataAfter,
|
||||
amountBefore,
|
||||
amountAfter,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
timestamp,
|
||||
metadata,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/// Entité métier Approbation Transaction
|
||||
///
|
||||
/// Représente une approbation dans le workflow financier multi-niveaux
|
||||
library transaction_approval;
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Statut de l'approbation
|
||||
enum ApprovalStatus {
|
||||
/// En attente d'approbation
|
||||
pending,
|
||||
|
||||
/// Approuvée (niveau 1)
|
||||
approved,
|
||||
|
||||
/// Validée (niveau 2 - validation finale)
|
||||
validated,
|
||||
|
||||
/// Rejetée
|
||||
rejected,
|
||||
|
||||
/// Expirée (timeout)
|
||||
expired,
|
||||
|
||||
/// Annulée
|
||||
cancelled,
|
||||
}
|
||||
|
||||
/// Niveau d'approbation requis selon montant
|
||||
enum ApprovalLevel {
|
||||
/// Aucune approbation requise (< seuil)
|
||||
none,
|
||||
|
||||
/// Niveau 1 : Un approbateur requis
|
||||
level1,
|
||||
|
||||
/// Niveau 2 : Deux approbateurs requis
|
||||
level2,
|
||||
|
||||
/// Niveau 3 : Trois approbateurs requis (montants très élevés)
|
||||
level3,
|
||||
}
|
||||
|
||||
/// Type de transaction financière
|
||||
enum TransactionType {
|
||||
/// Cotisation/contribution
|
||||
contribution,
|
||||
|
||||
/// Dépôt épargne
|
||||
deposit,
|
||||
|
||||
/// Retrait épargne
|
||||
withdrawal,
|
||||
|
||||
/// Transfert
|
||||
transfer,
|
||||
|
||||
/// Dépense solidarité
|
||||
solidarity,
|
||||
|
||||
/// Dépense événement
|
||||
event,
|
||||
|
||||
/// Autre dépense
|
||||
other,
|
||||
}
|
||||
|
||||
/// Entité Approbation de Transaction
|
||||
class TransactionApproval extends Equatable {
|
||||
final String id;
|
||||
final String transactionId;
|
||||
final TransactionType transactionType;
|
||||
final double amount;
|
||||
final String currency;
|
||||
final String requesterId;
|
||||
final String requesterName;
|
||||
final String? organizationId;
|
||||
final ApprovalLevel requiredLevel;
|
||||
final ApprovalStatus status;
|
||||
final List<ApproverAction> approvers;
|
||||
final String? rejectionReason;
|
||||
final DateTime createdAt;
|
||||
final DateTime? expiresAt;
|
||||
final DateTime? completedAt;
|
||||
final Map<String, dynamic>? metadata;
|
||||
|
||||
const TransactionApproval({
|
||||
required this.id,
|
||||
required this.transactionId,
|
||||
required this.transactionType,
|
||||
required this.amount,
|
||||
this.currency = 'XOF',
|
||||
required this.requesterId,
|
||||
required this.requesterName,
|
||||
this.organizationId,
|
||||
required this.requiredLevel,
|
||||
required this.status,
|
||||
this.approvers = const [],
|
||||
this.rejectionReason,
|
||||
required this.createdAt,
|
||||
this.expiresAt,
|
||||
this.completedAt,
|
||||
this.metadata,
|
||||
});
|
||||
|
||||
/// Vérifie si l'approbation est en attente
|
||||
bool get isPending => status == ApprovalStatus.pending;
|
||||
|
||||
/// Vérifie si l'approbation est complétée
|
||||
bool get isCompleted =>
|
||||
status == ApprovalStatus.validated ||
|
||||
status == ApprovalStatus.rejected ||
|
||||
status == ApprovalStatus.cancelled;
|
||||
|
||||
/// Vérifie si l'approbation est expirée
|
||||
bool get isExpired {
|
||||
if (expiresAt == null) return false;
|
||||
return DateTime.now().isAfter(expiresAt!);
|
||||
}
|
||||
|
||||
/// Nombre d'approbations reçues
|
||||
int get approvalCount =>
|
||||
approvers.where((a) => a.decision == ApprovalDecision.approved).length;
|
||||
|
||||
/// Nombre d'approbations requises
|
||||
int get requiredApprovals {
|
||||
switch (requiredLevel) {
|
||||
case ApprovalLevel.none:
|
||||
return 0;
|
||||
case ApprovalLevel.level1:
|
||||
return 1;
|
||||
case ApprovalLevel.level2:
|
||||
return 2;
|
||||
case ApprovalLevel.level3:
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
/// Vérifie si toutes les approbations sont reçues
|
||||
bool get hasAllApprovals => approvalCount >= requiredApprovals;
|
||||
|
||||
/// Copie avec modifications
|
||||
TransactionApproval copyWith({
|
||||
String? id,
|
||||
String? transactionId,
|
||||
TransactionType? transactionType,
|
||||
double? amount,
|
||||
String? currency,
|
||||
String? requesterId,
|
||||
String? requesterName,
|
||||
String? organizationId,
|
||||
ApprovalLevel? requiredLevel,
|
||||
ApprovalStatus? status,
|
||||
List<ApproverAction>? approvers,
|
||||
String? rejectionReason,
|
||||
DateTime? createdAt,
|
||||
DateTime? expiresAt,
|
||||
DateTime? completedAt,
|
||||
Map<String, dynamic>? metadata,
|
||||
}) {
|
||||
return TransactionApproval(
|
||||
id: id ?? this.id,
|
||||
transactionId: transactionId ?? this.transactionId,
|
||||
transactionType: transactionType ?? this.transactionType,
|
||||
amount: amount ?? this.amount,
|
||||
currency: currency ?? this.currency,
|
||||
requesterId: requesterId ?? this.requesterId,
|
||||
requesterName: requesterName ?? this.requesterName,
|
||||
organizationId: organizationId ?? this.organizationId,
|
||||
requiredLevel: requiredLevel ?? this.requiredLevel,
|
||||
status: status ?? this.status,
|
||||
approvers: approvers ?? this.approvers,
|
||||
rejectionReason: rejectionReason ?? this.rejectionReason,
|
||||
createdAt: createdAt ?? this.createdAt,
|
||||
expiresAt: expiresAt ?? this.expiresAt,
|
||||
completedAt: completedAt ?? this.completedAt,
|
||||
metadata: metadata ?? this.metadata,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
id,
|
||||
transactionId,
|
||||
transactionType,
|
||||
amount,
|
||||
currency,
|
||||
requesterId,
|
||||
requesterName,
|
||||
organizationId,
|
||||
requiredLevel,
|
||||
status,
|
||||
approvers,
|
||||
rejectionReason,
|
||||
createdAt,
|
||||
expiresAt,
|
||||
completedAt,
|
||||
metadata,
|
||||
];
|
||||
}
|
||||
|
||||
/// Décision d'un approbateur
|
||||
enum ApprovalDecision {
|
||||
/// En attente
|
||||
pending,
|
||||
|
||||
/// Approuvé
|
||||
approved,
|
||||
|
||||
/// Rejeté
|
||||
rejected,
|
||||
}
|
||||
|
||||
/// Action d'un approbateur
|
||||
class ApproverAction extends Equatable {
|
||||
final String approverId;
|
||||
final String approverName;
|
||||
final String approverRole;
|
||||
final ApprovalDecision decision;
|
||||
final String? comment;
|
||||
final DateTime? decidedAt;
|
||||
|
||||
const ApproverAction({
|
||||
required this.approverId,
|
||||
required this.approverName,
|
||||
required this.approverRole,
|
||||
required this.decision,
|
||||
this.comment,
|
||||
this.decidedAt,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
approverId,
|
||||
approverName,
|
||||
approverRole,
|
||||
decision,
|
||||
comment,
|
||||
decidedAt,
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user