package dev.lions.unionflow.server.entity; import dev.lions.unionflow.server.api.enums.comptabilite.TypeJournalComptable; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.lang.reflect.Method; import java.math.BigDecimal; import java.time.LocalDate; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThat; @DisplayName("EcritureComptable") class EcritureComptableTest { private static JournalComptable newJournal() { JournalComptable j = new JournalComptable(); j.setId(UUID.randomUUID()); j.setCode("BQ"); j.setLibelle("Banque"); j.setTypeJournal(TypeJournalComptable.BANQUE); return j; } @Test @DisplayName("getters/setters") void gettersSetters() { EcritureComptable e = new EcritureComptable(); e.setNumeroPiece("ECR-001"); e.setDateEcriture(LocalDate.now()); e.setLibelle("Virement"); e.setReference("REF-1"); e.setLettrage("L1"); e.setPointe(true); e.setMontantDebit(new BigDecimal("100.00")); e.setMontantCredit(new BigDecimal("100.00")); e.setJournal(newJournal()); assertThat(e.getNumeroPiece()).isEqualTo("ECR-001"); assertThat(e.getLibelle()).isEqualTo("Virement"); assertThat(e.getMontantDebit()).isEqualByComparingTo("100.00"); assertThat(e.getMontantCredit()).isEqualByComparingTo("100.00"); assertThat(e.getPointe()).isTrue(); } @Test @DisplayName("isEquilibree: true si débit = crédit") void isEquilibree() { EcritureComptable e = new EcritureComptable(); e.setJournal(newJournal()); e.setNumeroPiece("X"); e.setDateEcriture(LocalDate.now()); e.setLibelle("L"); e.setMontantDebit(new BigDecimal("50.00")); e.setMontantCredit(new BigDecimal("50.00")); assertThat(e.isEquilibree()).isTrue(); e.setMontantCredit(new BigDecimal("60.00")); assertThat(e.isEquilibree()).isFalse(); e.setMontantDebit(null); assertThat(e.isEquilibree()).isFalse(); } @Test @DisplayName("calculerTotaux: à partir des lignes") void calculerTotaux() { JournalComptable j = newJournal(); EcritureComptable e = new EcritureComptable(); e.setJournal(j); e.setNumeroPiece("X"); e.setDateEcriture(LocalDate.now()); e.setLibelle("L"); e.setMontantDebit(BigDecimal.ZERO); e.setMontantCredit(BigDecimal.ZERO); LigneEcriture l1 = new LigneEcriture(); l1.setMontantDebit(new BigDecimal("100")); l1.setMontantCredit(BigDecimal.ZERO); LigneEcriture l2 = new LigneEcriture(); l2.setMontantDebit(BigDecimal.ZERO); l2.setMontantCredit(new BigDecimal("100")); e.getLignes().add(l1); e.getLignes().add(l2); e.calculerTotaux(); assertThat(e.getMontantDebit()).isEqualByComparingTo("100"); assertThat(e.getMontantCredit()).isEqualByComparingTo("100"); } @Test @DisplayName("genererNumeroPiece") void genererNumeroPiece() { String num = EcritureComptable.genererNumeroPiece("ECR", LocalDate.of(2025, 3, 15)); assertThat(num).startsWith("ECR-20250315-"); } @Test @DisplayName("equals et hashCode") void equalsHashCode() { UUID id = UUID.randomUUID(); JournalComptable j = newJournal(); EcritureComptable a = new EcritureComptable(); a.setId(id); a.setNumeroPiece("N1"); a.setDateEcriture(LocalDate.now()); a.setLibelle("L"); a.setJournal(j); EcritureComptable b = new EcritureComptable(); b.setId(id); b.setNumeroPiece("N1"); b.setDateEcriture(a.getDateEcriture()); b.setLibelle("L"); b.setJournal(j); assertThat(a).isEqualTo(b); assertThat(a.hashCode()).isEqualTo(b.hashCode()); } @Test @DisplayName("toString non null") void toString_nonNull() { EcritureComptable e = new EcritureComptable(); e.setNumeroPiece("X"); e.setDateEcriture(LocalDate.now()); e.setLibelle("L"); e.setJournal(newJournal()); assertThat(e.toString()).isNotNull().isNotEmpty(); } @Test @DisplayName("onUpdate (PreUpdate) calcule les totaux via réflexion") void onUpdate_calculesTotaux() throws Exception { EcritureComptable e = new EcritureComptable(); e.setNumeroPiece("X"); e.setDateEcriture(LocalDate.now()); e.setLibelle("L"); e.setJournal(newJournal()); e.setMontantDebit(BigDecimal.ZERO); e.setMontantCredit(BigDecimal.ZERO); LigneEcriture l1 = new LigneEcriture(); l1.setMontantDebit(new BigDecimal("200")); l1.setMontantCredit(BigDecimal.ZERO); LigneEcriture l2 = new LigneEcriture(); l2.setMontantDebit(BigDecimal.ZERO); l2.setMontantCredit(new BigDecimal("200")); e.getLignes().add(l1); e.getLignes().add(l2); Method onUpdate = EcritureComptable.class.getDeclaredMethod("onUpdate"); onUpdate.setAccessible(true); onUpdate.invoke(e); assertThat(e.getMontantDebit()).isEqualByComparingTo("200"); assertThat(e.getMontantCredit()).isEqualByComparingTo("200"); } @Test @DisplayName("onCreate: initialise les défauts si null") void onCreate_setsDefaults() throws Exception { EcritureComptable e = new EcritureComptable(); e.setNumeroPiece(null); e.setDateEcriture(null); e.setMontantDebit(null); e.setMontantCredit(null); e.setPointe(null); Method onCreate = EcritureComptable.class.getDeclaredMethod("onCreate"); onCreate.setAccessible(true); onCreate.invoke(e); assertThat(e.getNumeroPiece()).isNotNull().startsWith("ECR-"); assertThat(e.getDateEcriture()).isEqualTo(LocalDate.now()); assertThat(e.getMontantDebit()).isEqualByComparingTo(BigDecimal.ZERO); assertThat(e.getMontantCredit()).isEqualByComparingTo(BigDecimal.ZERO); assertThat(e.getPointe()).isFalse(); } @Test @DisplayName("onCreate: numeroPiece vide → généré") void onCreate_numeroPieceEmpty_generated() throws Exception { EcritureComptable e = new EcritureComptable(); e.setNumeroPiece(""); e.setDateEcriture(LocalDate.of(2025, 6, 1)); Method onCreate = EcritureComptable.class.getDeclaredMethod("onCreate"); onCreate.setAccessible(true); onCreate.invoke(e); assertThat(e.getNumeroPiece()).isNotEmpty().startsWith("ECR-20250601-"); } @Test @DisplayName("onCreate: avec lignes → calculerTotaux appelé") void onCreate_withLignes_calculesTotaux() throws Exception { EcritureComptable e = new EcritureComptable(); e.setNumeroPiece("X"); e.setDateEcriture(LocalDate.now()); LigneEcriture l1 = new LigneEcriture(); l1.setMontantDebit(new BigDecimal("300")); l1.setMontantCredit(BigDecimal.ZERO); LigneEcriture l2 = new LigneEcriture(); l2.setMontantDebit(BigDecimal.ZERO); l2.setMontantCredit(new BigDecimal("300")); e.getLignes().add(l1); e.getLignes().add(l2); Method onCreate = EcritureComptable.class.getDeclaredMethod("onCreate"); onCreate.setAccessible(true); onCreate.invoke(e); assertThat(e.getMontantDebit()).isEqualByComparingTo("300"); assertThat(e.getMontantCredit()).isEqualByComparingTo("300"); } @Test @DisplayName("isEquilibree: false si montantCredit null (branche ||)") void isEquilibree_montantCreditNull_returnsFalse() { // montantDebit non null mais montantCredit null → retourne false EcritureComptable e = new EcritureComptable(); e.setJournal(newJournal()); e.setNumeroPiece("X"); e.setDateEcriture(LocalDate.now()); e.setLibelle("L"); e.setMontantDebit(new BigDecimal("100.00")); e.setMontantCredit(null); assertThat(e.isEquilibree()).isFalse(); } @Test @DisplayName("calculerTotaux: lignes vides → totaux à ZERO") void calculerTotaux_emptyLignes_setsZero() { // Couvre la branche : `if (lignes == null || lignes.isEmpty()) { return ZERO; }` EcritureComptable e = new EcritureComptable(); e.setJournal(newJournal()); e.setNumeroPiece("X"); e.setDateEcriture(LocalDate.now()); e.setLibelle("L"); e.setMontantDebit(new BigDecimal("500.00")); e.setMontantCredit(new BigDecimal("500.00")); // lignes est vide (défaut) e.calculerTotaux(); assertThat(e.getMontantDebit()).isEqualByComparingTo(BigDecimal.ZERO); assertThat(e.getMontantCredit()).isEqualByComparingTo(BigDecimal.ZERO); } @Test @DisplayName("onCreate: lignes non vides présentes → calculerTotaux() appelé (branche true)") void onCreate_lignesNonVides_calculeTotaux() throws Exception { // Couvre la branche `if (lignes != null && !lignes.isEmpty())` → true dans onCreate // Ce test est complémentaire à onCreate_withLignes_calculesTotaux pour s'assurer // que le chemin est bien couvert. EcritureComptable e = new EcritureComptable(); e.setNumeroPiece("PIECE-001"); e.setDateEcriture(LocalDate.now()); e.setLibelle("Test"); LigneEcriture l1 = new LigneEcriture(); l1.setMontantDebit(new BigDecimal("75")); l1.setMontantCredit(BigDecimal.ZERO); LigneEcriture l2 = new LigneEcriture(); l2.setMontantDebit(BigDecimal.ZERO); l2.setMontantCredit(new BigDecimal("75")); e.getLignes().add(l1); e.getLignes().add(l2); Method onCreate = EcritureComptable.class.getDeclaredMethod("onCreate"); onCreate.setAccessible(true); onCreate.invoke(e); assertThat(e.getMontantDebit()).isEqualByComparingTo("75"); assertThat(e.getMontantCredit()).isEqualByComparingTo("75"); // numeroPiece déjà défini → conservé (branche false du if numeroPiece) assertThat(e.getNumeroPiece()).isEqualTo("PIECE-001"); } @Test @DisplayName("calculerTotaux: lignes == null → totaux à ZERO (branche lignes null)") void calculerTotaux_nullLignes_setsZero() throws Exception { EcritureComptable e = new EcritureComptable(); e.setNumeroPiece("X"); e.setDateEcriture(LocalDate.now()); e.setLibelle("L"); e.setMontantDebit(new BigDecimal("999")); e.setMontantCredit(new BigDecimal("999")); // Forcer lignes à null via réflexion java.lang.reflect.Field lignesField = EcritureComptable.class.getDeclaredField("lignes"); lignesField.setAccessible(true); lignesField.set(e, null); e.calculerTotaux(); assertThat(e.getMontantDebit()).isEqualByComparingTo(BigDecimal.ZERO); assertThat(e.getMontantCredit()).isEqualByComparingTo(BigDecimal.ZERO); } @Test @DisplayName("onCreate: lignes != null et isEmpty → calculerTotaux NON appelé (branche false)") void onCreate_lignesEmptyList_calculerTotauxNotCalled() throws Exception { EcritureComptable e = new EcritureComptable(); e.setNumeroPiece("X"); e.setDateEcriture(LocalDate.now()); e.setLibelle("L"); e.setMontantDebit(new BigDecimal("10")); e.setMontantCredit(new BigDecimal("10")); // lignes est une ArrayList vide (valeur par défaut) → lignes != null && !lignes.isEmpty() → false assertThat(e.getLignes()).isEmpty(); Method onCreate = EcritureComptable.class.getDeclaredMethod("onCreate"); onCreate.setAccessible(true); onCreate.invoke(e); // calculerTotaux n'a pas été appelé → montants restent (ou reset à 0 par init) // but montantDebit/Credit were already set, and they won't be recalculated // Just verify no exception and onCreate ran assertThat(e.getNumeroPiece()).isEqualTo("X"); } @Test @DisplayName("onCreate: numeroPiece vide ('') → génère un nouveau numeroPiece (branche isEmpty() true)") void onCreate_numeroPieceEmpty_generatesPiece() throws Exception { EcritureComptable e = new EcritureComptable(); e.setNumeroPiece(""); // non-null mais vide → isEmpty() true → génère e.setDateEcriture(LocalDate.now()); // non-null → ternaire true e.setLibelle("L"); e.setMontantDebit(new BigDecimal("10")); e.setMontantCredit(new BigDecimal("10")); Method onCreate = EcritureComptable.class.getDeclaredMethod("onCreate"); onCreate.setAccessible(true); onCreate.invoke(e); // numeroPiece était vide → a été généré assertThat(e.getNumeroPiece()).isNotEmpty(); assertThat(e.getNumeroPiece()).startsWith("ECR"); } @Test @DisplayName("calculerTotaux: filtre les montants null (branch false des lambdas filter)") void calculerTotaux_withNullAmounts() { EcritureComptable e = new EcritureComptable(); e.setNumeroPiece("X"); e.setDateEcriture(LocalDate.now()); e.setLibelle("L"); // Ligne avec montants null → filtrée (couvre branch false: amount != null → false) LigneEcriture l1 = new LigneEcriture(); l1.setMontantDebit(null); l1.setMontantCredit(null); LigneEcriture l2 = new LigneEcriture(); l2.setMontantDebit(new BigDecimal("50")); l2.setMontantCredit(new BigDecimal("50")); e.getLignes().add(l1); e.getLignes().add(l2); e.calculerTotaux(); assertThat(e.getMontantDebit()).isEqualByComparingTo("50"); assertThat(e.getMontantCredit()).isEqualByComparingTo("50"); } }