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.
58 lines
2.1 KiB
Dart
58 lines
2.1 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:unionflow_mobile_apps/features/compliance/data/models/compliance_snapshot_model.dart';
|
|
|
|
void main() {
|
|
group('ComplianceSnapshotModel.fromJson', () {
|
|
test('parsing complet', () {
|
|
final json = {
|
|
'organisationId': 'org-uuid',
|
|
'organisationNom': 'Mutuelle Test',
|
|
'referentielComptable': 'SYCEBNL',
|
|
'complianceOfficerDesigne': true,
|
|
'agAnnuelle': {'statut': 'OK', 'message': 'AG tenue'},
|
|
'rapportAirms': {'statut': 'EN_ATTENTE', 'message': ''},
|
|
'dirigeantsAvecCmu': 3,
|
|
'tauxKycAJourPct': 85.5,
|
|
'tauxFormationLbcFtPct': 70.0,
|
|
'commissaireAuxComptes': {'statut': 'OBLIGATOIRE', 'message': 'SFD'},
|
|
'fomusCi': {'statut': 'EN_VEILLE', 'message': ''},
|
|
'couvertureUboPct': 60.0,
|
|
'scoreGlobal': 82,
|
|
};
|
|
final m = ComplianceSnapshotModel.fromJson(json);
|
|
expect(m.organisationNom, 'Mutuelle Test');
|
|
expect(m.referentielComptable, 'SYCEBNL');
|
|
expect(m.complianceOfficerDesigne, isTrue);
|
|
expect(m.agAnnuelle.statut, 'OK');
|
|
expect(m.dirigeantsAvecCmu, 3);
|
|
expect(m.tauxKycAJourPct, 85.5);
|
|
expect(m.scoreGlobal, 82);
|
|
});
|
|
|
|
test('valeurs manquantes → fallbacks raisonnables', () {
|
|
final m = ComplianceSnapshotModel.fromJson(<String, dynamic>{});
|
|
expect(m.organisationId, '');
|
|
expect(m.referentielComptable, 'SYSCOHADA');
|
|
expect(m.complianceOfficerDesigne, isFalse);
|
|
expect(m.agAnnuelle.statut, 'EN_VEILLE');
|
|
expect(m.dirigeantsAvecCmu, 0);
|
|
expect(m.tauxKycAJourPct, 0.0);
|
|
expect(m.scoreGlobal, 0);
|
|
});
|
|
|
|
test('taux passé en string → converti en double', () {
|
|
final m = ComplianceSnapshotModel.fromJson({
|
|
'tauxKycAJourPct': '85.5',
|
|
'couvertureUboPct': '60',
|
|
});
|
|
expect(m.tauxKycAJourPct, 85.5);
|
|
expect(m.couvertureUboPct, 60.0);
|
|
});
|
|
|
|
test('indicateur non-Map → fallback EN_VEILLE', () {
|
|
final m = ComplianceSnapshotModel.fromJson({'agAnnuelle': 'invalid'});
|
|
expect(m.agAnnuelle.statut, 'EN_VEILLE');
|
|
});
|
|
});
|
|
}
|