323 lines
12 KiB
Java
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);
|
|
}
|
|
}
|