test: couverture Messaging + Versement + ContactPolicy + MemberBlock
Tests unitaires pour les nouveaux modules : - Entity tests : ContactPolicyTest, ConversationParticipantTest, MemberBlockTest, VersementTest, VersementObjetTest - Repository tests : ContactPolicyRepositoryTest, ConversationParticipantRepositoryTest, MemberBlockRepositoryTest, VersementRepositoryTest - Resource tests : MessagingResourceTest, VersementResourceTest - Service tests : MessagingServiceTest, VersementServiceTest
This commit is contained in:
@@ -0,0 +1,109 @@
|
|||||||
|
package dev.lions.unionflow.server.entity;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.enums.messagerie.TypePolitiqueCommunication;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@DisplayName("ContactPolicy")
|
||||||
|
class ContactPolicyTest {
|
||||||
|
|
||||||
|
private static Organisation newOrg() {
|
||||||
|
Organisation org = new Organisation();
|
||||||
|
org.setId(UUID.randomUUID());
|
||||||
|
org.setNom("Org Test");
|
||||||
|
return org;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getters/setters — tous les champs")
|
||||||
|
void gettersSetters() {
|
||||||
|
ContactPolicy policy = new ContactPolicy();
|
||||||
|
Organisation org = newOrg();
|
||||||
|
policy.setOrganisation(org);
|
||||||
|
policy.setTypePolitique(TypePolitiqueCommunication.BUREAU_SEULEMENT);
|
||||||
|
policy.setAutoriserMembreVersMembre(false);
|
||||||
|
policy.setAutoriserMembreVersRole(true);
|
||||||
|
policy.setAutoriserNotesVocales(false);
|
||||||
|
|
||||||
|
assertThat(policy.getOrganisation()).isEqualTo(org);
|
||||||
|
assertThat(policy.getTypePolitique()).isEqualTo(TypePolitiqueCommunication.BUREAU_SEULEMENT);
|
||||||
|
assertThat(policy.getAutoriserMembreVersMembre()).isFalse();
|
||||||
|
assertThat(policy.getAutoriserMembreVersRole()).isTrue();
|
||||||
|
assertThat(policy.getAutoriserNotesVocales()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("onCreate — valeurs par défaut : OUVERT, tout à true")
|
||||||
|
void onCreate_defaults() {
|
||||||
|
ContactPolicy policy = new ContactPolicy();
|
||||||
|
policy.setOrganisation(newOrg());
|
||||||
|
|
||||||
|
policy.onCreate();
|
||||||
|
|
||||||
|
assertThat(policy.getTypePolitique()).isEqualTo(TypePolitiqueCommunication.OUVERT);
|
||||||
|
assertThat(policy.getAutoriserMembreVersMembre()).isTrue();
|
||||||
|
assertThat(policy.getAutoriserMembreVersRole()).isTrue();
|
||||||
|
assertThat(policy.getAutoriserNotesVocales()).isTrue();
|
||||||
|
assertThat(policy.getDateCreation()).isNotNull();
|
||||||
|
assertThat(policy.getActif()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("onCreate — ne remplace pas les valeurs existantes")
|
||||||
|
void onCreate_preservesExisting() {
|
||||||
|
ContactPolicy policy = new ContactPolicy();
|
||||||
|
policy.setOrganisation(newOrg());
|
||||||
|
policy.setTypePolitique(TypePolitiqueCommunication.GROUPES_INTERNES);
|
||||||
|
policy.setAutoriserNotesVocales(false);
|
||||||
|
|
||||||
|
policy.onCreate();
|
||||||
|
|
||||||
|
assertThat(policy.getTypePolitique()).isEqualTo(TypePolitiqueCommunication.GROUPES_INTERNES);
|
||||||
|
assertThat(policy.getAutoriserNotesVocales()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("builder — tous les champs")
|
||||||
|
void builder_allFields() {
|
||||||
|
Organisation org = newOrg();
|
||||||
|
ContactPolicy policy = ContactPolicy.builder()
|
||||||
|
.organisation(org)
|
||||||
|
.typePolitique(TypePolitiqueCommunication.OUVERT)
|
||||||
|
.autoriserMembreVersMembre(true)
|
||||||
|
.autoriserMembreVersRole(true)
|
||||||
|
.autoriserNotesVocales(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(policy.getOrganisation()).isEqualTo(org);
|
||||||
|
assertThat(policy.getTypePolitique()).isEqualTo(TypePolitiqueCommunication.OUVERT);
|
||||||
|
assertThat(policy.getAutoriserNotesVocales()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("equals et hashCode")
|
||||||
|
void equalsHashCode() {
|
||||||
|
UUID id = UUID.randomUUID();
|
||||||
|
Organisation org = newOrg();
|
||||||
|
|
||||||
|
ContactPolicy a = ContactPolicy.builder().organisation(org)
|
||||||
|
.typePolitique(TypePolitiqueCommunication.OUVERT).build();
|
||||||
|
a.setId(id);
|
||||||
|
ContactPolicy b = ContactPolicy.builder().organisation(org)
|
||||||
|
.typePolitique(TypePolitiqueCommunication.OUVERT).build();
|
||||||
|
b.setId(id);
|
||||||
|
|
||||||
|
assertThat(a).isEqualTo(b);
|
||||||
|
assertThat(a.hashCode()).isEqualTo(b.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toString non null")
|
||||||
|
void toString_nonNull() {
|
||||||
|
ContactPolicy policy = ContactPolicy.builder().organisation(newOrg()).build();
|
||||||
|
assertThat(policy.toString()).isNotNull().isNotEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
package dev.lions.unionflow.server.entity;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.enums.messagerie.StatutConversation;
|
||||||
|
import dev.lions.unionflow.server.api.enums.messagerie.TypeConversation;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@DisplayName("ConversationParticipant")
|
||||||
|
class ConversationParticipantTest {
|
||||||
|
|
||||||
|
private static Membre newMembre() {
|
||||||
|
Membre m = new Membre();
|
||||||
|
m.setId(UUID.randomUUID());
|
||||||
|
m.setNumeroMembre("M1");
|
||||||
|
m.setPrenom("Alpha");
|
||||||
|
m.setNom("Diallo");
|
||||||
|
m.setEmail("alpha@test.com");
|
||||||
|
m.setDateNaissance(LocalDate.now());
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Conversation newConversation() {
|
||||||
|
Organisation org = new Organisation();
|
||||||
|
org.setId(UUID.randomUUID());
|
||||||
|
org.setNom("Org Test");
|
||||||
|
Conversation c = new Conversation();
|
||||||
|
c.setId(UUID.randomUUID());
|
||||||
|
c.setOrganisation(org);
|
||||||
|
c.setTypeConversation(TypeConversation.DIRECTE);
|
||||||
|
c.setStatut(StatutConversation.ACTIVE);
|
||||||
|
c.setNombreMessages(0);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getters/setters")
|
||||||
|
void gettersSetters() {
|
||||||
|
ConversationParticipant p = new ConversationParticipant();
|
||||||
|
Conversation conv = newConversation();
|
||||||
|
Membre membre = newMembre();
|
||||||
|
p.setConversation(conv);
|
||||||
|
p.setMembre(membre);
|
||||||
|
p.setRoleDansConversation("INITIATEUR");
|
||||||
|
p.setNotifier(true);
|
||||||
|
|
||||||
|
assertThat(p.getConversation()).isEqualTo(conv);
|
||||||
|
assertThat(p.getMembre()).isEqualTo(membre);
|
||||||
|
assertThat(p.getRoleDansConversation()).isEqualTo("INITIATEUR");
|
||||||
|
assertThat(p.getNotifier()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("estInitiateur — INITIATEUR → true")
|
||||||
|
void estInitiateur_true() {
|
||||||
|
ConversationParticipant p = buildMinimal("INITIATEUR");
|
||||||
|
assertThat(p.estInitiateur()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("estInitiateur — PARTICIPANT → false")
|
||||||
|
void estInitiateur_false() {
|
||||||
|
ConversationParticipant p = buildMinimal("PARTICIPANT");
|
||||||
|
assertThat(p.estInitiateur()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("marquerLu — luJusqua mis à jour")
|
||||||
|
void marquerLu() {
|
||||||
|
ConversationParticipant p = buildMinimal("PARTICIPANT");
|
||||||
|
p.setLuJusqua(null);
|
||||||
|
p.marquerLu();
|
||||||
|
assertThat(p.getLuJusqua()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("marquerLu — luJusqua remplace l'ancien")
|
||||||
|
void marquerLu_replaceOld() {
|
||||||
|
ConversationParticipant p = buildMinimal("PARTICIPANT");
|
||||||
|
LocalDateTime old = LocalDateTime.now().minusDays(1);
|
||||||
|
p.setLuJusqua(old);
|
||||||
|
p.marquerLu();
|
||||||
|
assertThat(p.getLuJusqua()).isAfter(old);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("builder — valeurs par défaut")
|
||||||
|
void builder_defaults() {
|
||||||
|
ConversationParticipant p = ConversationParticipant.builder()
|
||||||
|
.conversation(newConversation())
|
||||||
|
.membre(newMembre())
|
||||||
|
.build();
|
||||||
|
assertThat(p.getRoleDansConversation()).isEqualTo("PARTICIPANT");
|
||||||
|
assertThat(p.getNotifier()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("equals et hashCode")
|
||||||
|
void equalsHashCode() {
|
||||||
|
UUID id = UUID.randomUUID();
|
||||||
|
ConversationParticipant a = buildMinimal("PARTICIPANT");
|
||||||
|
a.setId(id);
|
||||||
|
ConversationParticipant b = buildMinimal("PARTICIPANT");
|
||||||
|
b.setId(id);
|
||||||
|
assertThat(a).isEqualTo(b);
|
||||||
|
assertThat(a.hashCode()).isEqualTo(b.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toString non null")
|
||||||
|
void toString_nonNull() {
|
||||||
|
assertThat(buildMinimal("PARTICIPANT").toString()).isNotNull().isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConversationParticipant buildMinimal(String role) {
|
||||||
|
ConversationParticipant p = new ConversationParticipant();
|
||||||
|
p.setConversation(newConversation());
|
||||||
|
p.setMembre(newMembre());
|
||||||
|
p.setRoleDansConversation(role);
|
||||||
|
p.setNotifier(true);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package dev.lions.unionflow.server.entity;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@DisplayName("MemberBlock")
|
||||||
|
class MemberBlockTest {
|
||||||
|
|
||||||
|
private static Membre newMembre(String email) {
|
||||||
|
Membre m = new Membre();
|
||||||
|
m.setId(UUID.randomUUID());
|
||||||
|
m.setNumeroMembre("M-" + UUID.randomUUID().toString().substring(0, 4));
|
||||||
|
m.setPrenom("Test");
|
||||||
|
m.setNom("User");
|
||||||
|
m.setEmail(email);
|
||||||
|
m.setDateNaissance(LocalDate.now());
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Organisation newOrg() {
|
||||||
|
Organisation org = new Organisation();
|
||||||
|
org.setId(UUID.randomUUID());
|
||||||
|
org.setNom("Org Test");
|
||||||
|
return org;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getters/setters")
|
||||||
|
void gettersSetters() {
|
||||||
|
Membre bloqueur = newMembre("bloqueur@test.com");
|
||||||
|
Membre bloque = newMembre("bloque@test.com");
|
||||||
|
Organisation org = newOrg();
|
||||||
|
|
||||||
|
MemberBlock block = new MemberBlock();
|
||||||
|
block.setBloqueur(bloqueur);
|
||||||
|
block.setBloque(bloque);
|
||||||
|
block.setOrganisation(org);
|
||||||
|
|
||||||
|
assertThat(block.getBloqueur()).isEqualTo(bloqueur);
|
||||||
|
assertThat(block.getBloque()).isEqualTo(bloque);
|
||||||
|
assertThat(block.getOrganisation()).isEqualTo(org);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("builder — tous les champs")
|
||||||
|
void builder_allFields() {
|
||||||
|
Membre bloqueur = newMembre("a@test.com");
|
||||||
|
Membre bloque = newMembre("b@test.com");
|
||||||
|
Organisation org = newOrg();
|
||||||
|
|
||||||
|
MemberBlock block = MemberBlock.builder()
|
||||||
|
.bloqueur(bloqueur)
|
||||||
|
.bloque(bloque)
|
||||||
|
.organisation(org)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(block.getBloqueur()).isEqualTo(bloqueur);
|
||||||
|
assertThat(block.getBloque()).isEqualTo(bloque);
|
||||||
|
assertThat(block.getOrganisation()).isEqualTo(org);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("equals et hashCode")
|
||||||
|
void equalsHashCode() {
|
||||||
|
UUID id = UUID.randomUUID();
|
||||||
|
Membre bloqueur = newMembre("a@test.com");
|
||||||
|
Membre bloque = newMembre("b@test.com");
|
||||||
|
Organisation org = newOrg();
|
||||||
|
|
||||||
|
MemberBlock a = MemberBlock.builder().bloqueur(bloqueur).bloque(bloque).organisation(org).build();
|
||||||
|
a.setId(id);
|
||||||
|
MemberBlock b = MemberBlock.builder().bloqueur(bloqueur).bloque(bloque).organisation(org).build();
|
||||||
|
b.setId(id);
|
||||||
|
|
||||||
|
assertThat(a).isEqualTo(b);
|
||||||
|
assertThat(a.hashCode()).isEqualTo(b.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toString non null")
|
||||||
|
void toString_nonNull() {
|
||||||
|
MemberBlock block = MemberBlock.builder()
|
||||||
|
.bloqueur(newMembre("a@test.com"))
|
||||||
|
.bloque(newMembre("b@test.com"))
|
||||||
|
.organisation(newOrg())
|
||||||
|
.build();
|
||||||
|
assertThat(block.toString()).isNotNull().isNotEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package dev.lions.unionflow.server.entity;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@DisplayName("VersementObjet")
|
||||||
|
class VersementObjetTest {
|
||||||
|
|
||||||
|
private static Versement newVersement() {
|
||||||
|
Membre m = new Membre();
|
||||||
|
m.setId(UUID.randomUUID());
|
||||||
|
m.setNumeroMembre("M1");
|
||||||
|
m.setPrenom("A");
|
||||||
|
m.setNom("B");
|
||||||
|
m.setEmail("a@test.com");
|
||||||
|
m.setDateNaissance(java.time.LocalDate.now());
|
||||||
|
Versement v = new Versement();
|
||||||
|
v.setId(UUID.randomUUID());
|
||||||
|
v.setNumeroReference("VRS-2026-001");
|
||||||
|
v.setMontant(BigDecimal.TEN);
|
||||||
|
v.setCodeDevise("XOF");
|
||||||
|
v.setMethodePaiement("WAVE");
|
||||||
|
v.setMembre(m);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getters/setters")
|
||||||
|
void gettersSetters() {
|
||||||
|
VersementObjet vo = new VersementObjet();
|
||||||
|
vo.setVersement(newVersement());
|
||||||
|
vo.setTypeObjetCible("COTISATION");
|
||||||
|
vo.setObjetCibleId(UUID.randomUUID());
|
||||||
|
vo.setMontantApplique(new BigDecimal("5000.00"));
|
||||||
|
vo.setDateApplication(LocalDateTime.now());
|
||||||
|
vo.setCommentaire("Cotisation janvier");
|
||||||
|
|
||||||
|
assertThat(vo.getTypeObjetCible()).isEqualTo("COTISATION");
|
||||||
|
assertThat(vo.getMontantApplique()).isEqualByComparingTo("5000.00");
|
||||||
|
assertThat(vo.getCommentaire()).isEqualTo("Cotisation janvier");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("equals et hashCode")
|
||||||
|
void equalsHashCode() {
|
||||||
|
UUID id = UUID.randomUUID();
|
||||||
|
UUID objId = UUID.randomUUID();
|
||||||
|
Versement v = newVersement();
|
||||||
|
VersementObjet a = new VersementObjet();
|
||||||
|
a.setId(id);
|
||||||
|
a.setVersement(v);
|
||||||
|
a.setTypeObjetCible("COTISATION");
|
||||||
|
a.setObjetCibleId(objId);
|
||||||
|
a.setMontantApplique(BigDecimal.ONE);
|
||||||
|
VersementObjet b = new VersementObjet();
|
||||||
|
b.setId(id);
|
||||||
|
b.setVersement(v);
|
||||||
|
b.setTypeObjetCible("COTISATION");
|
||||||
|
b.setObjetCibleId(objId);
|
||||||
|
b.setMontantApplique(BigDecimal.ONE);
|
||||||
|
assertThat(a).isEqualTo(b);
|
||||||
|
assertThat(a.hashCode()).isEqualTo(b.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toString non null")
|
||||||
|
void toString_nonNull() {
|
||||||
|
VersementObjet vo = new VersementObjet();
|
||||||
|
vo.setVersement(newVersement());
|
||||||
|
vo.setTypeObjetCible("COTISATION");
|
||||||
|
vo.setObjetCibleId(UUID.randomUUID());
|
||||||
|
vo.setMontantApplique(BigDecimal.ONE);
|
||||||
|
assertThat(vo.toString()).isNotNull().isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("onCreate initialise dateApplication si null")
|
||||||
|
void onCreate_setsDateApplicationWhenNull() {
|
||||||
|
VersementObjet vo = new VersementObjet();
|
||||||
|
vo.setVersement(newVersement());
|
||||||
|
vo.setTypeObjetCible("COTISATION");
|
||||||
|
vo.setObjetCibleId(UUID.randomUUID());
|
||||||
|
vo.setMontantApplique(BigDecimal.ONE);
|
||||||
|
|
||||||
|
vo.onCreate();
|
||||||
|
|
||||||
|
assertThat(vo.getDateApplication()).isNotNull();
|
||||||
|
assertThat(vo.getActif()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("onCreate ne remplace pas une dateApplication existante")
|
||||||
|
void onCreate_doesNotOverrideDateApplication() {
|
||||||
|
LocalDateTime fixed = LocalDateTime.of(2026, 1, 1, 0, 0);
|
||||||
|
VersementObjet vo = new VersementObjet();
|
||||||
|
vo.setDateApplication(fixed);
|
||||||
|
|
||||||
|
vo.onCreate();
|
||||||
|
|
||||||
|
assertThat(vo.getDateApplication()).isEqualTo(fixed);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package dev.lions.unionflow.server.entity;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@DisplayName("Versement")
|
||||||
|
class VersementTest {
|
||||||
|
|
||||||
|
private static Membre newMembre() {
|
||||||
|
Membre m = new Membre();
|
||||||
|
m.setId(UUID.randomUUID());
|
||||||
|
m.setNumeroMembre("M1");
|
||||||
|
m.setPrenom("A");
|
||||||
|
m.setNom("B");
|
||||||
|
m.setEmail("a@test.com");
|
||||||
|
m.setDateNaissance(java.time.LocalDate.now());
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getters/setters")
|
||||||
|
void gettersSetters() {
|
||||||
|
Versement v = new Versement();
|
||||||
|
v.setNumeroReference("VRS-2026-001");
|
||||||
|
v.setMontant(new BigDecimal("10000.00"));
|
||||||
|
v.setCodeDevise("XOF");
|
||||||
|
v.setMethodePaiement("WAVE");
|
||||||
|
v.setStatutPaiement("CONFIRME");
|
||||||
|
v.setDatePaiement(LocalDateTime.now());
|
||||||
|
v.setNumeroTelephone("771234567");
|
||||||
|
v.setMembre(newMembre());
|
||||||
|
|
||||||
|
assertThat(v.getNumeroReference()).isEqualTo("VRS-2026-001");
|
||||||
|
assertThat(v.getMontant()).isEqualByComparingTo("10000.00");
|
||||||
|
assertThat(v.getCodeDevise()).isEqualTo("XOF");
|
||||||
|
assertThat(v.getStatutPaiement()).isEqualTo("CONFIRME");
|
||||||
|
assertThat(v.getNumeroTelephone()).isEqualTo("771234567");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("genererNumeroReference commence par VRS-")
|
||||||
|
void genererNumeroReference_startsWithVRS() {
|
||||||
|
String ref = Versement.genererNumeroReference();
|
||||||
|
assertThat(ref).startsWith("VRS-").isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("genererNumeroReference retourne des références uniques")
|
||||||
|
void genererNumeroReference_unique() {
|
||||||
|
String ref1 = Versement.genererNumeroReference();
|
||||||
|
String ref2 = Versement.genererNumeroReference();
|
||||||
|
assertThat(ref1).isNotEqualTo(ref2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("isConfirme — statut CONFIRME")
|
||||||
|
void isConfirme_statutCONFIRME() {
|
||||||
|
Versement v = buildMinimal();
|
||||||
|
v.setStatutPaiement("CONFIRME");
|
||||||
|
assertThat(v.isConfirme()).isTrue();
|
||||||
|
assertThat(v.peutEtreModifie()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("isConfirme — statut VALIDE (compatibilité)")
|
||||||
|
void isConfirme_statutVALIDE() {
|
||||||
|
Versement v = buildMinimal();
|
||||||
|
v.setStatutPaiement("VALIDE");
|
||||||
|
assertThat(v.isConfirme()).isTrue();
|
||||||
|
assertThat(v.peutEtreModifie()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("isConfirme — statut EN_ATTENTE")
|
||||||
|
void isConfirme_statutEnAttente() {
|
||||||
|
Versement v = buildMinimal();
|
||||||
|
v.setStatutPaiement("EN_ATTENTE");
|
||||||
|
assertThat(v.isConfirme()).isFalse();
|
||||||
|
assertThat(v.peutEtreModifie()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("peutEtreModifie — statut ANNULE")
|
||||||
|
void peutEtreModifie_false_whenANNULE() {
|
||||||
|
Versement v = buildMinimal();
|
||||||
|
v.setStatutPaiement("ANNULE");
|
||||||
|
assertThat(v.peutEtreModifie()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("peutEtreModifie — statut EN_ATTENTE_VALIDATION")
|
||||||
|
void peutEtreModifie_true_whenEnAttenteValidation() {
|
||||||
|
Versement v = buildMinimal();
|
||||||
|
v.setStatutPaiement("EN_ATTENTE_VALIDATION");
|
||||||
|
assertThat(v.peutEtreModifie()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("onCreate initialise reference, statut et datePaiement si null")
|
||||||
|
void onCreate_initDefaults() {
|
||||||
|
Versement v = new Versement();
|
||||||
|
v.setMontant(BigDecimal.TEN);
|
||||||
|
v.setCodeDevise("XOF");
|
||||||
|
v.setMethodePaiement("WAVE");
|
||||||
|
v.setMembre(newMembre());
|
||||||
|
|
||||||
|
v.onCreate();
|
||||||
|
|
||||||
|
assertThat(v.getNumeroReference()).startsWith("VRS-");
|
||||||
|
assertThat(v.getStatutPaiement()).isEqualTo("EN_ATTENTE");
|
||||||
|
assertThat(v.getDatePaiement()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("onCreate conserve la référence existante")
|
||||||
|
void onCreate_preservesExistingReference() {
|
||||||
|
Versement v = buildMinimal();
|
||||||
|
v.setNumeroReference("VRS-CUSTOM-001");
|
||||||
|
v.onCreate();
|
||||||
|
assertThat(v.getNumeroReference()).isEqualTo("VRS-CUSTOM-001");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("equals et hashCode")
|
||||||
|
void equalsHashCode() {
|
||||||
|
UUID id = UUID.randomUUID();
|
||||||
|
Membre m = newMembre();
|
||||||
|
Versement a = buildMinimal();
|
||||||
|
a.setId(id);
|
||||||
|
a.setMembre(m);
|
||||||
|
Versement b = buildMinimal();
|
||||||
|
b.setId(id);
|
||||||
|
b.setMembre(m);
|
||||||
|
assertThat(a).isEqualTo(b);
|
||||||
|
assertThat(a.hashCode()).isEqualTo(b.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toString non null")
|
||||||
|
void toString_nonNull() {
|
||||||
|
assertThat(buildMinimal().toString()).isNotNull().isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Versement buildMinimal() {
|
||||||
|
Versement v = new Versement();
|
||||||
|
v.setNumeroReference("VRS-2026-TEST");
|
||||||
|
v.setMontant(BigDecimal.ONE);
|
||||||
|
v.setCodeDevise("XOF");
|
||||||
|
v.setMethodePaiement("WAVE");
|
||||||
|
v.setStatutPaiement("EN_ATTENTE");
|
||||||
|
v.setMembre(newMembre());
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package dev.lions.unionflow.server.repository;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.entity.ContactPolicy;
|
||||||
|
import io.quarkus.test.TestTransaction;
|
||||||
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@QuarkusTest
|
||||||
|
@DisplayName("ContactPolicyRepository")
|
||||||
|
class ContactPolicyRepositoryTest {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ContactPolicyRepository contactPolicyRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findByOrganisationId retourne empty pour organisation inexistante")
|
||||||
|
void findByOrganisationId_inexistant_returnsEmpty() {
|
||||||
|
Optional<ContactPolicy> opt = contactPolicyRepository.findByOrganisationId(UUID.randomUUID());
|
||||||
|
assertThat(opt).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("listAll retourne liste non nulle")
|
||||||
|
void listAll_returnsNonNull() {
|
||||||
|
assertThat(contactPolicyRepository.listAll()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("count retourne >= 0")
|
||||||
|
void count_returnsNonNegative() {
|
||||||
|
assertThat(contactPolicyRepository.count()).isGreaterThanOrEqualTo(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package dev.lions.unionflow.server.repository;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.entity.ConversationParticipant;
|
||||||
|
import io.quarkus.test.TestTransaction;
|
||||||
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@QuarkusTest
|
||||||
|
@DisplayName("ConversationParticipantRepository")
|
||||||
|
class ConversationParticipantRepositoryTest {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ConversationParticipantRepository conversationParticipantRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findParticipant retourne empty pour conversation inexistante")
|
||||||
|
void findParticipant_returnsEmpty() {
|
||||||
|
Optional<ConversationParticipant> opt =
|
||||||
|
conversationParticipantRepository.findParticipant(UUID.randomUUID(), UUID.randomUUID());
|
||||||
|
assertThat(opt).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findByConversation retourne liste vide pour conversation inexistante")
|
||||||
|
void findByConversation_returnsEmpty() {
|
||||||
|
List<ConversationParticipant> list =
|
||||||
|
conversationParticipantRepository.findByConversation(UUID.randomUUID());
|
||||||
|
assertThat(list).isNotNull().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("estParticipant retourne false pour conversation inexistante")
|
||||||
|
void estParticipant_returnsFalse() {
|
||||||
|
boolean result = conversationParticipantRepository.estParticipant(
|
||||||
|
UUID.randomUUID(), UUID.randomUUID());
|
||||||
|
assertThat(result).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("count retourne >= 0")
|
||||||
|
void count_returnsNonNegative() {
|
||||||
|
assertThat(conversationParticipantRepository.count()).isGreaterThanOrEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("listAll retourne liste non nulle")
|
||||||
|
void listAll_returnsNonNull() {
|
||||||
|
assertThat(conversationParticipantRepository.listAll()).isNotNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package dev.lions.unionflow.server.repository;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.entity.MemberBlock;
|
||||||
|
import io.quarkus.test.TestTransaction;
|
||||||
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@QuarkusTest
|
||||||
|
@DisplayName("MemberBlockRepository")
|
||||||
|
class MemberBlockRepositoryTest {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MemberBlockRepository memberBlockRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("estBloque retourne false si aucun blocage")
|
||||||
|
void estBloque_returns_false() {
|
||||||
|
boolean result = memberBlockRepository.estBloque(
|
||||||
|
UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID());
|
||||||
|
assertThat(result).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findBlocage retourne empty si aucun blocage")
|
||||||
|
void findBlocage_returnsEmpty() {
|
||||||
|
Optional<MemberBlock> opt = memberBlockRepository.findBlocage(
|
||||||
|
UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID());
|
||||||
|
assertThat(opt).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findByBloqueur retourne liste vide pour membre inexistant")
|
||||||
|
void findByBloqueur_returnsEmpty() {
|
||||||
|
List<MemberBlock> list = memberBlockRepository.findByBloqueur(UUID.randomUUID());
|
||||||
|
assertThat(list).isNotNull().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findByBloqueurEtOrganisation retourne liste vide")
|
||||||
|
void findByBloqueurEtOrganisation_returnsEmpty() {
|
||||||
|
List<MemberBlock> list = memberBlockRepository.findByBloqueurEtOrganisation(
|
||||||
|
UUID.randomUUID(), UUID.randomUUID());
|
||||||
|
assertThat(list).isNotNull().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("count retourne >= 0")
|
||||||
|
void count_returnsNonNegative() {
|
||||||
|
assertThat(memberBlockRepository.count()).isGreaterThanOrEqualTo(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
package dev.lions.unionflow.server.repository;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.MethodePaiement;
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.StatutPaiement;
|
||||||
|
import dev.lions.unionflow.server.entity.Versement;
|
||||||
|
import io.quarkus.test.TestTransaction;
|
||||||
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@QuarkusTest
|
||||||
|
@DisplayName("VersementRepository")
|
||||||
|
class VersementRepositoryTest {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
VersementRepository versementRepository;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findById retourne null pour UUID inexistant")
|
||||||
|
void findById_inexistant_returnsNull() {
|
||||||
|
assertThat(versementRepository.findById(UUID.randomUUID())).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findVersementById retourne empty pour UUID inexistant")
|
||||||
|
void findVersementById_inexistant_returnsEmpty() {
|
||||||
|
Optional<Versement> opt = versementRepository.findVersementById(UUID.randomUUID());
|
||||||
|
assertThat(opt).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findByNumeroReference retourne empty pour référence inexistante")
|
||||||
|
void findByNumeroReference_inexistant_returnsEmpty() {
|
||||||
|
Optional<Versement> opt = versementRepository.findByNumeroReference("VRS-" + UUID.randomUUID());
|
||||||
|
assertThat(opt).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("listAll retourne une liste")
|
||||||
|
void listAll_returnsList() {
|
||||||
|
List<Versement> list = versementRepository.listAll();
|
||||||
|
assertThat(list).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("count retourne un nombre >= 0")
|
||||||
|
void count_returnsNonNegative() {
|
||||||
|
assertThat(versementRepository.count()).isGreaterThanOrEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findByMembreId retourne liste vide pour membre inexistant")
|
||||||
|
void findByMembreId_inconnu_returnsEmpty() {
|
||||||
|
List<Versement> list = versementRepository.findByMembreId(UUID.randomUUID());
|
||||||
|
assertThat(list).isNotNull().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findByStatut retourne liste non nulle")
|
||||||
|
void findByStatut_returnsNonNull() {
|
||||||
|
List<Versement> list = versementRepository.findByStatut(StatutPaiement.EN_ATTENTE);
|
||||||
|
assertThat(list).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findByMethode retourne liste non nulle")
|
||||||
|
void findByMethode_returnsNonNull() {
|
||||||
|
List<Versement> list = versementRepository.findByMethode(MethodePaiement.WAVE_MOBILE_MONEY);
|
||||||
|
assertThat(list).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("findConfirmesParPeriode retourne liste non nulle")
|
||||||
|
void findConfirmesParPeriode_returnsNonNull() {
|
||||||
|
LocalDateTime debut = LocalDateTime.now().minusDays(30);
|
||||||
|
LocalDateTime fin = LocalDateTime.now();
|
||||||
|
List<Versement> list = versementRepository.findConfirmesParPeriode(debut, fin);
|
||||||
|
assertThat(list).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestTransaction
|
||||||
|
@DisplayName("calculerMontantTotalConfirmes retourne ZERO si aucun versement")
|
||||||
|
void calculerMontantTotalConfirmes_returnsZeroWhenEmpty() {
|
||||||
|
LocalDateTime debut = LocalDateTime.now().minusSeconds(1);
|
||||||
|
LocalDateTime fin = LocalDateTime.now().plusSeconds(1);
|
||||||
|
BigDecimal total = versementRepository.calculerMontantTotalConfirmes(debut, fin);
|
||||||
|
// Peut être > 0 selon les données de test, mais ne doit pas être null
|
||||||
|
assertThat(total).isNotNull().isGreaterThanOrEqualTo(BigDecimal.ZERO);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,439 @@
|
|||||||
|
package dev.lions.unionflow.server.resource;
|
||||||
|
|
||||||
|
import static io.restassured.RestAssured.given;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.response.ContactPolicyResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.response.ConversationResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.response.ConversationSummaryResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.response.MessageResponse;
|
||||||
|
import dev.lions.unionflow.server.service.MessagingService;
|
||||||
|
import io.quarkus.test.InjectMock;
|
||||||
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
|
import io.quarkus.test.security.TestSecurity;
|
||||||
|
import io.restassured.http.ContentType;
|
||||||
|
import jakarta.ws.rs.NotFoundException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.MethodOrderer;
|
||||||
|
import org.junit.jupiter.api.Order;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.TestMethodOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests d'intégration REST pour {@link MessagingResource}.
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 4.0
|
||||||
|
* @since 2026-04-13
|
||||||
|
*/
|
||||||
|
@QuarkusTest
|
||||||
|
@DisplayName("MessagingResource")
|
||||||
|
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||||
|
class MessagingResourceTest {
|
||||||
|
|
||||||
|
private static final String BASE = "/api/messagerie";
|
||||||
|
private static final String CONV_ID = "00000000-0000-0000-0000-000000000001";
|
||||||
|
private static final String MSG_ID = "00000000-0000-0000-0000-000000000002";
|
||||||
|
private static final String MEMBRE_ID = "00000000-0000-0000-0000-000000000003";
|
||||||
|
private static final String ORG_ID = "00000000-0000-0000-0000-000000000004";
|
||||||
|
|
||||||
|
@InjectMock
|
||||||
|
MessagingService messagingService;
|
||||||
|
|
||||||
|
// ── POST /conversations/directe ───────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("demarrerConversationDirecte — requête valide → 201")
|
||||||
|
void demarrerConversationDirecte_valid_returns201() {
|
||||||
|
ConversationResponse conv = ConversationResponse.builder()
|
||||||
|
.id(UUID.fromString(CONV_ID))
|
||||||
|
.typeConversation("DIRECTE")
|
||||||
|
.statut("ACTIVE")
|
||||||
|
.build();
|
||||||
|
when(messagingService.demarrerConversationDirecte(any())).thenReturn(conv);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"destinataireId\":\"" + MEMBRE_ID + "\",\"organisationId\":\"" + ORG_ID + "\"}")
|
||||||
|
.when().post(BASE + "/conversations/directe")
|
||||||
|
.then().statusCode(201)
|
||||||
|
.body("typeConversation", equalTo("DIRECTE"))
|
||||||
|
.body("statut", equalTo("ACTIVE"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(2)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("demarrerConversationDirecte — destinataireId manquant → 400")
|
||||||
|
void demarrerConversationDirecte_missingDestinataire_returns400() {
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"organisationId\":\"" + ORG_ID + "\"}")
|
||||||
|
.when().post(BASE + "/conversations/directe")
|
||||||
|
.then().statusCode(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── POST /conversations/role ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(3)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("demarrerConversationRole — requête valide → 201")
|
||||||
|
void demarrerConversationRole_valid_returns201() {
|
||||||
|
ConversationResponse conv = ConversationResponse.builder()
|
||||||
|
.id(UUID.fromString(CONV_ID))
|
||||||
|
.typeConversation("ROLE_CANAL")
|
||||||
|
.roleCible("TRESORIER")
|
||||||
|
.build();
|
||||||
|
when(messagingService.demarrerConversationRole(any())).thenReturn(conv);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"organisationId\":\"" + ORG_ID + "\","
|
||||||
|
+ "\"roleCible\":\"TRESORIER\","
|
||||||
|
+ "\"contenuInitial\":\"Bonjour\"}")
|
||||||
|
.when().post(BASE + "/conversations/role")
|
||||||
|
.then().statusCode(201)
|
||||||
|
.body("typeConversation", equalTo("ROLE_CANAL"))
|
||||||
|
.body("roleCible", equalTo("TRESORIER"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(4)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("demarrerConversationRole — rôle invalide → 400")
|
||||||
|
void demarrerConversationRole_invalidRole_returns400() {
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"organisationId\":\"" + ORG_ID + "\","
|
||||||
|
+ "\"roleCible\":\"DIRECTEUR\","
|
||||||
|
+ "\"contenuInitial\":\"Bonjour\"}")
|
||||||
|
.when().post(BASE + "/conversations/role")
|
||||||
|
.then().statusCode(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── GET /conversations ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(5)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("getMesConversations — liste vide → 200")
|
||||||
|
void getMesConversations_empty_returns200() {
|
||||||
|
when(messagingService.getMesConversations()).thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/conversations")
|
||||||
|
.then().statusCode(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(6)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("getMesConversations — liste non vide → 200")
|
||||||
|
void getMesConversations_nonEmpty_returns200() {
|
||||||
|
ConversationSummaryResponse summary = ConversationSummaryResponse.builder()
|
||||||
|
.id(UUID.fromString(CONV_ID))
|
||||||
|
.typeConversation("DIRECTE")
|
||||||
|
.titre("Alice Dupont")
|
||||||
|
.build();
|
||||||
|
when(messagingService.getMesConversations()).thenReturn(List.of(summary));
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/conversations")
|
||||||
|
.then().statusCode(200)
|
||||||
|
.body("[0].titre", equalTo("Alice Dupont"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── GET /conversations/{id} ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(7)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("getConversation — trouvée → 200")
|
||||||
|
void getConversation_found_returns200() {
|
||||||
|
ConversationResponse conv = ConversationResponse.builder()
|
||||||
|
.id(UUID.fromString(CONV_ID))
|
||||||
|
.typeConversation("DIRECTE")
|
||||||
|
.titre("Bob Martin")
|
||||||
|
.build();
|
||||||
|
when(messagingService.getConversation(any(UUID.class))).thenReturn(conv);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/conversations/" + CONV_ID)
|
||||||
|
.then().statusCode(200)
|
||||||
|
.body("titre", equalTo("Bob Martin"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(8)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("getConversation — non trouvée → 404")
|
||||||
|
void getConversation_notFound_returns404() {
|
||||||
|
when(messagingService.getConversation(any(UUID.class)))
|
||||||
|
.thenThrow(new NotFoundException("conversation non trouvée"));
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/conversations/" + CONV_ID)
|
||||||
|
.then().statusCode(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── DELETE /conversations/{id} ────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(9)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("archiverConversation → 200")
|
||||||
|
void archiverConversation_returns200() {
|
||||||
|
ConversationResponse conv = ConversationResponse.builder()
|
||||||
|
.id(UUID.fromString(CONV_ID))
|
||||||
|
.statut("ARCHIVEE")
|
||||||
|
.build();
|
||||||
|
when(messagingService.archiverConversation(any(UUID.class))).thenReturn(conv);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().delete(BASE + "/conversations/" + CONV_ID)
|
||||||
|
.then().statusCode(200)
|
||||||
|
.body("statut", equalTo("ARCHIVEE"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── POST /conversations/{id}/messages ─────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(10)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("envoyerMessage — message texte → 201")
|
||||||
|
void envoyerMessage_texte_returns201() {
|
||||||
|
MessageResponse msg = MessageResponse.builder()
|
||||||
|
.id(UUID.fromString(MSG_ID))
|
||||||
|
.typeMessage("TEXTE")
|
||||||
|
.contenu("Bonjour !")
|
||||||
|
.build();
|
||||||
|
when(messagingService.envoyerMessage(any(UUID.class), any())).thenReturn(msg);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"typeMessage\":\"TEXTE\",\"contenu\":\"Bonjour !\"}")
|
||||||
|
.when().post(BASE + "/conversations/" + CONV_ID + "/messages")
|
||||||
|
.then().statusCode(201)
|
||||||
|
.body("typeMessage", equalTo("TEXTE"))
|
||||||
|
.body("contenu", equalTo("Bonjour !"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(11)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("envoyerMessage — type invalide → 400")
|
||||||
|
void envoyerMessage_invalidType_returns400() {
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"typeMessage\":\"VIDEO\",\"contenu\":\"test\"}")
|
||||||
|
.when().post(BASE + "/conversations/" + CONV_ID + "/messages")
|
||||||
|
.then().statusCode(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── GET /conversations/{id}/messages ──────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(12)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("getMessages — page 0 → 200")
|
||||||
|
void getMessages_page0_returns200() {
|
||||||
|
when(messagingService.getMessages(any(UUID.class), anyInt()))
|
||||||
|
.thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/conversations/" + CONV_ID + "/messages")
|
||||||
|
.then().statusCode(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(13)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("getMessages — page custom → 200")
|
||||||
|
void getMessages_customPage_returns200() {
|
||||||
|
when(messagingService.getMessages(any(UUID.class), anyInt()))
|
||||||
|
.thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
given()
|
||||||
|
.queryParam("page", 2)
|
||||||
|
.when().get(BASE + "/conversations/" + CONV_ID + "/messages")
|
||||||
|
.then().statusCode(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── PUT /conversations/{id}/lire ──────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(14)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("marquerLu → 204")
|
||||||
|
void marquerLu_returns204() {
|
||||||
|
doNothing().when(messagingService).marquerConversationLue(any(UUID.class));
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().put(BASE + "/conversations/" + CONV_ID + "/lire")
|
||||||
|
.then().statusCode(204);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── DELETE /conversations/{cId}/messages/{mId} ────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(15)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("supprimerMessage → 204")
|
||||||
|
void supprimerMessage_returns204() {
|
||||||
|
doNothing().when(messagingService).supprimerMessage(any(UUID.class), any(UUID.class));
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().delete(BASE + "/conversations/" + CONV_ID + "/messages/" + MSG_ID)
|
||||||
|
.then().statusCode(204);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(16)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("supprimerMessage — non trouvé → 404")
|
||||||
|
void supprimerMessage_notFound_returns404() {
|
||||||
|
org.mockito.Mockito.doThrow(new NotFoundException("message introuvable"))
|
||||||
|
.when(messagingService).supprimerMessage(any(UUID.class), any(UUID.class));
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().delete(BASE + "/conversations/" + CONV_ID + "/messages/" + MSG_ID)
|
||||||
|
.then().statusCode(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── POST /blocages ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(17)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("bloquerMembre — requête valide → 204")
|
||||||
|
void bloquerMembre_valid_returns204() {
|
||||||
|
doNothing().when(messagingService).bloquerMembre(any());
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"membreABloquerId\":\"" + MEMBRE_ID + "\","
|
||||||
|
+ "\"organisationId\":\"" + ORG_ID + "\"}")
|
||||||
|
.when().post(BASE + "/blocages")
|
||||||
|
.then().statusCode(204);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(18)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("bloquerMembre — membreABloquerId manquant → 400")
|
||||||
|
void bloquerMembre_missingId_returns400() {
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"organisationId\":\"" + ORG_ID + "\"}")
|
||||||
|
.when().post(BASE + "/blocages")
|
||||||
|
.then().statusCode(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── DELETE /blocages/{membreId} ───────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(19)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("debloquerMembre → 204")
|
||||||
|
void debloquerMembre_returns204() {
|
||||||
|
doNothing().when(messagingService).debloquerMembre(any(UUID.class), any());
|
||||||
|
|
||||||
|
given()
|
||||||
|
.queryParam("organisationId", ORG_ID)
|
||||||
|
.when().delete(BASE + "/blocages/" + MEMBRE_ID)
|
||||||
|
.then().statusCode(204);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── GET /blocages ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(20)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("getMesBlocages → 200")
|
||||||
|
void getMesBlocages_returns200() {
|
||||||
|
when(messagingService.getMesBlocages()).thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/blocages")
|
||||||
|
.then().statusCode(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── GET /politique/{organisationId} ───────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(21)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("getPolitique → 200")
|
||||||
|
void getPolitique_returns200() {
|
||||||
|
ContactPolicyResponse policy = ContactPolicyResponse.builder()
|
||||||
|
.id(UUID.randomUUID())
|
||||||
|
.organisationId(UUID.fromString(ORG_ID))
|
||||||
|
.typePolitique("OUVERT")
|
||||||
|
.autoriserMembreVersMembre(true)
|
||||||
|
.autoriserMembreVersRole(true)
|
||||||
|
.autoriserNotesVocales(true)
|
||||||
|
.build();
|
||||||
|
when(messagingService.getPolitique(any(UUID.class))).thenReturn(policy);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/politique/" + ORG_ID)
|
||||||
|
.then().statusCode(200)
|
||||||
|
.body("typePolitique", equalTo("OUVERT"))
|
||||||
|
.body("autoriserNotesVocales", equalTo(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── PUT /politique/{organisationId} ───────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(22)
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
@DisplayName("mettreAJourPolitique — ADMIN → 200")
|
||||||
|
void mettreAJourPolitique_admin_returns200() {
|
||||||
|
ContactPolicyResponse updated = ContactPolicyResponse.builder()
|
||||||
|
.typePolitique("BUREAU_SEULEMENT")
|
||||||
|
.build();
|
||||||
|
when(messagingService.mettreAJourPolitique(any(UUID.class), any())).thenReturn(updated);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"typePolitique\":\"BUREAU_SEULEMENT\"}")
|
||||||
|
.when().put(BASE + "/politique/" + ORG_ID)
|
||||||
|
.then().statusCode(200)
|
||||||
|
.body("typePolitique", equalTo("BUREAU_SEULEMENT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(23)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
@DisplayName("mettreAJourPolitique — MEMBRE → 403")
|
||||||
|
void mettreAJourPolitique_membre_returns403() {
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"typePolitique\":\"BUREAU_SEULEMENT\"}")
|
||||||
|
.when().put(BASE + "/politique/" + ORG_ID)
|
||||||
|
.then().statusCode(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(24)
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
@DisplayName("mettreAJourPolitique — politique invalide → 400")
|
||||||
|
void mettreAJourPolitique_invalidPolicy_returns400() {
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"typePolitique\":\"LIBRE\"}")
|
||||||
|
.when().put(BASE + "/politique/" + ORG_ID)
|
||||||
|
.then().statusCode(400);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,317 @@
|
|||||||
|
package dev.lions.unionflow.server.resource;
|
||||||
|
|
||||||
|
import static io.restassured.RestAssured.given;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.response.VersementGatewayResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.response.VersementResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.response.VersementStatutResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.response.VersementSummaryResponse;
|
||||||
|
import dev.lions.unionflow.server.service.VersementService;
|
||||||
|
import io.quarkus.test.InjectMock;
|
||||||
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
|
import io.quarkus.test.security.TestSecurity;
|
||||||
|
import io.restassured.http.ContentType;
|
||||||
|
import jakarta.ws.rs.NotFoundException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.junit.jupiter.api.MethodOrderer;
|
||||||
|
import org.junit.jupiter.api.Order;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.TestMethodOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests d'intégration REST pour {@link VersementResource}.
|
||||||
|
*
|
||||||
|
* @author UnionFlow Team
|
||||||
|
* @version 4.0
|
||||||
|
* @since 2026-04-13
|
||||||
|
*/
|
||||||
|
@QuarkusTest
|
||||||
|
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||||
|
class VersementResourceTest {
|
||||||
|
|
||||||
|
private static final String BASE = "/api/versements";
|
||||||
|
private static final String VERSEMENT_ID = "00000000-0000-0000-0000-000000000010";
|
||||||
|
private static final String MEMBRE_ID = "00000000-0000-0000-0000-000000000020";
|
||||||
|
private static final String INTENTION_ID = "00000000-0000-0000-0000-000000000030";
|
||||||
|
|
||||||
|
@InjectMock
|
||||||
|
VersementService versementService;
|
||||||
|
|
||||||
|
// ── GET /{id} ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1)
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void trouverParId_found_returns200() {
|
||||||
|
VersementResponse response = VersementResponse.builder()
|
||||||
|
.numeroReference("VRS-2026-001")
|
||||||
|
.build();
|
||||||
|
when(versementService.trouverParId(any(UUID.class))).thenReturn(response);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/" + VERSEMENT_ID)
|
||||||
|
.then().statusCode(200)
|
||||||
|
.body("numeroReference", equalTo("VRS-2026-001"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(2)
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void trouverParId_notFound_returns404() {
|
||||||
|
when(versementService.trouverParId(any(UUID.class)))
|
||||||
|
.thenThrow(new NotFoundException("non trouvé"));
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/" + VERSEMENT_ID)
|
||||||
|
.then().statusCode(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── GET /reference/{ref} ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(3)
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void trouverParReference_found_returns200() {
|
||||||
|
VersementResponse response = VersementResponse.builder()
|
||||||
|
.numeroReference("VRS-2026-001")
|
||||||
|
.build();
|
||||||
|
when(versementService.trouverParNumeroReference(anyString())).thenReturn(response);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/reference/VRS-2026-001")
|
||||||
|
.then().statusCode(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── GET /membre/{id} ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(4)
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void listerParMembre_returns200() {
|
||||||
|
when(versementService.listerParMembre(any(UUID.class)))
|
||||||
|
.thenReturn(List.of(new VersementSummaryResponse()));
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/membre/" + MEMBRE_ID)
|
||||||
|
.then().statusCode(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── GET /mes-versements ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(5)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void getMesVersements_returns200() {
|
||||||
|
when(versementService.getMesVersements(anyInt()))
|
||||||
|
.thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/mes-versements")
|
||||||
|
.then().statusCode(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(6)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void getMesVersements_customLimit_returns200() {
|
||||||
|
when(versementService.getMesVersements(10))
|
||||||
|
.thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
given()
|
||||||
|
.queryParam("limit", 10)
|
||||||
|
.when().get(BASE + "/mes-versements")
|
||||||
|
.then().statusCode(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── POST /{id}/valider ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(7)
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void validerVersement_returns200() {
|
||||||
|
VersementResponse response = VersementResponse.builder()
|
||||||
|
.statutPaiement("CONFIRME")
|
||||||
|
.build();
|
||||||
|
when(versementService.validerVersement(any(UUID.class))).thenReturn(response);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.when().post(BASE + "/" + VERSEMENT_ID + "/valider")
|
||||||
|
.then().statusCode(200)
|
||||||
|
.body("statutPaiement", equalTo("CONFIRME"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(8)
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void validerVersement_notFound_returns404() {
|
||||||
|
when(versementService.validerVersement(any(UUID.class)))
|
||||||
|
.thenThrow(new NotFoundException("non trouvé"));
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.when().post(BASE + "/" + VERSEMENT_ID + "/valider")
|
||||||
|
.then().statusCode(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── POST /{id}/annuler ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(9)
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void annulerVersement_returns200() {
|
||||||
|
VersementResponse response = VersementResponse.builder()
|
||||||
|
.statutPaiement("ANNULE")
|
||||||
|
.build();
|
||||||
|
when(versementService.annulerVersement(any(UUID.class))).thenReturn(response);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.when().post(BASE + "/" + VERSEMENT_ID + "/annuler")
|
||||||
|
.then().statusCode(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── POST /initier-wave ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(10)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierWave_validRequest_returns201() {
|
||||||
|
VersementGatewayResponse gateway = VersementGatewayResponse.builder()
|
||||||
|
.versementId(UUID.fromString(VERSEMENT_ID))
|
||||||
|
.waveLaunchUrl("wave://checkout/abc123")
|
||||||
|
.waveCheckoutSessionId("cos-abc")
|
||||||
|
.clientReference(INTENTION_ID)
|
||||||
|
.montant(new BigDecimal("5000"))
|
||||||
|
.statut("EN_ATTENTE")
|
||||||
|
.build();
|
||||||
|
when(versementService.initierVersementWave(any())).thenReturn(gateway);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"cotisationId\":\"" + UUID.randomUUID() + "\",\"numeroTelephone\":\"771234567\"}")
|
||||||
|
.when().post(BASE + "/initier-wave")
|
||||||
|
.then().statusCode(201)
|
||||||
|
.body("waveLaunchUrl", equalTo("wave://checkout/abc123"))
|
||||||
|
.body("waveCheckoutSessionId", equalTo("cos-abc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(11)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierWave_missingCotisationId_returns400() {
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"numeroTelephone\":\"771234567\"}")
|
||||||
|
.when().post(BASE + "/initier-wave")
|
||||||
|
.then().statusCode(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── GET /statut/{intentionId} ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(12)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void getStatutVersement_completee_returns200() {
|
||||||
|
VersementStatutResponse statut = VersementStatutResponse.builder()
|
||||||
|
.intentionId(UUID.fromString(INTENTION_ID))
|
||||||
|
.statut("COMPLETEE")
|
||||||
|
.confirme(true)
|
||||||
|
.message("Versement confirmé !")
|
||||||
|
.build();
|
||||||
|
when(versementService.verifierStatutVersement(any(UUID.class))).thenReturn(statut);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/statut/" + INTENTION_ID)
|
||||||
|
.then().statusCode(200)
|
||||||
|
.body("confirme", equalTo(true))
|
||||||
|
.body("statut", equalTo("COMPLETEE"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(13)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void getStatutVersement_notFound_returns404() {
|
||||||
|
when(versementService.verifierStatutVersement(any(UUID.class)))
|
||||||
|
.thenThrow(new NotFoundException("non trouvé"));
|
||||||
|
|
||||||
|
given()
|
||||||
|
.when().get(BASE + "/statut/" + INTENTION_ID)
|
||||||
|
.then().statusCode(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── POST /declarer-manuel ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(14)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void declarerManuel_validRequest_returns201() {
|
||||||
|
VersementResponse response = VersementResponse.builder()
|
||||||
|
.statutPaiement("EN_ATTENTE_VALIDATION")
|
||||||
|
.methodePaiement("ESPECES")
|
||||||
|
.build();
|
||||||
|
when(versementService.declarerVersementManuel(any())).thenReturn(response);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"cotisationId\":\"" + UUID.randomUUID()
|
||||||
|
+ "\",\"methodePaiement\":\"ESPECES\"}")
|
||||||
|
.when().post(BASE + "/declarer-manuel")
|
||||||
|
.then().statusCode(201)
|
||||||
|
.body("statutPaiement", equalTo("EN_ATTENTE_VALIDATION"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(15)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void declarerManuel_methodInvalide_returns400() {
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"cotisationId\":\"" + UUID.randomUUID()
|
||||||
|
+ "\",\"methodePaiement\":\"PAYPAL\"}")
|
||||||
|
.when().post(BASE + "/declarer-manuel")
|
||||||
|
.then().statusCode(400);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── POST /initier-depot-epargne ───────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(16)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierDepotEpargne_validRequest_returns201() {
|
||||||
|
VersementGatewayResponse gateway = VersementGatewayResponse.builder()
|
||||||
|
.waveLaunchUrl("wave://checkout/epargne")
|
||||||
|
.statut("EN_ATTENTE")
|
||||||
|
.montant(new BigDecimal("10000"))
|
||||||
|
.build();
|
||||||
|
when(versementService.initierDepotEpargneEnLigne(any())).thenReturn(gateway);
|
||||||
|
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"compteId\":\"" + UUID.randomUUID()
|
||||||
|
+ "\",\"montant\":10000,\"numeroTelephone\":\"771234567\"}")
|
||||||
|
.when().post(BASE + "/initier-depot-epargne")
|
||||||
|
.then().statusCode(201)
|
||||||
|
.body("waveLaunchUrl", notNullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(17)
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierDepotEpargne_montantManquant_returns400() {
|
||||||
|
given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("{\"compteId\":\"" + UUID.randomUUID() + "\"}")
|
||||||
|
.when().post(BASE + "/initier-depot-epargne")
|
||||||
|
.then().statusCode(400);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,509 @@
|
|||||||
|
package dev.lions.unionflow.server.service;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.request.BloquerMembreRequest;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.request.DemarrerConversationDirecteRequest;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.request.DemarrerConversationRoleRequest;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.request.EnvoyerMessageRequest;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.request.MettreAJourPolitiqueRequest;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.response.ContactPolicyResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.response.ConversationResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.response.ConversationSummaryResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.messagerie.response.MessageResponse;
|
||||||
|
import dev.lions.unionflow.server.api.enums.messagerie.StatutConversation;
|
||||||
|
import dev.lions.unionflow.server.api.enums.messagerie.TypeContenu;
|
||||||
|
import dev.lions.unionflow.server.api.enums.messagerie.TypeConversation;
|
||||||
|
import dev.lions.unionflow.server.api.enums.messagerie.TypePolitiqueCommunication;
|
||||||
|
import dev.lions.unionflow.server.entity.ContactPolicy;
|
||||||
|
import dev.lions.unionflow.server.entity.Conversation;
|
||||||
|
import dev.lions.unionflow.server.entity.ConversationParticipant;
|
||||||
|
import dev.lions.unionflow.server.entity.MemberBlock;
|
||||||
|
import dev.lions.unionflow.server.entity.Membre;
|
||||||
|
import dev.lions.unionflow.server.entity.Message;
|
||||||
|
import dev.lions.unionflow.server.entity.Organisation;
|
||||||
|
import dev.lions.unionflow.server.repository.ContactPolicyRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.ConversationParticipantRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.ConversationRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.MemberBlockRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.MembreOrganisationRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.MembreRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.MessageRepository;
|
||||||
|
import dev.lions.unionflow.server.messaging.KafkaEventProducer;
|
||||||
|
import io.quarkus.security.identity.SecurityIdentity;
|
||||||
|
import io.quarkus.test.InjectMock;
|
||||||
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.BadRequestException;
|
||||||
|
import jakarta.ws.rs.ForbiddenException;
|
||||||
|
import jakarta.ws.rs.NotFoundException;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests unitaires du MessagingService avec mocks.
|
||||||
|
*/
|
||||||
|
@QuarkusTest
|
||||||
|
@DisplayName("MessagingService")
|
||||||
|
class MessagingServiceTest {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
MessagingService messagingService;
|
||||||
|
|
||||||
|
@InjectMock ConversationRepository conversationRepository;
|
||||||
|
@InjectMock ConversationParticipantRepository participantRepository;
|
||||||
|
@InjectMock MessageRepository messageRepository;
|
||||||
|
@InjectMock ContactPolicyRepository contactPolicyRepository;
|
||||||
|
@InjectMock MemberBlockRepository memberBlockRepository;
|
||||||
|
@InjectMock MembreRepository membreRepository;
|
||||||
|
@InjectMock MembreOrganisationRepository membreOrganisationRepository;
|
||||||
|
@InjectMock KafkaEventProducer kafkaEventProducer;
|
||||||
|
@InjectMock SecurityIdentity securityIdentity;
|
||||||
|
|
||||||
|
private static final UUID MEMBRE_ID = UUID.fromString("00000000-0000-0000-0000-000000000001");
|
||||||
|
private static final UUID DESTINATAIRE_ID = UUID.fromString("00000000-0000-0000-0000-000000000002");
|
||||||
|
private static final UUID ORG_ID = UUID.fromString("00000000-0000-0000-0000-000000000003");
|
||||||
|
private static final UUID CONV_ID = UUID.fromString("00000000-0000-0000-0000-000000000004");
|
||||||
|
private static final UUID MESSAGE_ID = UUID.fromString("00000000-0000-0000-0000-000000000005");
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
// Mock du membre connecté
|
||||||
|
io.quarkus.security.runtime.QuarkusPrincipal principal =
|
||||||
|
new io.quarkus.security.runtime.QuarkusPrincipal("membre@test.com");
|
||||||
|
when(securityIdentity.getPrincipal()).thenReturn(principal);
|
||||||
|
|
||||||
|
Membre moi = newMembre(MEMBRE_ID, "membre@test.com", "Alpha", "Diallo");
|
||||||
|
when(membreRepository.find("email", "membre@test.com"))
|
||||||
|
.thenReturn(io.quarkus.hibernate.orm.panache.PanacheQuery.class.cast(
|
||||||
|
mockSingleResultQuery(moi)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── getMesConversations ───────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getMesConversations — retourne liste vide")
|
||||||
|
void getMesConversations_returnsEmpty() {
|
||||||
|
when(conversationRepository.findByMembreId(MEMBRE_ID))
|
||||||
|
.thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
List<ConversationSummaryResponse> result = messagingService.getMesConversations();
|
||||||
|
|
||||||
|
assertThat(result).isNotNull().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getMesConversations — retourne la liste des conversations")
|
||||||
|
void getMesConversations_returnsList() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
when(conversationRepository.findByMembreId(MEMBRE_ID)).thenReturn(List.of(conv));
|
||||||
|
when(messageRepository.findDernierMessage(CONV_ID)).thenReturn(Optional.empty());
|
||||||
|
when(messageRepository.countNonLus(CONV_ID, MEMBRE_ID)).thenReturn(0L);
|
||||||
|
when(participantRepository.findByConversation(CONV_ID)).thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
List<ConversationSummaryResponse> result = messagingService.getMesConversations();
|
||||||
|
|
||||||
|
assertThat(result).hasSize(1);
|
||||||
|
assertThat(result.get(0).getTypeConversation()).isEqualTo("DIRECTE");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── getConversation ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getConversation — notFound → NotFoundException")
|
||||||
|
void getConversation_notFound() {
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.getConversation(CONV_ID))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getConversation — non participant → ForbiddenException")
|
||||||
|
void getConversation_nonParticipant() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.of(conv));
|
||||||
|
when(participantRepository.estParticipant(CONV_ID, MEMBRE_ID)).thenReturn(false);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.getConversation(CONV_ID))
|
||||||
|
.isInstanceOf(ForbiddenException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getConversation — success → retourne ConversationResponse")
|
||||||
|
void getConversation_success() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.of(conv));
|
||||||
|
when(participantRepository.estParticipant(CONV_ID, MEMBRE_ID)).thenReturn(true);
|
||||||
|
when(participantRepository.findByConversation(CONV_ID)).thenReturn(Collections.emptyList());
|
||||||
|
when(messageRepository.findByConversationPagine(eq(CONV_ID), eq(0), anyInt()))
|
||||||
|
.thenReturn(Collections.emptyList());
|
||||||
|
when(messageRepository.countNonLus(CONV_ID, MEMBRE_ID)).thenReturn(2L);
|
||||||
|
|
||||||
|
ConversationResponse result = messagingService.getConversation(CONV_ID);
|
||||||
|
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
assertThat(result.getId()).isEqualTo(CONV_ID);
|
||||||
|
assertThat(result.getNonLus()).isEqualTo(2L);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── archiverConversation ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("archiverConversation — success → statut ARCHIVEE")
|
||||||
|
void archiverConversation_success() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.of(conv));
|
||||||
|
when(participantRepository.estParticipant(CONV_ID, MEMBRE_ID)).thenReturn(true);
|
||||||
|
when(participantRepository.findByConversation(CONV_ID)).thenReturn(Collections.emptyList());
|
||||||
|
when(messageRepository.findByConversationPagine(eq(CONV_ID), eq(0), anyInt()))
|
||||||
|
.thenReturn(Collections.emptyList());
|
||||||
|
when(messageRepository.countNonLus(CONV_ID, MEMBRE_ID)).thenReturn(0L);
|
||||||
|
|
||||||
|
ConversationResponse result = messagingService.archiverConversation(CONV_ID);
|
||||||
|
|
||||||
|
assertThat(result.getStatut()).isEqualTo("ARCHIVEE");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── envoyerMessage ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("envoyerMessage — conversation non trouvée → NotFoundException")
|
||||||
|
void envoyerMessage_notFound() {
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
|
||||||
|
.typeMessage("TEXTE").contenu("Bonjour").build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.envoyerMessage(CONV_ID, req))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("envoyerMessage — non participant → ForbiddenException")
|
||||||
|
void envoyerMessage_nonParticipant() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.of(conv));
|
||||||
|
when(participantRepository.estParticipant(CONV_ID, MEMBRE_ID)).thenReturn(false);
|
||||||
|
|
||||||
|
EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
|
||||||
|
.typeMessage("TEXTE").contenu("Bonjour").build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.envoyerMessage(CONV_ID, req))
|
||||||
|
.isInstanceOf(ForbiddenException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("envoyerMessage — conversation archivée → BadRequestException")
|
||||||
|
void envoyerMessage_archived() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
conv.setStatut(StatutConversation.ARCHIVEE);
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.of(conv));
|
||||||
|
when(participantRepository.estParticipant(CONV_ID, MEMBRE_ID)).thenReturn(true);
|
||||||
|
|
||||||
|
EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
|
||||||
|
.typeMessage("TEXTE").contenu("Bonjour").build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.envoyerMessage(CONV_ID, req))
|
||||||
|
.isInstanceOf(BadRequestException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("envoyerMessage — TEXTE sans contenu → BadRequestException")
|
||||||
|
void envoyerMessage_texteSansContenu() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.of(conv));
|
||||||
|
when(participantRepository.estParticipant(CONV_ID, MEMBRE_ID)).thenReturn(true);
|
||||||
|
|
||||||
|
EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
|
||||||
|
.typeMessage("TEXTE").contenu("").build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.envoyerMessage(CONV_ID, req))
|
||||||
|
.isInstanceOf(BadRequestException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("envoyerMessage — VOCAL sans urlFichier → BadRequestException")
|
||||||
|
void envoyerMessage_vocalSansUrl() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.of(conv));
|
||||||
|
when(participantRepository.estParticipant(CONV_ID, MEMBRE_ID)).thenReturn(true);
|
||||||
|
|
||||||
|
EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
|
||||||
|
.typeMessage("VOCAL").dureeAudio(30).build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.envoyerMessage(CONV_ID, req))
|
||||||
|
.isInstanceOf(BadRequestException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("envoyerMessage — VOCAL sans dureeAudio → BadRequestException")
|
||||||
|
void envoyerMessage_vocalSansDuree() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.of(conv));
|
||||||
|
when(participantRepository.estParticipant(CONV_ID, MEMBRE_ID)).thenReturn(true);
|
||||||
|
|
||||||
|
EnvoyerMessageRequest req = EnvoyerMessageRequest.builder()
|
||||||
|
.typeMessage("VOCAL").urlFichier("https://example.com/audio.opus").build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.envoyerMessage(CONV_ID, req))
|
||||||
|
.isInstanceOf(BadRequestException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── getMessages ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getMessages — success → retourne liste de messages")
|
||||||
|
void getMessages_success() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
Message msg = buildMessage(conv);
|
||||||
|
when(conversationRepository.findConversationById(CONV_ID)).thenReturn(Optional.of(conv));
|
||||||
|
when(participantRepository.estParticipant(CONV_ID, MEMBRE_ID)).thenReturn(true);
|
||||||
|
when(messageRepository.findByConversationPagine(eq(CONV_ID), eq(0), anyInt()))
|
||||||
|
.thenReturn(List.of(msg));
|
||||||
|
|
||||||
|
List<MessageResponse> result = messagingService.getMessages(CONV_ID, 0);
|
||||||
|
|
||||||
|
assertThat(result).hasSize(1);
|
||||||
|
assertThat(result.get(0).getTypeMessage()).isEqualTo("TEXTE");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── marquerConversationLue ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("marquerConversationLue — participant trouvé → luJusqua mis à jour")
|
||||||
|
void marquerConversationLue_success() {
|
||||||
|
ConversationParticipant participant = new ConversationParticipant();
|
||||||
|
participant.setMembre(newMembre(MEMBRE_ID, "membre@test.com", "Alpha", "Diallo"));
|
||||||
|
when(participantRepository.findParticipant(CONV_ID, MEMBRE_ID))
|
||||||
|
.thenReturn(Optional.of(participant));
|
||||||
|
|
||||||
|
messagingService.marquerConversationLue(CONV_ID);
|
||||||
|
|
||||||
|
assertThat(participant.getLuJusqua()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("marquerConversationLue — participant absent → no-op")
|
||||||
|
void marquerConversationLue_noParticipant() {
|
||||||
|
when(participantRepository.findParticipant(CONV_ID, MEMBRE_ID))
|
||||||
|
.thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
// ne lève pas d'exception
|
||||||
|
messagingService.marquerConversationLue(CONV_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── supprimerMessage ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("supprimerMessage — message non trouvé → NotFoundException")
|
||||||
|
void supprimerMessage_notFound() {
|
||||||
|
when(messageRepository.findMessageById(MESSAGE_ID)).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.supprimerMessage(CONV_ID, MESSAGE_ID))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("supprimerMessage — message dans autre conversation → NotFoundException")
|
||||||
|
void supprimerMessage_wrongConversation() {
|
||||||
|
Conversation autreConv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
autreConv.setId(UUID.randomUUID()); // ID différent de CONV_ID
|
||||||
|
Message msg = buildMessage(autreConv);
|
||||||
|
when(messageRepository.findMessageById(MESSAGE_ID)).thenReturn(Optional.of(msg));
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.supprimerMessage(CONV_ID, MESSAGE_ID))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("supprimerMessage — pas l'auteur → ForbiddenException")
|
||||||
|
void supprimerMessage_notAuthor() {
|
||||||
|
Conversation conv = buildConversation(TypeConversation.DIRECTE);
|
||||||
|
Membre autreExpedireur = newMembre(DESTINATAIRE_ID, "other@test.com", "Beta", "Koné");
|
||||||
|
Message msg = new Message();
|
||||||
|
msg.setId(MESSAGE_ID);
|
||||||
|
msg.setConversation(conv);
|
||||||
|
msg.setExpediteur(autreExpedireur);
|
||||||
|
msg.setTypeMessage(TypeContenu.TEXTE);
|
||||||
|
msg.setContenu("Message d'un autre");
|
||||||
|
when(messageRepository.findMessageById(MESSAGE_ID)).thenReturn(Optional.of(msg));
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.supprimerMessage(CONV_ID, MESSAGE_ID))
|
||||||
|
.isInstanceOf(ForbiddenException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── bloquerMembre ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("bloquerMembre — soi-même → BadRequestException")
|
||||||
|
void bloquerMembre_soiMeme() {
|
||||||
|
BloquerMembreRequest req = BloquerMembreRequest.builder()
|
||||||
|
.membreABloquerId(MEMBRE_ID)
|
||||||
|
.organisationId(ORG_ID)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.bloquerMembre(req))
|
||||||
|
.isInstanceOf(BadRequestException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("bloquerMembre — membre introuvable → NotFoundException")
|
||||||
|
void bloquerMembre_destinataireInconnu() {
|
||||||
|
when(membreRepository.findById(DESTINATAIRE_ID)).thenReturn(null);
|
||||||
|
|
||||||
|
BloquerMembreRequest req = BloquerMembreRequest.builder()
|
||||||
|
.membreABloquerId(DESTINATAIRE_ID)
|
||||||
|
.organisationId(ORG_ID)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.bloquerMembre(req))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("bloquerMembre — déjà bloqué → BadRequestException")
|
||||||
|
void bloquerMembre_dejaBloque() {
|
||||||
|
Membre aBloquer = newMembre(DESTINATAIRE_ID, "dest@test.com", "Beta", "Koné");
|
||||||
|
when(membreRepository.findById(DESTINATAIRE_ID)).thenReturn(aBloquer);
|
||||||
|
when(memberBlockRepository.estBloque(MEMBRE_ID, DESTINATAIRE_ID, ORG_ID)).thenReturn(true);
|
||||||
|
|
||||||
|
BloquerMembreRequest req = BloquerMembreRequest.builder()
|
||||||
|
.membreABloquerId(DESTINATAIRE_ID)
|
||||||
|
.organisationId(ORG_ID)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.bloquerMembre(req))
|
||||||
|
.isInstanceOf(BadRequestException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── debloquerMembre ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("debloquerMembre — blocage non trouvé → NotFoundException")
|
||||||
|
void debloquerMembre_notFound() {
|
||||||
|
when(memberBlockRepository.findBlocage(MEMBRE_ID, DESTINATAIRE_ID, ORG_ID))
|
||||||
|
.thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> messagingService.debloquerMembre(DESTINATAIRE_ID, ORG_ID))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── getPolitique ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getPolitique — politique existante → retourne la politique")
|
||||||
|
void getPolitique_existing() {
|
||||||
|
Organisation org = newOrg();
|
||||||
|
ContactPolicy policy = ContactPolicy.builder()
|
||||||
|
.organisation(org)
|
||||||
|
.typePolitique(TypePolitiqueCommunication.BUREAU_SEULEMENT)
|
||||||
|
.autoriserMembreVersMembre(false)
|
||||||
|
.autoriserMembreVersRole(true)
|
||||||
|
.autoriserNotesVocales(true)
|
||||||
|
.build();
|
||||||
|
policy.setId(UUID.randomUUID());
|
||||||
|
|
||||||
|
when(contactPolicyRepository.findByOrganisationId(ORG_ID)).thenReturn(Optional.of(policy));
|
||||||
|
|
||||||
|
ContactPolicyResponse result = messagingService.getPolitique(ORG_ID);
|
||||||
|
|
||||||
|
assertThat(result.getTypePolitique()).isEqualTo("BUREAU_SEULEMENT");
|
||||||
|
assertThat(result.isAutoriserMembreVersMembre()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── mettreAJourPolitique ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("mettreAJourPolitique — change typePolitique")
|
||||||
|
void mettreAJourPolitique_changeType() {
|
||||||
|
Organisation org = newOrg();
|
||||||
|
ContactPolicy policy = ContactPolicy.builder()
|
||||||
|
.organisation(org)
|
||||||
|
.typePolitique(TypePolitiqueCommunication.OUVERT)
|
||||||
|
.autoriserMembreVersMembre(true)
|
||||||
|
.autoriserMembreVersRole(true)
|
||||||
|
.autoriserNotesVocales(true)
|
||||||
|
.build();
|
||||||
|
policy.setId(UUID.randomUUID());
|
||||||
|
|
||||||
|
when(contactPolicyRepository.findByOrganisationId(ORG_ID)).thenReturn(Optional.of(policy));
|
||||||
|
|
||||||
|
MettreAJourPolitiqueRequest req = MettreAJourPolitiqueRequest.builder()
|
||||||
|
.typePolitique("BUREAU_SEULEMENT")
|
||||||
|
.autoriserMembreVersMembre(false)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
ContactPolicyResponse result = messagingService.mettreAJourPolitique(ORG_ID, req);
|
||||||
|
|
||||||
|
assertThat(result.getTypePolitique()).isEqualTo("BUREAU_SEULEMENT");
|
||||||
|
assertThat(result.isAutoriserMembreVersMembre()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Helpers ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private Membre newMembre(UUID id, String email, String prenom, String nom) {
|
||||||
|
Membre m = new Membre();
|
||||||
|
m.setId(id);
|
||||||
|
m.setNumeroMembre("M-" + id.toString().substring(0, 4));
|
||||||
|
m.setPrenom(prenom);
|
||||||
|
m.setNom(nom);
|
||||||
|
m.setEmail(email);
|
||||||
|
m.setDateNaissance(LocalDate.now());
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Organisation newOrg() {
|
||||||
|
Organisation org = new Organisation();
|
||||||
|
org.setId(ORG_ID);
|
||||||
|
org.setNom("Tontine Test");
|
||||||
|
return org;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Conversation buildConversation(TypeConversation type) {
|
||||||
|
Conversation conv = new Conversation();
|
||||||
|
conv.setId(CONV_ID);
|
||||||
|
conv.setOrganisation(newOrg());
|
||||||
|
conv.setTypeConversation(type);
|
||||||
|
conv.setStatut(StatutConversation.ACTIVE);
|
||||||
|
conv.setNombreMessages(0);
|
||||||
|
return conv;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Message buildMessage(Conversation conv) {
|
||||||
|
Membre expediteur = newMembre(MEMBRE_ID, "membre@test.com", "Alpha", "Diallo");
|
||||||
|
Message msg = new Message();
|
||||||
|
msg.setId(MESSAGE_ID);
|
||||||
|
msg.setConversation(conv);
|
||||||
|
msg.setExpediteur(expediteur);
|
||||||
|
msg.setTypeMessage(TypeContenu.TEXTE);
|
||||||
|
msg.setContenu("Bonjour !");
|
||||||
|
msg.setDateCreation(LocalDateTime.now());
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> io.quarkus.hibernate.orm.panache.PanacheQuery<T> mockSingleResultQuery(T entity) {
|
||||||
|
io.quarkus.hibernate.orm.panache.PanacheQuery<T> query =
|
||||||
|
org.mockito.Mockito.mock(io.quarkus.hibernate.orm.panache.PanacheQuery.class);
|
||||||
|
when(query.firstResult()).thenReturn(entity);
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,755 @@
|
|||||||
|
package dev.lions.unionflow.server.service;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.request.DeclarerVersementManuelRequest;
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.request.InitierDepotEpargneRequest;
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.request.InitierVersementWaveRequest;
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.response.VersementGatewayResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.response.VersementResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.response.VersementStatutResponse;
|
||||||
|
import dev.lions.unionflow.server.api.dto.versement.response.VersementSummaryResponse;
|
||||||
|
import dev.lions.unionflow.server.api.enums.paiement.StatutIntentionPaiement;
|
||||||
|
import dev.lions.unionflow.server.entity.Cotisation;
|
||||||
|
import dev.lions.unionflow.server.entity.IntentionPaiement;
|
||||||
|
import dev.lions.unionflow.server.entity.Membre;
|
||||||
|
import dev.lions.unionflow.server.entity.Organisation;
|
||||||
|
import dev.lions.unionflow.server.entity.Versement;
|
||||||
|
import dev.lions.unionflow.server.entity.mutuelle.epargne.CompteEpargne;
|
||||||
|
import dev.lions.unionflow.server.repository.IntentionPaiementRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.MembreOrganisationRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.MembreRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.TypeReferenceRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.VersementRepository;
|
||||||
|
import dev.lions.unionflow.server.repository.mutuelle.epargne.CompteEpargneRepository;
|
||||||
|
import dev.lions.unionflow.server.service.WaveCheckoutService.WaveCheckoutException;
|
||||||
|
import dev.lions.unionflow.server.service.WaveCheckoutService.WaveCheckoutSessionResponse;
|
||||||
|
import io.quarkus.test.InjectMock;
|
||||||
|
import io.quarkus.test.junit.QuarkusTest;
|
||||||
|
import io.quarkus.test.security.TestSecurity;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.TypedQuery;
|
||||||
|
import jakarta.ws.rs.NotFoundException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests unitaires pour {@link VersementService}.
|
||||||
|
*
|
||||||
|
* Couverture : trouverParId, trouverParNumeroReference, listerParMembre,
|
||||||
|
* calculerMontantTotalConfirmes, getMesVersements, validerVersement,
|
||||||
|
* annulerVersement, initierVersementWave (succès + Wave error + cotisation
|
||||||
|
* inconnue + cotisation d'un autre membre), declarerVersementManuel,
|
||||||
|
* verifierStatutVersement (complété / expiré / en attente),
|
||||||
|
* confirmerVersementWave (idempotence), toE164 (toutes branches).
|
||||||
|
*/
|
||||||
|
@QuarkusTest
|
||||||
|
@DisplayName("VersementService")
|
||||||
|
class VersementServiceTest {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
VersementService versementService;
|
||||||
|
|
||||||
|
@InjectMock VersementRepository versementRepository;
|
||||||
|
@InjectMock MembreRepository membreRepository;
|
||||||
|
@InjectMock KeycloakService keycloakService;
|
||||||
|
@InjectMock TypeReferenceRepository typeReferenceRepository;
|
||||||
|
@InjectMock IntentionPaiementRepository intentionPaiementRepository;
|
||||||
|
@InjectMock WaveCheckoutService waveCheckoutService;
|
||||||
|
@InjectMock CompteEpargneRepository compteEpargneRepository;
|
||||||
|
@InjectMock MembreOrganisationRepository membreOrganisationRepository;
|
||||||
|
@InjectMock NotificationService notificationService;
|
||||||
|
|
||||||
|
private Membre testMembre;
|
||||||
|
private Membre autreMembre;
|
||||||
|
private Organisation testOrg;
|
||||||
|
private Cotisation testCotisation;
|
||||||
|
private Versement testVersement;
|
||||||
|
private CompteEpargne testCompte;
|
||||||
|
private EntityManager mockEm;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
testOrg = new Organisation();
|
||||||
|
testOrg.setId(UUID.randomUUID());
|
||||||
|
testOrg.setNom("Org Test");
|
||||||
|
|
||||||
|
testMembre = new Membre();
|
||||||
|
testMembre.setId(UUID.randomUUID());
|
||||||
|
testMembre.setNumeroMembre("M001");
|
||||||
|
testMembre.setEmail("membre@test.com");
|
||||||
|
testMembre.setPrenom("Jean");
|
||||||
|
testMembre.setNom("Dupont");
|
||||||
|
testMembre.setDateNaissance(LocalDate.of(1990, 1, 1));
|
||||||
|
|
||||||
|
autreMembre = new Membre();
|
||||||
|
autreMembre.setId(UUID.randomUUID());
|
||||||
|
autreMembre.setNumeroMembre("M002");
|
||||||
|
autreMembre.setEmail("autre@test.com");
|
||||||
|
autreMembre.setDateNaissance(LocalDate.of(1985, 5, 15));
|
||||||
|
|
||||||
|
testCotisation = new Cotisation();
|
||||||
|
testCotisation.setId(UUID.randomUUID());
|
||||||
|
testCotisation.setNumeroReference("COT-2026-001");
|
||||||
|
testCotisation.setMembre(testMembre);
|
||||||
|
testCotisation.setOrganisation(testOrg);
|
||||||
|
testCotisation.setMontantDu(new BigDecimal("5000"));
|
||||||
|
testCotisation.setCodeDevise("XOF");
|
||||||
|
testCotisation.setStatut("EN_ATTENTE");
|
||||||
|
testCotisation.setDateEcheance(LocalDate.now().plusDays(30));
|
||||||
|
testCotisation.setTypeCotisation("MENSUELLE");
|
||||||
|
testCotisation.setLibelle("Cotisation janvier 2026");
|
||||||
|
testCotisation.setAnnee(2026);
|
||||||
|
|
||||||
|
testVersement = new Versement();
|
||||||
|
testVersement.setId(UUID.randomUUID());
|
||||||
|
testVersement.setNumeroReference("VRS-2026-001");
|
||||||
|
testVersement.setMontant(new BigDecimal("5000"));
|
||||||
|
testVersement.setCodeDevise("XOF");
|
||||||
|
testVersement.setMethodePaiement("WAVE");
|
||||||
|
testVersement.setStatutPaiement("EN_ATTENTE");
|
||||||
|
testVersement.setMembre(testMembre);
|
||||||
|
testVersement.setDatePaiement(LocalDateTime.now());
|
||||||
|
|
||||||
|
testCompte = new CompteEpargne();
|
||||||
|
testCompte.setId(UUID.randomUUID());
|
||||||
|
testCompte.setMembre(testMembre);
|
||||||
|
testCompte.setOrganisation(testOrg);
|
||||||
|
|
||||||
|
mockEm = mock(EntityManager.class);
|
||||||
|
when(versementRepository.getEntityManager()).thenReturn(mockEm);
|
||||||
|
when(typeReferenceRepository.findByDomaineAndCode(anyString(), anyString()))
|
||||||
|
.thenReturn(Optional.empty());
|
||||||
|
when(keycloakService.getCurrentUserEmail()).thenReturn(testMembre.getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── trouverParId ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("trouverParId — trouvé → retourne response")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void trouverParId_found() {
|
||||||
|
when(versementRepository.findVersementById(testVersement.getId()))
|
||||||
|
.thenReturn(Optional.of(testVersement));
|
||||||
|
|
||||||
|
VersementResponse r = versementService.trouverParId(testVersement.getId());
|
||||||
|
|
||||||
|
assertThat(r.getNumeroReference()).isEqualTo("VRS-2026-001");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("trouverParId — non trouvé → NotFoundException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void trouverParId_notFound() {
|
||||||
|
when(versementRepository.findVersementById(any())).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.trouverParId(UUID.randomUUID()))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── trouverParNumeroReference ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("trouverParNumeroReference — trouvé → response")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void trouverParNumeroReference_found() {
|
||||||
|
when(versementRepository.findByNumeroReference("VRS-2026-001"))
|
||||||
|
.thenReturn(Optional.of(testVersement));
|
||||||
|
|
||||||
|
VersementResponse r = versementService.trouverParNumeroReference("VRS-2026-001");
|
||||||
|
assertThat(r).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("trouverParNumeroReference — non trouvé → NotFoundException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void trouverParNumeroReference_notFound() {
|
||||||
|
when(versementRepository.findByNumeroReference(anyString())).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.trouverParNumeroReference("VRS-INCONNU"))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── listerParMembre ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("listerParMembre — retourne liste non nulle")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void listerParMembre_returnsList() {
|
||||||
|
when(versementRepository.findByMembreId(testMembre.getId()))
|
||||||
|
.thenReturn(List.of(testVersement));
|
||||||
|
|
||||||
|
List<VersementSummaryResponse> list = versementService.listerParMembre(testMembre.getId());
|
||||||
|
assertThat(list).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── calculerMontantTotalConfirmes ─────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("calculerMontantTotalConfirmes — délègue au repository")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void calculerMontantTotalConfirmes_delegates() {
|
||||||
|
LocalDateTime debut = LocalDateTime.now().minusDays(30);
|
||||||
|
LocalDateTime fin = LocalDateTime.now();
|
||||||
|
when(versementRepository.calculerMontantTotalConfirmes(debut, fin))
|
||||||
|
.thenReturn(new BigDecimal("15000"));
|
||||||
|
|
||||||
|
BigDecimal total = versementService.calculerMontantTotalConfirmes(debut, fin);
|
||||||
|
assertThat(total).isEqualByComparingTo("15000");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── getMesVersements ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getMesVersements — retourne historique du membre connecté")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void getMesVersements_returnsHistory() {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
TypedQuery<Versement> query = mock(TypedQuery.class);
|
||||||
|
doReturn(query).when(mockEm).createQuery(anyString(), any());
|
||||||
|
when(query.setParameter(anyString(), any())).thenReturn(query);
|
||||||
|
when(query.setMaxResults(anyInt())).thenReturn(query);
|
||||||
|
when(query.getResultList()).thenReturn(List.of(testVersement));
|
||||||
|
|
||||||
|
List<VersementSummaryResponse> list = versementService.getMesVersements(5);
|
||||||
|
assertThat(list).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("getMesVersements — membre non trouvé → NotFoundException")
|
||||||
|
@TestSecurity(user = "inconnu@test.com", roles = {"MEMBRE"})
|
||||||
|
void getMesVersements_memberNotFound() {
|
||||||
|
when(membreRepository.findByEmail(anyString())).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.getMesVersements(5))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── validerVersement ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("validerVersement — passe à CONFIRME")
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void validerVersement_setsConfirme() {
|
||||||
|
when(versementRepository.findVersementById(testVersement.getId()))
|
||||||
|
.thenReturn(Optional.of(testVersement));
|
||||||
|
|
||||||
|
VersementResponse r = versementService.validerVersement(testVersement.getId());
|
||||||
|
assertThat(r.getStatutPaiement()).isEqualTo("CONFIRME");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("validerVersement — déjà confirmé → idempotent")
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void validerVersement_alreadyConfirme_idempotent() {
|
||||||
|
testVersement.setStatutPaiement("CONFIRME");
|
||||||
|
when(versementRepository.findVersementById(testVersement.getId()))
|
||||||
|
.thenReturn(Optional.of(testVersement));
|
||||||
|
|
||||||
|
VersementResponse r = versementService.validerVersement(testVersement.getId());
|
||||||
|
assertThat(r.getStatutPaiement()).isEqualTo("CONFIRME");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("validerVersement — non trouvé → NotFoundException")
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void validerVersement_notFound() {
|
||||||
|
when(versementRepository.findVersementById(any())).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.validerVersement(UUID.randomUUID()))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── annulerVersement ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("annulerVersement — passe à ANNULE")
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void annulerVersement_setsAnnule() {
|
||||||
|
when(versementRepository.findVersementById(testVersement.getId()))
|
||||||
|
.thenReturn(Optional.of(testVersement));
|
||||||
|
|
||||||
|
VersementResponse r = versementService.annulerVersement(testVersement.getId());
|
||||||
|
assertThat(r.getStatutPaiement()).isEqualTo("ANNULE");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("annulerVersement — déjà ANNULE → IllegalStateException")
|
||||||
|
@TestSecurity(user = "admin@test.com", roles = {"ADMIN"})
|
||||||
|
void annulerVersement_alreadyAnnule() {
|
||||||
|
testVersement.setStatutPaiement("ANNULE");
|
||||||
|
when(versementRepository.findVersementById(testVersement.getId()))
|
||||||
|
.thenReturn(Optional.of(testVersement));
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.annulerVersement(testVersement.getId()))
|
||||||
|
.isInstanceOf(IllegalStateException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── initierVersementWave ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("initierVersementWave — succès Wave → retourne waveLaunchUrl")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierVersementWave_success() throws WaveCheckoutException {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
when(mockEm.find(Cotisation.class, testCotisation.getId()))
|
||||||
|
.thenReturn(testCotisation);
|
||||||
|
when(waveCheckoutService.getRedirectBaseUrl()).thenReturn("https://api.test.com");
|
||||||
|
|
||||||
|
WaveCheckoutSessionResponse session = new WaveCheckoutSessionResponse("cos-abc123", "wave://checkout/abc123");
|
||||||
|
when(waveCheckoutService.createSession(
|
||||||
|
anyString(), anyString(), anyString(), anyString(), anyString(), anyString()))
|
||||||
|
.thenReturn(session);
|
||||||
|
doAnswer(inv -> null).when(intentionPaiementRepository).persist(any(IntentionPaiement.class));
|
||||||
|
doAnswer(inv -> null).when(versementRepository).persist(any(Versement.class));
|
||||||
|
when(mockEm.merge(any())).thenReturn(testCotisation);
|
||||||
|
|
||||||
|
InitierVersementWaveRequest request = InitierVersementWaveRequest.builder()
|
||||||
|
.cotisationId(testCotisation.getId())
|
||||||
|
.numeroTelephone("771234567")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
VersementGatewayResponse r = versementService.initierVersementWave(request);
|
||||||
|
|
||||||
|
assertThat(r.getWaveLaunchUrl()).isEqualTo("wave://checkout/abc123");
|
||||||
|
assertThat(r.getWaveCheckoutSessionId()).isEqualTo("cos-abc123");
|
||||||
|
assertThat(r.getMontant()).isEqualByComparingTo("5000");
|
||||||
|
assertThat(r.getClientReference()).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("initierVersementWave — cotisation inconnue → NotFoundException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierVersementWave_cotisationInconnue() {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
when(mockEm.find(Cotisation.class, any())).thenReturn(null);
|
||||||
|
|
||||||
|
InitierVersementWaveRequest request = InitierVersementWaveRequest.builder()
|
||||||
|
.cotisationId(UUID.randomUUID())
|
||||||
|
.numeroTelephone("771234567")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.initierVersementWave(request))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("initierVersementWave — cotisation d'un autre membre → IllegalArgumentException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierVersementWave_cotisationAutreMembre() {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
testCotisation.setMembre(autreMembre);
|
||||||
|
when(mockEm.find(Cotisation.class, testCotisation.getId()))
|
||||||
|
.thenReturn(testCotisation);
|
||||||
|
|
||||||
|
InitierVersementWaveRequest request = InitierVersementWaveRequest.builder()
|
||||||
|
.cotisationId(testCotisation.getId())
|
||||||
|
.numeroTelephone("771234567")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.initierVersementWave(request))
|
||||||
|
.isInstanceOf(IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("initierVersementWave — Wave API error → BadRequestException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierVersementWave_waveApiError() throws WaveCheckoutException {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
when(mockEm.find(Cotisation.class, testCotisation.getId()))
|
||||||
|
.thenReturn(testCotisation);
|
||||||
|
when(waveCheckoutService.getRedirectBaseUrl()).thenReturn("https://api.test.com");
|
||||||
|
doAnswer(inv -> null).when(intentionPaiementRepository).persist(any(IntentionPaiement.class));
|
||||||
|
doThrow(new WaveCheckoutException("Wave down"))
|
||||||
|
.when(waveCheckoutService).createSession(
|
||||||
|
anyString(), anyString(), anyString(), anyString(), anyString(), anyString());
|
||||||
|
|
||||||
|
InitierVersementWaveRequest request = InitierVersementWaveRequest.builder()
|
||||||
|
.cotisationId(testCotisation.getId())
|
||||||
|
.numeroTelephone("771234567")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.initierVersementWave(request))
|
||||||
|
.isInstanceOf(jakarta.ws.rs.BadRequestException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("initierVersementWave — sans numéro téléphone (web QR) → successUrl web")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierVersementWave_noPhone_webContext() throws WaveCheckoutException {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
when(mockEm.find(Cotisation.class, testCotisation.getId()))
|
||||||
|
.thenReturn(testCotisation);
|
||||||
|
when(waveCheckoutService.getRedirectBaseUrl()).thenReturn("https://api.test.com");
|
||||||
|
|
||||||
|
WaveCheckoutSessionResponse session = new WaveCheckoutSessionResponse("cos-web", "wave://checkout/web");
|
||||||
|
when(waveCheckoutService.createSession(
|
||||||
|
anyString(), anyString(), anyString(), anyString(), anyString(), anyString()))
|
||||||
|
.thenReturn(session);
|
||||||
|
doAnswer(inv -> null).when(intentionPaiementRepository).persist(any(IntentionPaiement.class));
|
||||||
|
doAnswer(inv -> null).when(versementRepository).persist(any(Versement.class));
|
||||||
|
when(mockEm.merge(any())).thenReturn(testCotisation);
|
||||||
|
|
||||||
|
InitierVersementWaveRequest request = InitierVersementWaveRequest.builder()
|
||||||
|
.cotisationId(testCotisation.getId())
|
||||||
|
.build(); // pas de numéro → web
|
||||||
|
|
||||||
|
VersementGatewayResponse r = versementService.initierVersementWave(request);
|
||||||
|
assertThat(r.getWaveLaunchUrl()).isEqualTo("wave://checkout/web");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── initierDepotEpargneEnLigne ────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("initierDepotEpargneEnLigne — succès Wave")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierDepotEpargne_success() throws WaveCheckoutException {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
when(compteEpargneRepository.findByIdOptional(testCompte.getId()))
|
||||||
|
.thenReturn(Optional.of(testCompte));
|
||||||
|
when(waveCheckoutService.getRedirectBaseUrl()).thenReturn("https://api.test.com");
|
||||||
|
|
||||||
|
WaveCheckoutSessionResponse session = new WaveCheckoutSessionResponse("cos-epargne", "wave://checkout/epargne");
|
||||||
|
when(waveCheckoutService.createSession(
|
||||||
|
anyString(), anyString(), anyString(), anyString(), anyString(), anyString()))
|
||||||
|
.thenReturn(session);
|
||||||
|
doAnswer(inv -> null).when(intentionPaiementRepository).persist(any(IntentionPaiement.class));
|
||||||
|
|
||||||
|
InitierDepotEpargneRequest request = InitierDepotEpargneRequest.builder()
|
||||||
|
.compteId(testCompte.getId())
|
||||||
|
.montant(new BigDecimal("10000"))
|
||||||
|
.numeroTelephone("771234567")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
VersementGatewayResponse r = versementService.initierDepotEpargneEnLigne(request);
|
||||||
|
assertThat(r.getWaveLaunchUrl()).isEqualTo("wave://checkout/epargne");
|
||||||
|
assertThat(r.getMontant()).isEqualByComparingTo("10000");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("initierDepotEpargneEnLigne — compte inconnu → NotFoundException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierDepotEpargne_compteInconnu() {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
when(compteEpargneRepository.findByIdOptional(any())).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.initierDepotEpargneEnLigne(
|
||||||
|
InitierDepotEpargneRequest.builder()
|
||||||
|
.compteId(UUID.randomUUID())
|
||||||
|
.montant(BigDecimal.TEN)
|
||||||
|
.build()))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("initierDepotEpargneEnLigne — compte d'un autre membre → IllegalArgumentException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierDepotEpargne_compteAutreMembre() {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
testCompte.setMembre(autreMembre);
|
||||||
|
when(compteEpargneRepository.findByIdOptional(testCompte.getId()))
|
||||||
|
.thenReturn(Optional.of(testCompte));
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.initierDepotEpargneEnLigne(
|
||||||
|
InitierDepotEpargneRequest.builder()
|
||||||
|
.compteId(testCompte.getId())
|
||||||
|
.montant(BigDecimal.TEN)
|
||||||
|
.build()))
|
||||||
|
.isInstanceOf(IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("initierDepotEpargneEnLigne — Wave error → BadRequestException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void initierDepotEpargne_waveError() throws WaveCheckoutException {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
when(compteEpargneRepository.findByIdOptional(testCompte.getId()))
|
||||||
|
.thenReturn(Optional.of(testCompte));
|
||||||
|
when(waveCheckoutService.getRedirectBaseUrl()).thenReturn("https://api.test.com");
|
||||||
|
doAnswer(inv -> null).when(intentionPaiementRepository).persist(any(IntentionPaiement.class));
|
||||||
|
doThrow(new WaveCheckoutException("Wave down"))
|
||||||
|
.when(waveCheckoutService).createSession(
|
||||||
|
anyString(), anyString(), anyString(), anyString(), anyString(), anyString());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.initierDepotEpargneEnLigne(
|
||||||
|
InitierDepotEpargneRequest.builder()
|
||||||
|
.compteId(testCompte.getId())
|
||||||
|
.montant(BigDecimal.TEN)
|
||||||
|
.build()))
|
||||||
|
.isInstanceOf(jakarta.ws.rs.BadRequestException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── declarerVersementManuel ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("declarerVersementManuel — créé EN_ATTENTE_VALIDATION")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void declarerVersementManuel_success() {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
TypedQuery<Cotisation> query = mock(TypedQuery.class);
|
||||||
|
doReturn(query).when(mockEm).createQuery(anyString(), any());
|
||||||
|
when(query.setParameter(anyString(), any())).thenReturn(query);
|
||||||
|
when(query.getResultList()).thenReturn(List.of(testCotisation));
|
||||||
|
doAnswer(inv -> null).when(versementRepository).persist(any(Versement.class));
|
||||||
|
when(membreOrganisationRepository.findFirstByMembreId(any()))
|
||||||
|
.thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
DeclarerVersementManuelRequest request = DeclarerVersementManuelRequest.builder()
|
||||||
|
.cotisationId(testCotisation.getId())
|
||||||
|
.methodePaiement("ESPECES")
|
||||||
|
.commentaire("Remis en main propre")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
VersementResponse r = versementService.declarerVersementManuel(request);
|
||||||
|
assertThat(r.getStatutPaiement()).isEqualTo("EN_ATTENTE_VALIDATION");
|
||||||
|
assertThat(r.getMethodePaiement()).isEqualTo("ESPECES");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("declarerVersementManuel — cotisation inconnue → NotFoundException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void declarerVersementManuel_cotisationInconnue() {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
TypedQuery<Cotisation> query = mock(TypedQuery.class);
|
||||||
|
doReturn(query).when(mockEm).createQuery(anyString(), any());
|
||||||
|
when(query.setParameter(anyString(), any())).thenReturn(query);
|
||||||
|
when(query.getResultList()).thenReturn(Collections.emptyList());
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.declarerVersementManuel(
|
||||||
|
DeclarerVersementManuelRequest.builder()
|
||||||
|
.cotisationId(UUID.randomUUID())
|
||||||
|
.methodePaiement("ESPECES")
|
||||||
|
.build()))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("declarerVersementManuel — cotisation d'un autre membre → IllegalArgumentException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void declarerVersementManuel_cotisationAutreMembre() {
|
||||||
|
when(membreRepository.findByEmail("membre@test.com"))
|
||||||
|
.thenReturn(Optional.of(testMembre));
|
||||||
|
testCotisation.setMembre(autreMembre);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
TypedQuery<Cotisation> query = mock(TypedQuery.class);
|
||||||
|
doReturn(query).when(mockEm).createQuery(anyString(), any());
|
||||||
|
when(query.setParameter(anyString(), any())).thenReturn(query);
|
||||||
|
when(query.getResultList()).thenReturn(List.of(testCotisation));
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.declarerVersementManuel(
|
||||||
|
DeclarerVersementManuelRequest.builder()
|
||||||
|
.cotisationId(testCotisation.getId())
|
||||||
|
.methodePaiement("ESPECES")
|
||||||
|
.build()))
|
||||||
|
.isInstanceOf(IllegalArgumentException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── verifierStatutVersement ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("verifierStatutVersement — intention inconnue → NotFoundException")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void verifierStatutVersement_notFound() {
|
||||||
|
when(intentionPaiementRepository.findById(any())).thenReturn(null);
|
||||||
|
|
||||||
|
assertThatThrownBy(() -> versementService.verifierStatutVersement(UUID.randomUUID()))
|
||||||
|
.isInstanceOf(NotFoundException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("verifierStatutVersement — déjà COMPLETEE → confirme=true")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void verifierStatutVersement_completee() {
|
||||||
|
IntentionPaiement intention = buildIntention(StatutIntentionPaiement.COMPLETEE);
|
||||||
|
when(intentionPaiementRepository.findById(intention.getId()))
|
||||||
|
.thenReturn(intention);
|
||||||
|
|
||||||
|
VersementStatutResponse r = versementService.verifierStatutVersement(intention.getId());
|
||||||
|
assertThat(r.isConfirme()).isTrue();
|
||||||
|
assertThat(r.getMessage()).contains("confirmé");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("verifierStatutVersement — EXPIREE → confirme=false")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void verifierStatutVersement_expiree() {
|
||||||
|
IntentionPaiement intention = buildIntention(StatutIntentionPaiement.EXPIREE);
|
||||||
|
when(intentionPaiementRepository.findById(intention.getId()))
|
||||||
|
.thenReturn(intention);
|
||||||
|
|
||||||
|
VersementStatutResponse r = versementService.verifierStatutVersement(intention.getId());
|
||||||
|
assertThat(r.isConfirme()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("verifierStatutVersement — ECHOUEE → confirme=false")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void verifierStatutVersement_echouee() {
|
||||||
|
IntentionPaiement intention = buildIntention(StatutIntentionPaiement.ECHOUEE);
|
||||||
|
when(intentionPaiementRepository.findById(intention.getId()))
|
||||||
|
.thenReturn(intention);
|
||||||
|
|
||||||
|
VersementStatutResponse r = versementService.verifierStatutVersement(intention.getId());
|
||||||
|
assertThat(r.isConfirme()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("verifierStatutVersement — session expirée localement → EXPIREE")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void verifierStatutVersement_localExpiry() {
|
||||||
|
IntentionPaiement intention = buildIntention(StatutIntentionPaiement.EN_COURS);
|
||||||
|
intention.setDateExpiration(LocalDateTime.now().minusMinutes(5));
|
||||||
|
when(intentionPaiementRepository.findById(intention.getId()))
|
||||||
|
.thenReturn(intention);
|
||||||
|
|
||||||
|
VersementStatutResponse r = versementService.verifierStatutVersement(intention.getId());
|
||||||
|
assertThat(r.getStatut()).isEqualTo("EXPIREE");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("verifierStatutVersement — EN_COURS sans session Wave → en attente")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void verifierStatutVersement_enCoursNoSession() {
|
||||||
|
IntentionPaiement intention = buildIntention(StatutIntentionPaiement.EN_COURS);
|
||||||
|
intention.setDateExpiration(LocalDateTime.now().plusMinutes(25));
|
||||||
|
when(intentionPaiementRepository.findById(intention.getId()))
|
||||||
|
.thenReturn(intention);
|
||||||
|
|
||||||
|
VersementStatutResponse r = versementService.verifierStatutVersement(intention.getId());
|
||||||
|
assertThat(r.isConfirme()).isFalse();
|
||||||
|
assertThat(r.getMessage()).containsIgnoringCase("attente");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── confirmerVersementWave ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("confirmerVersementWave — déjà COMPLETEE → idempotent")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void confirmerVersementWave_alreadyCompletee_idempotent() {
|
||||||
|
IntentionPaiement intention = buildIntention(StatutIntentionPaiement.COMPLETEE);
|
||||||
|
// Ne doit pas appeler persist
|
||||||
|
versementService.confirmerVersementWave(intention, null);
|
||||||
|
// Pas d'exception = idempotence OK
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("confirmerVersementWave — objetsCibles null → passe sans erreur")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void confirmerVersementWave_nullObjetsCibles() {
|
||||||
|
IntentionPaiement intention = buildIntention(StatutIntentionPaiement.EN_COURS);
|
||||||
|
intention.setObjetsCibles(null);
|
||||||
|
doAnswer(inv -> null).when(intentionPaiementRepository).persist(any(IntentionPaiement.class));
|
||||||
|
|
||||||
|
versementService.confirmerVersementWave(intention, "TCN-123");
|
||||||
|
|
||||||
|
assertThat(intention.getStatut()).isEqualTo(StatutIntentionPaiement.COMPLETEE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("confirmerVersementWave — JSON cotisation → mise à jour cotisation")
|
||||||
|
@TestSecurity(user = "membre@test.com", roles = {"MEMBRE"})
|
||||||
|
void confirmerVersementWave_reconcilesCotisation() {
|
||||||
|
UUID cotisationId = testCotisation.getId();
|
||||||
|
IntentionPaiement intention = buildIntention(StatutIntentionPaiement.EN_COURS);
|
||||||
|
intention.setObjetsCibles(
|
||||||
|
"[{\"type\":\"COTISATION\",\"id\":\"" + cotisationId + "\",\"montant\":5000}]");
|
||||||
|
doAnswer(inv -> null).when(intentionPaiementRepository).persist(any(IntentionPaiement.class));
|
||||||
|
when(mockEm.find(Cotisation.class, cotisationId)).thenReturn(testCotisation);
|
||||||
|
when(mockEm.merge(any())).thenReturn(testCotisation);
|
||||||
|
|
||||||
|
versementService.confirmerVersementWave(intention, "TCN-ABC");
|
||||||
|
|
||||||
|
assertThat(testCotisation.getStatut()).isEqualTo("PAYEE");
|
||||||
|
assertThat(testCotisation.getMontantPaye()).isEqualByComparingTo("5000");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── toE164 ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toE164 — null → null")
|
||||||
|
void toE164_null() {
|
||||||
|
assertThat(VersementService.toE164(null)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toE164 — vide → null")
|
||||||
|
void toE164_blank() {
|
||||||
|
assertThat(VersementService.toE164(" ")).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toE164 — 9 chiffres commençant par 7 → +221 prefix")
|
||||||
|
void toE164_9digits_7prefix() {
|
||||||
|
assertThat(VersementService.toE164("771234567")).isEqualTo("+221771234567");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toE164 — 9 chiffres commençant par 0 → +221 + supprime 0")
|
||||||
|
void toE164_9digits_0prefix() {
|
||||||
|
assertThat(VersementService.toE164("071234567")).isEqualTo("+22171234567");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toE164 — déjà avec indicatif 221 → ajoute +")
|
||||||
|
void toE164_with221prefix() {
|
||||||
|
assertThat(VersementService.toE164("221771234567")).isEqualTo("+221771234567");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toE164 — déjà au format E.164 (+221...) → conservé")
|
||||||
|
void toE164_alreadyE164() {
|
||||||
|
assertThat(VersementService.toE164("+221771234567")).isEqualTo("+221771234567");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("toE164 — format non reconnu → + + chiffres")
|
||||||
|
void toE164_unknown() {
|
||||||
|
assertThat(VersementService.toE164("0033612345678")).startsWith("+");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── helpers ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private IntentionPaiement buildIntention(StatutIntentionPaiement statut) {
|
||||||
|
IntentionPaiement i = new IntentionPaiement();
|
||||||
|
i.setId(UUID.randomUUID());
|
||||||
|
i.setStatut(statut);
|
||||||
|
i.setMontantTotal(new BigDecimal("5000"));
|
||||||
|
i.setCodeDevise("XOF");
|
||||||
|
i.setUtilisateur(testMembre);
|
||||||
|
i.setDateExpiration(LocalDateTime.now().plusMinutes(30));
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user