From db36727001d47ec37386348d6cf1d5c970eace02 Mon Sep 17 00:00:00 2001 From: dahoud <41957584+DahoudG@users.noreply.github.com> Date: Sat, 25 Apr 2026 16:47:54 +0000 Subject: [PATCH] =?UTF-8?q?feat(sprint-17=20api=202026-04-25):=20bump=201.?= =?UTF-8?q?0.10=20+=20DTO=20KpiPublicSnapshot=20pour=20partage=20KPI=20pub?= =?UTF-8?q?lic=20sign=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sous-ensemble strictement filtré de ComplianceSnapshot — vue read-only pour autorités externes (BCEAO, ARTCI, CENTIF). N'expose que les indicateurs agrégés, jamais d'informations sensibles (complianceOfficerId, payloads, IDs membres, PEP details). Champs : organisationNom, referentielComptable, scoreGlobal, complianceOfficerDesigne, agAnnuelleStatut, rapportAirmsStatut, dirigeantsAvecCmu, tauxKycAJourPct, tauxFormationLbcFtPct, couvertureUboPct, commissaireAuxComptesStatut, dateGeneration. Tests Jacoco 100% (3 tests : builder all-fields, null defaults, equals/hash/toString) ACTION USER : `mvn clean install` puis `mvn deploy` pour 1.0.10 sur Gitea. --- pom.xml | 2 +- .../response/KpiPublicSnapshot.java | 57 +++++++++++++++++ .../response/KpiPublicSnapshotTest.java | 64 +++++++++++++++++++ 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 src/main/java/dev/lions/unionflow/server/api/dto/compliance/response/KpiPublicSnapshot.java create mode 100644 src/test/java/dev/lions/unionflow/server/api/dto/compliance/response/KpiPublicSnapshotTest.java diff --git a/pom.xml b/pom.xml index 3cbd4bf..f437f7f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ dev.lions.unionflow unionflow-server-api - 1.0.9 + 1.0.10 jar UnionFlow Server API diff --git a/src/main/java/dev/lions/unionflow/server/api/dto/compliance/response/KpiPublicSnapshot.java b/src/main/java/dev/lions/unionflow/server/api/dto/compliance/response/KpiPublicSnapshot.java new file mode 100644 index 0000000..60e0ad3 --- /dev/null +++ b/src/main/java/dev/lions/unionflow/server/api/dto/compliance/response/KpiPublicSnapshot.java @@ -0,0 +1,57 @@ +package dev.lions.unionflow.server.api.dto.compliance.response; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import lombok.Builder; + +/** + * Snapshot KPI public (Sprint 17) — vue read-only pour autorités externes (BCEAO, ARTCI, CENTIF). + * + *

Sous-ensemble strictement filtré de la conformité : indicateurs agrégés uniquement, + * jamais de données sensibles ({@code complianceOfficerId}, payloads détaillés, IDs membres, + * informations PEP). L'autorité voit le score, l'état des obligations, les pourcentages + * de couverture — pas l'intimité opérationnelle. + * + *

Diffusé via URL signée temporairement (HMAC-SHA256, expiry stricte). + * + * @since 2026-04-25 (Sprint 17 — transparency réglementaire publique) + */ +@Builder +public record KpiPublicSnapshot( + /** Nom de l'organisation. */ + String organisationNom, + + /** Référentiel comptable applicable (SYSCOHADA / SYCEBNL / PCSFD_UMOA). */ + String referentielComptable, + + /** Score conformité agrégé 0-100. */ + int scoreGlobal, + + /** Compliance Officer désigné (présence uniquement, pas l'identité). */ + boolean complianceOfficerDesigne, + + /** Statut AG annuelle : OK / EN_ATTENTE / RETARD. */ + String agAnnuelleStatut, + + /** Statut rapport AIRMS : OK / EN_ATTENTE. */ + String rapportAirmsStatut, + + /** Nombre de dirigeants enrôlés CMU (sans liste). */ + int dirigeantsAvecCmu, + + /** Pourcentage KYC à jour (membres). */ + BigDecimal tauxKycAJourPct, + + /** Pourcentage formation LBC/FT (membres formés dans les 12 derniers mois). */ + BigDecimal tauxFormationLbcFtPct, + + /** Pourcentage couverture UBO (Bénéficiaires Effectifs documentés). */ + BigDecimal couvertureUboPct, + + /** Statut commissaire aux comptes (OPTIONNEL / OBLIGATOIRE). */ + String commissaireAuxComptesStatut, + + /** Date de génération du snapshot. */ + LocalDateTime dateGeneration +) { +} diff --git a/src/test/java/dev/lions/unionflow/server/api/dto/compliance/response/KpiPublicSnapshotTest.java b/src/test/java/dev/lions/unionflow/server/api/dto/compliance/response/KpiPublicSnapshotTest.java new file mode 100644 index 0000000..d694845 --- /dev/null +++ b/src/test/java/dev/lions/unionflow/server/api/dto/compliance/response/KpiPublicSnapshotTest.java @@ -0,0 +1,64 @@ +package dev.lions.unionflow.server.api.dto.compliance.response; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import org.junit.jupiter.api.Test; + +class KpiPublicSnapshotTest { + + @Test + void testBuilder_AllFields() { + LocalDateTime now = LocalDateTime.of(2026, 4, 25, 12, 0); + KpiPublicSnapshot s = KpiPublicSnapshot.builder() + .organisationNom("Mutuelle Test") + .referentielComptable("SYCEBNL") + .scoreGlobal(82) + .complianceOfficerDesigne(true) + .agAnnuelleStatut("OK") + .rapportAirmsStatut("EN_ATTENTE") + .dirigeantsAvecCmu(3) + .tauxKycAJourPct(new BigDecimal("85.5")) + .tauxFormationLbcFtPct(new BigDecimal("70.0")) + .couvertureUboPct(new BigDecimal("60.0")) + .commissaireAuxComptesStatut("OPTIONNEL") + .dateGeneration(now) + .build(); + + assertThat(s.organisationNom()).isEqualTo("Mutuelle Test"); + assertThat(s.referentielComptable()).isEqualTo("SYCEBNL"); + assertThat(s.scoreGlobal()).isEqualTo(82); + assertThat(s.complianceOfficerDesigne()).isTrue(); + assertThat(s.agAnnuelleStatut()).isEqualTo("OK"); + assertThat(s.rapportAirmsStatut()).isEqualTo("EN_ATTENTE"); + assertThat(s.dirigeantsAvecCmu()).isEqualTo(3); + assertThat(s.tauxKycAJourPct()).isEqualByComparingTo("85.5"); + assertThat(s.tauxFormationLbcFtPct()).isEqualByComparingTo("70.0"); + assertThat(s.couvertureUboPct()).isEqualByComparingTo("60.0"); + assertThat(s.commissaireAuxComptesStatut()).isEqualTo("OPTIONNEL"); + assertThat(s.dateGeneration()).isEqualTo(now); + } + + @Test + void testBuilder_NullDefaults() { + KpiPublicSnapshot empty = KpiPublicSnapshot.builder().build(); + assertThat(empty.organisationNom()).isNull(); + assertThat(empty.scoreGlobal()).isZero(); + assertThat(empty.complianceOfficerDesigne()).isFalse(); + assertThat(empty.dirigeantsAvecCmu()).isZero(); + assertThat(empty.tauxKycAJourPct()).isNull(); + } + + @Test + void testEqualsHashCodeToString() { + LocalDateTime t = LocalDateTime.of(2026, 4, 25, 10, 0); + KpiPublicSnapshot a = KpiPublicSnapshot.builder() + .organisationNom("Org").scoreGlobal(80).dateGeneration(t).build(); + KpiPublicSnapshot b = KpiPublicSnapshot.builder() + .organisationNom("Org").scoreGlobal(80).dateGeneration(t).build(); + assertThat(a).isEqualTo(b); + assertThat(a.hashCode()).isEqualTo(b.hashCode()); + assertThat(a.toString()).contains("KpiPublicSnapshot"); + } +}