/// 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 approvers; final String? rejectionReason; final DateTime createdAt; final DateTime? expiresAt; final DateTime? completedAt; final Map? 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? approvers, String? rejectionReason, DateTime? createdAt, DateTime? expiresAt, DateTime? completedAt, Map? 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 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 get props => [ approverId, approverName, approverRole, decision, comment, decidedAt, ]; }