Files
unionflow-server-impl-quarkus/src/test/java/dev/lions/unionflow/server/entity/TransactionApprovalTest.java
2026-03-28 14:21:30 +00:00

323 lines
12 KiB
Java

package dev.lions.unionflow.server.entity;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
@DisplayName("TransactionApproval")
class TransactionApprovalTest {
private static Organisation newOrganisation() {
Organisation o = new Organisation();
o.setId(UUID.randomUUID());
return o;
}
private static ApproverAction approvedAction() {
ApproverAction a = new ApproverAction();
a.setApproverId(UUID.randomUUID());
a.setApproverName("Approver Test");
a.setApproverRole("TRESORIER");
a.setDecision("APPROVED");
return a;
}
private static ApproverAction pendingAction() {
ApproverAction a = new ApproverAction();
a.setApproverId(UUID.randomUUID());
a.setApproverName("Approver Pending");
a.setApproverRole("PRESIDENT");
a.setDecision("PENDING");
return a;
}
// -------------------------------------------------------------------------
// getRequiredApprovals
// -------------------------------------------------------------------------
@Test
@DisplayName("getRequiredApprovals: NONE renvoie 0")
void getRequiredApprovals_none_returns0() {
TransactionApproval ta = new TransactionApproval();
ta.setRequiredLevel("NONE");
assertThat(ta.getRequiredApprovals()).isEqualTo(0);
}
@Test
@DisplayName("getRequiredApprovals: LEVEL1 renvoie 1")
void getRequiredApprovals_level1_returns1() {
TransactionApproval ta = new TransactionApproval();
ta.setRequiredLevel("LEVEL1");
assertThat(ta.getRequiredApprovals()).isEqualTo(1);
}
@Test
@DisplayName("getRequiredApprovals: LEVEL2 renvoie 2")
void getRequiredApprovals_level2_returns2() {
TransactionApproval ta = new TransactionApproval();
ta.setRequiredLevel("LEVEL2");
assertThat(ta.getRequiredApprovals()).isEqualTo(2);
}
@Test
@DisplayName("getRequiredApprovals: LEVEL3 renvoie 3")
void getRequiredApprovals_level3_returns3() {
TransactionApproval ta = new TransactionApproval();
ta.setRequiredLevel("LEVEL3");
assertThat(ta.getRequiredApprovals()).isEqualTo(3);
}
@Test
@DisplayName("getRequiredApprovals: valeur inconnue renvoie 0 (default)")
void getRequiredApprovals_default_returns0() {
TransactionApproval ta = new TransactionApproval();
ta.setRequiredLevel("INVALID");
assertThat(ta.getRequiredApprovals()).isEqualTo(0);
}
// -------------------------------------------------------------------------
// countApprovals
// -------------------------------------------------------------------------
@Test
@DisplayName("countApprovals: aucun approbateur renvoie 0")
void countApprovals_noApprovers_returns0() {
TransactionApproval ta = TransactionApproval.builder()
.transactionId(UUID.randomUUID())
.transactionType("CONTRIBUTION")
.amount(new BigDecimal("5000.00"))
.requesterId(UUID.randomUUID())
.requesterName("Test Requester")
.requiredLevel("LEVEL1")
.build();
assertThat(ta.countApprovals()).isEqualTo(0);
}
@Test
@DisplayName("countApprovals: seuls les APPROVED sont comptés")
void countApprovals_mixedDecisions_countsApprovedOnly() {
TransactionApproval ta = TransactionApproval.builder()
.transactionId(UUID.randomUUID())
.transactionType("DEPOSIT")
.amount(new BigDecimal("10000.00"))
.requesterId(UUID.randomUUID())
.requesterName("Requester")
.requiredLevel("LEVEL2")
.build();
ta.addApproverAction(approvedAction());
ta.addApproverAction(pendingAction());
ta.addApproverAction(approvedAction());
assertThat(ta.countApprovals()).isEqualTo(2);
}
// -------------------------------------------------------------------------
// hasAllApprovals
// -------------------------------------------------------------------------
@Test
@DisplayName("hasAllApprovals: NONE sans approbateur renvoie toujours true")
void hasAllApprovals_none_alwaysTrue() {
TransactionApproval ta = new TransactionApproval();
ta.setRequiredLevel("NONE");
assertThat(ta.hasAllApprovals()).isTrue();
}
@Test
@DisplayName("hasAllApprovals: LEVEL1 avec une approbation renvoie true")
void hasAllApprovals_level1_oneApproval_true() {
TransactionApproval ta = TransactionApproval.builder()
.transactionId(UUID.randomUUID())
.transactionType("CONTRIBUTION")
.amount(new BigDecimal("1000.00"))
.requesterId(UUID.randomUUID())
.requesterName("Requester")
.requiredLevel("LEVEL1")
.build();
ta.addApproverAction(approvedAction());
assertThat(ta.hasAllApprovals()).isTrue();
}
@Test
@DisplayName("hasAllApprovals: LEVEL2 avec une seule approbation renvoie false")
void hasAllApprovals_level2_onlyOneApproval_false() {
TransactionApproval ta = TransactionApproval.builder()
.transactionId(UUID.randomUUID())
.transactionType("WITHDRAWAL")
.amount(new BigDecimal("50000.00"))
.requesterId(UUID.randomUUID())
.requesterName("Requester")
.requiredLevel("LEVEL2")
.build();
ta.addApproverAction(approvedAction());
assertThat(ta.hasAllApprovals()).isFalse();
}
// -------------------------------------------------------------------------
// addApproverAction
// -------------------------------------------------------------------------
@Test
@DisplayName("addApproverAction: ajoute l'action et positionne le parent")
void addApproverAction_setsParentAndAdds() {
TransactionApproval ta = TransactionApproval.builder()
.transactionId(UUID.randomUUID())
.transactionType("CONTRIBUTION")
.amount(new BigDecimal("2000.00"))
.requesterId(UUID.randomUUID())
.requesterName("Requester")
.requiredLevel("LEVEL1")
.build();
ApproverAction action = pendingAction();
ta.addApproverAction(action);
assertThat(ta.getApprovers()).hasSize(1);
assertThat(action.getApproval()).isSameAs(ta);
}
// -------------------------------------------------------------------------
// isExpired
// -------------------------------------------------------------------------
@Test
@DisplayName("isExpired: expiresAt null renvoie false")
void isExpired_expiresAtNull_returnsFalse() {
TransactionApproval ta = new TransactionApproval();
ta.setExpiresAt(null);
assertThat(ta.isExpired()).isFalse();
}
@Test
@DisplayName("isExpired: expiresAt dans le passé renvoie true")
void isExpired_expiredInPast_returnsTrue() {
TransactionApproval ta = new TransactionApproval();
ta.setExpiresAt(LocalDateTime.now().minusMinutes(1));
assertThat(ta.isExpired()).isTrue();
}
@Test
@DisplayName("isExpired: expiresAt dans le futur renvoie false")
void isExpired_futureExpiry_returnsFalse() {
TransactionApproval ta = new TransactionApproval();
ta.setExpiresAt(LocalDateTime.now().plusDays(1));
assertThat(ta.isExpired()).isFalse();
}
// -------------------------------------------------------------------------
// isPending
// -------------------------------------------------------------------------
@Test
@DisplayName("isPending: statut PENDING renvoie true")
void isPending_pending_returnsTrue() {
TransactionApproval ta = new TransactionApproval();
ta.setStatus("PENDING");
assertThat(ta.isPending()).isTrue();
}
@Test
@DisplayName("isPending: statut APPROVED renvoie false")
void isPending_approved_returnsFalse() {
TransactionApproval ta = new TransactionApproval();
ta.setStatus("APPROVED");
assertThat(ta.isPending()).isFalse();
}
// -------------------------------------------------------------------------
// isCompleted
// -------------------------------------------------------------------------
@Test
@DisplayName("isCompleted: statut VALIDATED renvoie true")
void isCompleted_validated_returnsTrue() {
TransactionApproval ta = new TransactionApproval();
ta.setStatus("VALIDATED");
assertThat(ta.isCompleted()).isTrue();
}
@Test
@DisplayName("isCompleted: statut REJECTED renvoie true")
void isCompleted_rejected_returnsTrue() {
TransactionApproval ta = new TransactionApproval();
ta.setStatus("REJECTED");
assertThat(ta.isCompleted()).isTrue();
}
@Test
@DisplayName("isCompleted: statut CANCELLED renvoie true")
void isCompleted_cancelled_returnsTrue() {
TransactionApproval ta = new TransactionApproval();
ta.setStatus("CANCELLED");
assertThat(ta.isCompleted()).isTrue();
}
@Test
@DisplayName("isCompleted: statut PENDING renvoie false")
void isCompleted_pending_returnsFalse() {
TransactionApproval ta = new TransactionApproval();
ta.setStatus("PENDING");
assertThat(ta.isCompleted()).isFalse();
}
// -------------------------------------------------------------------------
// onCreate (réflexion)
// -------------------------------------------------------------------------
@Test
@DisplayName("onCreate: initialise createdAt, currency, status, expiresAt si null")
void onCreate_initializesNullFields() throws Exception {
TransactionApproval ta = new TransactionApproval();
ta.setCreatedAt(null);
ta.setCurrency(null);
ta.setStatus(null);
ta.setExpiresAt(null);
Method onCreate = TransactionApproval.class.getDeclaredMethod("onCreate");
onCreate.setAccessible(true);
onCreate.invoke(ta);
assertThat(ta.getCreatedAt()).isNotNull();
assertThat(ta.getCurrency()).isEqualTo("XOF");
assertThat(ta.getStatus()).isEqualTo("PENDING");
assertThat(ta.getExpiresAt()).isNotNull();
// expiresAt doit être ~7 jours après createdAt
assertThat(ta.getExpiresAt()).isAfter(ta.getCreatedAt());
assertThat(ta.getExpiresAt()).isBeforeOrEqualTo(ta.getCreatedAt().plusDays(7).plusSeconds(1));
}
@Test
@DisplayName("onCreate: ne remplace pas createdAt si déjà renseigné")
void onCreate_doesNotOverrideExistingCreatedAt() throws Exception {
LocalDateTime existingDate = LocalDateTime.of(2025, 3, 10, 9, 0);
LocalDateTime existingExpiry = LocalDateTime.of(2025, 3, 17, 9, 0);
TransactionApproval ta = new TransactionApproval();
ta.setCreatedAt(existingDate);
ta.setCurrency("EUR");
ta.setStatus("APPROVED");
ta.setExpiresAt(existingExpiry);
Method onCreate = TransactionApproval.class.getDeclaredMethod("onCreate");
onCreate.setAccessible(true);
onCreate.invoke(ta);
assertThat(ta.getCreatedAt()).isEqualTo(existingDate);
assertThat(ta.getCurrency()).isEqualTo("EUR");
assertThat(ta.getStatus()).isEqualTo("APPROVED");
assertThat(ta.getExpiresAt()).isEqualTo(existingExpiry);
}
}