Apporte aux compliance officers et controleurs internes l'accès mobile au tableau de bord de conformité backend (P1-NEW-7). Et prépare la diaspora avec Devise enum + sélecteur préférence persisté. Feature Compliance (Clean Architecture) - Domain : ComplianceSnapshot + ConformiteIndicateur (Equatable), helpers scoreSeverite + hasAlertesCritiques - Data : ComplianceSnapshotModel.fromJson (parsing tolerant aux nullables), ComplianceRemoteDataSourceImpl Dio (GET /api/compliance/dashboard), ComplianceRepositoryImpl @Injectable - Presentation : ComplianceBloc (Load/Refresh events, Initial/Loading/Loaded/Error states), ConformiteDashboardPage (Material 3, ScoreCard 0-100 colorée, 9 IndicateurTile, AlertesCard rouge si critiques) Feature Devise - Devise enum (10 valeurs miroirs backend, code/libelle/zone) - fromCode tolérant casse + null/vide → XOF - estInternationale pour AML - DeviseSelector widget DropdownButtonFormField + readPreferred/writePreferred via FlutterSecureStorage (clé unionflow.devise.preferee) Tests (17/17 verts) - ComplianceSnapshot : 7 tests (scoreSeverite × 3, hasAlertesCritiques × 4) - ComplianceSnapshotModel.fromJson : 4 tests (complet, fallbacks, string→double, indicateur invalide) - Devise enum : 6 tests (reference, fromCode parse, fromCode null/inconnu, estInternationale × 2, intégrité valeurs) Note : feature reporting trimestriel mobile (PDF viewer + bloc liste) reportée à un sprint dédié — nécessite intégration pdf viewer + cache local non triviale.
54 lines
2.1 KiB
Dart
54 lines
2.1 KiB
Dart
import '../../domain/entities/compliance_snapshot.dart';
|
|
|
|
class ComplianceSnapshotModel extends ComplianceSnapshot {
|
|
const ComplianceSnapshotModel({
|
|
required super.organisationId,
|
|
required super.organisationNom,
|
|
required super.referentielComptable,
|
|
required super.complianceOfficerDesigne,
|
|
required super.agAnnuelle,
|
|
required super.rapportAirms,
|
|
required super.dirigeantsAvecCmu,
|
|
required super.tauxKycAJourPct,
|
|
required super.tauxFormationLbcFtPct,
|
|
required super.commissaireAuxComptes,
|
|
required super.fomusCi,
|
|
required super.couvertureUboPct,
|
|
required super.scoreGlobal,
|
|
});
|
|
|
|
factory ComplianceSnapshotModel.fromJson(Map<String, dynamic> json) {
|
|
return ComplianceSnapshotModel(
|
|
organisationId: json['organisationId']?.toString() ?? '',
|
|
organisationNom: json['organisationNom']?.toString() ?? '',
|
|
referentielComptable: json['referentielComptable']?.toString() ?? 'SYSCOHADA',
|
|
complianceOfficerDesigne: json['complianceOfficerDesigne'] as bool? ?? false,
|
|
agAnnuelle: _indicateur(json['agAnnuelle']),
|
|
rapportAirms: _indicateur(json['rapportAirms']),
|
|
dirigeantsAvecCmu: (json['dirigeantsAvecCmu'] as num?)?.toInt() ?? 0,
|
|
tauxKycAJourPct: _toDouble(json['tauxKycAJourPct']),
|
|
tauxFormationLbcFtPct: _toDouble(json['tauxFormationLbcFtPct']),
|
|
commissaireAuxComptes: _indicateur(json['commissaireAuxComptes']),
|
|
fomusCi: _indicateur(json['fomusCi']),
|
|
couvertureUboPct: _toDouble(json['couvertureUboPct']),
|
|
scoreGlobal: (json['scoreGlobal'] as num?)?.toInt() ?? 0,
|
|
);
|
|
}
|
|
|
|
static ConformiteIndicateur _indicateur(dynamic raw) {
|
|
if (raw is Map<String, dynamic>) {
|
|
return ConformiteIndicateur(
|
|
statut: raw['statut']?.toString() ?? 'EN_VEILLE',
|
|
message: raw['message']?.toString() ?? '',
|
|
);
|
|
}
|
|
return const ConformiteIndicateur(statut: 'EN_VEILLE', message: '');
|
|
}
|
|
|
|
static double _toDouble(dynamic raw) {
|
|
if (raw is num) return raw.toDouble();
|
|
if (raw is String) return double.tryParse(raw) ?? 0.0;
|
|
return 0.0;
|
|
}
|
|
}
|