From 41b086fb33283c996567b0eb368d13d9d16fc854 Mon Sep 17 00:00:00 2001
From: Nessar
Date: Fri, 24 Jul 2026 19:55:43 +0200
Subject: [PATCH] Keep payment violations domain-shaped (#55)
---
.../web/common/RentalApiExceptionHandler.java | 3 +-
.../adapter/in/web/rent/RentPaymentApi.java | 2 +
.../in/web/rent/RentPaymentController.java | 25 +++++++--
.../rent/AllocateRentPaymentService.java | 12 ++---
.../rent/RecordRentPaymentService.java | 3 +-
.../rent/RefundRentPaymentService.java | 6 +--
.../rent/RentPaymentValidationFailure.java | 26 ++++++----
.../application/shared/ConcurrentChange.java | 2 -
.../adapter/in/web/RentalWebAdaptersTest.java | 7 +--
.../RentPaymentConflictContractTest.java | 12 +++++
.../rent/RentPaymentControllerErrorTest.java | 51 +++++++++++--------
.../rent/AllocateRentPaymentServiceTest.java | 13 ++---
.../rent/RecordRentPaymentServiceTest.java | 4 +-
.../rent/RefundRentPaymentServiceTest.java | 9 ++--
14 files changed, 106 insertions(+), 69 deletions(-)
diff --git a/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/common/RentalApiExceptionHandler.java b/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/common/RentalApiExceptionHandler.java
index 0c6621a..71c3ed7 100644
--- a/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/common/RentalApiExceptionHandler.java
+++ b/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/common/RentalApiExceptionHandler.java
@@ -103,7 +103,8 @@ ResponseEntity unreadableRequest() {
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
-ResponseEntity invalidParameter(MethodArgumentTypeMismatchException exception) {
+ResponseEntity invalidParameter(
+ MethodArgumentTypeMismatchException exception) {
return validation(exception.getName(), "invalid");
}
diff --git a/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentApi.java b/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentApi.java
index 5029376..60eff84 100644
--- a/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentApi.java
+++ b/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentApi.java
@@ -14,6 +14,8 @@ import java.time.LocalDate;
import java.util.List;
final class RentPaymentApi {
+static final String CONCURRENT_CHANGE_CODE = "concurrent_change";
+
private RentPaymentApi() {}
record ConcurrentChangeResponse(String code, String message) {}
diff --git a/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentController.java b/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentController.java
index 8df38c2..a6c1c88 100644
--- a/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentController.java
+++ b/backend/src/main/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentController.java
@@ -68,7 +68,7 @@ ResponseEntity concurrentChange(
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(
new RentPaymentApi.ConcurrentChangeResponse(
- ConcurrentChange.CODE,
+ RentPaymentApi.CONCURRENT_CHANGE_CODE,
"La ressource a été modifiée ; rechargez-la puis réessayez."));
}
@@ -78,8 +78,27 @@ ResponseEntity invalidPayment(
return ResponseEntity.badRequest()
.body(
new RentPaymentApi.ValidationFailureResponse(
- "validation_failed",
- List.of(new RentPaymentApi.FieldErrorResponse(failure.field(), failure.code()))));
+ "validation_failed", List.of(validationError(failure.rule()))));
+}
+
+private static RentPaymentApi.FieldErrorResponse validationError(
+ RentPaymentValidationFailure.Rule rule) {
+ return switch (rule) {
+ case RECEIVED_AT_MUST_NOT_BE_FUTURE ->
+ new RentPaymentApi.FieldErrorResponse("receivedAt", "future_date");
+ case REFUNDED_AT_MUST_NOT_BE_FUTURE ->
+ new RentPaymentApi.FieldErrorResponse("refundedAt", "future_date");
+ case RENT_DUE_MUST_BELONG_TO_PAYMENT_LEASE ->
+ new RentPaymentApi.FieldErrorResponse("rentDueId", "different_lease");
+ case RENT_DUE_MUST_NOT_ALREADY_BE_ALLOCATED ->
+ new RentPaymentApi.FieldErrorResponse("rentDueId", "already_allocated");
+ case AMOUNT_MUST_NOT_EXCEED_PAYMENT_BALANCE ->
+ new RentPaymentApi.FieldErrorResponse("amount", "exceeds_payment_balance");
+ case AMOUNT_MUST_NOT_EXCEED_RENT_DUE_BALANCE ->
+ new RentPaymentApi.FieldErrorResponse("amount", "exceeds_rent_due_balance");
+ case AMOUNT_MUST_NOT_EXCEED_UNALLOCATED_BALANCE ->
+ new RentPaymentApi.FieldErrorResponse("amount", "exceeds_unallocated_balance");
+ };
}
@GetMapping
diff --git a/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/AllocateRentPaymentService.java b/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/AllocateRentPaymentService.java
index 8160462..fcb7fa4 100644
--- a/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/AllocateRentPaymentService.java
+++ b/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/AllocateRentPaymentService.java
@@ -79,15 +79,13 @@ public RentPayment allocate(
}
if (!payment.leaseId().equals(due.leaseId())) {
throw new RentPaymentValidationFailure(
- "rentDueId",
- "different_lease",
+ RentPaymentValidationFailure.Rule.RENT_DUE_MUST_BELONG_TO_PAYMENT_LEASE,
"Une affectation doit viser une échéance du même bail.");
}
if (payment.allocations().stream()
.anyMatch(allocation -> allocation.rentDueId().equals(due.id()))) {
throw new RentPaymentValidationFailure(
- "rentDueId",
- "already_allocated",
+ RentPaymentValidationFailure.Rule.RENT_DUE_MUST_NOT_ALREADY_BE_ALLOCATED,
"Cette échéance a déjà reçu une affectation de ce règlement.");
}
if (due.settlement() == RentDueSettlement.PAID) {
@@ -96,14 +94,12 @@ public RentPayment allocate(
}
if (amount != null && amount.compareTo(payment.unallocatedBalance()) > 0) {
throw new RentPaymentValidationFailure(
- "amount",
- "exceeds_payment_balance",
+ RentPaymentValidationFailure.Rule.AMOUNT_MUST_NOT_EXCEED_PAYMENT_BALANCE,
"L'affectation dépasse le solde non affecté du règlement.");
}
if (amount != null && amount.compareTo(due.remainingAmount()) > 0) {
throw new RentPaymentValidationFailure(
- "amount",
- "exceeds_rent_due_balance",
+ RentPaymentValidationFailure.Rule.AMOUNT_MUST_NOT_EXCEED_RENT_DUE_BALANCE,
"L'affectation dépasse le solde restant de l'échéance.");
}
PaymentAllocation allocation =
diff --git a/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RecordRentPaymentService.java b/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RecordRentPaymentService.java
index 512bd82..a5c274e 100644
--- a/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RecordRentPaymentService.java
+++ b/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RecordRentPaymentService.java
@@ -88,8 +88,7 @@ private RentPayment recordInTransaction(
LocalDate today = LocalDate.now(clock.withZone(timeZone));
if (receivedAt == null || receivedAt.isAfter(today)) {
throw new RentPaymentValidationFailure(
- "receivedAt",
- "future_date",
+ RentPaymentValidationFailure.Rule.RECEIVED_AT_MUST_NOT_BE_FUTURE,
"La date de réception du règlement ne peut pas être future.");
}
RentDue due =
diff --git a/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RefundRentPaymentService.java b/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RefundRentPaymentService.java
index 1627a1f..788d610 100644
--- a/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RefundRentPaymentService.java
+++ b/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RefundRentPaymentService.java
@@ -72,7 +72,8 @@ private RentPayment refundInTransaction(
LocalDate today = LocalDate.now(clock.withZone(timeZone));
if (refundedAt == null || refundedAt.isAfter(today)) {
throw new RentPaymentValidationFailure(
- "refundedAt", "future_date", "La date du remboursement ne peut pas être future.");
+ RentPaymentValidationFailure.Rule.REFUNDED_AT_MUST_NOT_BE_FUTURE,
+ "La date du remboursement ne peut pas être future.");
}
RentPayment payment = payment(landlordId, paymentId);
if (payment.version() != paymentVersion) {
@@ -83,8 +84,7 @@ private RentPayment refundInTransaction(
}
if (amount != null && amount.compareTo(payment.unallocatedBalance()) > 0) {
throw new RentPaymentValidationFailure(
- "amount",
- "exceeds_unallocated_balance",
+ RentPaymentValidationFailure.Rule.AMOUNT_MUST_NOT_EXCEED_UNALLOCATED_BALANCE,
"Le remboursement dépasse le solde non affecté du règlement.");
}
RentPaymentRefund refund = RentPaymentRefund.recorded(refundId, payment, amount, refundedAt);
diff --git a/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RentPaymentValidationFailure.java b/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RentPaymentValidationFailure.java
index 3a471de..9f15f86 100644
--- a/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RentPaymentValidationFailure.java
+++ b/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/rent/RentPaymentValidationFailure.java
@@ -3,20 +3,24 @@ package fr.nessar.lmnporganizer.rental.application.rent;
import java.util.Objects;
public final class RentPaymentValidationFailure extends RuntimeException {
-private final String field;
-private final String code;
+public enum Rule {
+ RECEIVED_AT_MUST_NOT_BE_FUTURE,
+ REFUNDED_AT_MUST_NOT_BE_FUTURE,
+ RENT_DUE_MUST_BELONG_TO_PAYMENT_LEASE,
+ RENT_DUE_MUST_NOT_ALREADY_BE_ALLOCATED,
+ AMOUNT_MUST_NOT_EXCEED_PAYMENT_BALANCE,
+ AMOUNT_MUST_NOT_EXCEED_RENT_DUE_BALANCE,
+ AMOUNT_MUST_NOT_EXCEED_UNALLOCATED_BALANCE
+}
-public RentPaymentValidationFailure(String field, String code, String message) {
+private final Rule rule;
+
+public RentPaymentValidationFailure(Rule rule, String message) {
super(message);
- this.field = Objects.requireNonNull(field);
- this.code = Objects.requireNonNull(code);
+ this.rule = Objects.requireNonNull(rule);
}
-public String field() {
- return field;
-}
-
-public String code() {
- return code;
+public Rule rule() {
+ return rule;
}
}
diff --git a/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/shared/ConcurrentChange.java b/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/shared/ConcurrentChange.java
index 8bea64f..ba401f8 100644
--- a/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/shared/ConcurrentChange.java
+++ b/backend/src/main/java/fr/nessar/lmnporganizer/rental/application/shared/ConcurrentChange.java
@@ -1,8 +1,6 @@
package fr.nessar.lmnporganizer.rental.application.shared;
public final class ConcurrentChange extends RuntimeException {
-public static final String CODE = "concurrent_change";
-
public ConcurrentChange(String resource) {
super(resource + " changed concurrently; reload it and retry.");
}
diff --git a/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/RentalWebAdaptersTest.java b/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/RentalWebAdaptersTest.java
index 64fc14f..7649dac 100644
--- a/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/RentalWebAdaptersTest.java
+++ b/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/RentalWebAdaptersTest.java
@@ -148,8 +148,7 @@ void authenticateLandlordAndFixTime() {
LeaseClauseCatalog.load(getClass().getResourceAsStream("/lease-clauses.yml"));
when(leaseClauseCatalog.available(anyString(), any()))
.thenAnswer(
- invocation ->
- clauses.available(invocation.getArgument(0), invocation.getArgument(1)));
+ invocation -> clauses.available(invocation.getArgument(0), invocation.getArgument(1)));
}
@Test
@@ -444,9 +443,7 @@ void leaseDraftRequestsRejectAnImpossibleAnnualRevisionDay() throws Exception {
"""))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.code").value("validation_failed"))
- .andExpect(
- jsonPath("$.errors[0].field")
- .value("legalTerms.rentRevision.annualRevisionDay"))
+ .andExpect(jsonPath("$.errors[0].field").value("legalTerms.rentRevision.annualRevisionDay"))
.andExpect(jsonPath("$.errors[0].code").value("invalid_date"));
}
diff --git a/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/common/RentPaymentConflictContractTest.java b/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/common/RentPaymentConflictContractTest.java
index 6dbd3dc..6135e41 100644
--- a/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/common/RentPaymentConflictContractTest.java
+++ b/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/common/RentPaymentConflictContractTest.java
@@ -3,6 +3,7 @@ package fr.nessar.lmnporganizer.rental.adapter.in.web.common;
import static org.junit.jupiter.api.Assertions.assertEquals;
import fr.nessar.lmnporganizer.rental.application.rent.RentPaymentConflict;
+import fr.nessar.lmnporganizer.rental.application.shared.ConcurrentChange;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
@@ -16,4 +17,15 @@ void keepsBusinessConflictsAsUncoded409Responses() {
assertEquals(
new RentalApiExceptionHandler.ApiError("Échéance déjà réglée"), response.getBody());
}
+
+@Test
+void keepsSharedConcurrencyFailuresAsSafeUncoded409Responses() {
+ var response = new RentalApiExceptionHandler().concurrent(new ConcurrentChange("Rent payment"));
+
+ assertEquals(HttpStatus.CONFLICT, response.getStatusCode());
+ assertEquals(
+ new RentalApiExceptionHandler.ApiError(
+ "La ressource a été modifiée ; rechargez-la puis réessayez."),
+ response.getBody());
+}
}
diff --git a/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentControllerErrorTest.java b/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentControllerErrorTest.java
index 1a13e6a..64d7cda 100644
--- a/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentControllerErrorTest.java
+++ b/backend/src/test/java/fr/nessar/lmnporganizer/rental/adapter/in/web/rent/RentPaymentControllerErrorTest.java
@@ -13,34 +13,41 @@ import fr.nessar.lmnporganizer.rental.application.rent.RentPaymentValidationFail
import fr.nessar.lmnporganizer.rental.application.rent.ReverseRentPaymentService;
import fr.nessar.lmnporganizer.rental.application.shared.ConcurrentChange;
import java.util.List;
+import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpStatus;
class RentPaymentControllerErrorTest {
@Test
-void mapsPaymentInputFailuresToTheStableValidationContract() {
- RentPaymentController controller =
- new RentPaymentController(
- mock(RentPaymentHistoryService.class),
- mock(RecordRentPaymentService.class),
- mock(AllocateRentPaymentService.class),
- mock(RefundRentPaymentService.class),
- mock(ReverseRentPaymentService.class),
- mock(GeneratePaymentReceiptService.class),
- mock(AuthenticatedLandlord.class));
+void mapsPaymentRulesToTheStableValidationContract() {
+ Map expected =
+ Map.of(
+ RentPaymentValidationFailure.Rule.RECEIVED_AT_MUST_NOT_BE_FUTURE,
+ new RentPaymentApi.FieldErrorResponse("receivedAt", "future_date"),
+ RentPaymentValidationFailure.Rule.REFUNDED_AT_MUST_NOT_BE_FUTURE,
+ new RentPaymentApi.FieldErrorResponse("refundedAt", "future_date"),
+ RentPaymentValidationFailure.Rule.RENT_DUE_MUST_BELONG_TO_PAYMENT_LEASE,
+ new RentPaymentApi.FieldErrorResponse("rentDueId", "different_lease"),
+ RentPaymentValidationFailure.Rule.RENT_DUE_MUST_NOT_ALREADY_BE_ALLOCATED,
+ new RentPaymentApi.FieldErrorResponse("rentDueId", "already_allocated"),
+ RentPaymentValidationFailure.Rule.AMOUNT_MUST_NOT_EXCEED_PAYMENT_BALANCE,
+ new RentPaymentApi.FieldErrorResponse("amount", "exceeds_payment_balance"),
+ RentPaymentValidationFailure.Rule.AMOUNT_MUST_NOT_EXCEED_RENT_DUE_BALANCE,
+ new RentPaymentApi.FieldErrorResponse("amount", "exceeds_rent_due_balance"),
+ RentPaymentValidationFailure.Rule.AMOUNT_MUST_NOT_EXCEED_UNALLOCATED_BALANCE,
+ new RentPaymentApi.FieldErrorResponse("amount", "exceeds_unallocated_balance"));
- var response =
- controller.invalidPayment(
- new RentPaymentValidationFailure(
- "amount", "exceeds_unallocated_balance", "Le remboursement dépasse le solde."));
+ expected.forEach(
+ (rule, error) -> {
+ var response =
+ controller()
+ .invalidPayment(new RentPaymentValidationFailure(rule, "internal detail"));
- assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
- assertEquals(
- new RentPaymentApi.ValidationFailureResponse(
- "validation_failed",
- List.of(
- new RentPaymentApi.FieldErrorResponse("amount", "exceeds_unallocated_balance"))),
- response.getBody());
+ assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
+ assertEquals(
+ new RentPaymentApi.ValidationFailureResponse("validation_failed", List.of(error)),
+ response.getBody());
+ });
}
@Test
@@ -48,7 +55,7 @@ void mapsOnlyConcurrentChangesToTheCodedStaleContract() {
var response = controller().concurrentChange(new ConcurrentChange("Rent payment"));
assertEquals(HttpStatus.CONFLICT, response.getStatusCode());
- assertEquals(ConcurrentChange.CODE, response.getBody().code());
+ assertEquals(RentPaymentApi.CONCURRENT_CHANGE_CODE, response.getBody().code());
}
private static RentPaymentController controller() {
diff --git a/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/AllocateRentPaymentServiceTest.java b/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/AllocateRentPaymentServiceTest.java
index 4cacd14..25c77a4 100644
--- a/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/AllocateRentPaymentServiceTest.java
+++ b/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/AllocateRentPaymentServiceTest.java
@@ -271,8 +271,8 @@ void allocationMapsDuplicateAndBalanceFailuresToFields() {
() ->
service.allocate(
LANDLORD_ID, PAYMENT_ID, "operation-2", 4, DUE_ID, 2, new BigDecimal("10")));
- assertEquals("rentDueId", duplicate.field());
- assertEquals("already_allocated", duplicate.code());
+ assertEquals(
+ RentPaymentValidationFailure.Rule.RENT_DUE_MUST_NOT_ALREADY_BE_ALLOCATED, duplicate.rule());
RentPayment otherPayment =
RentPayment.reconstitute(
@@ -293,16 +293,17 @@ void allocationMapsDuplicateAndBalanceFailuresToFields() {
() ->
service.allocate(
LANDLORD_ID, PAYMENT_ID, "operation-3", 4, DUE_ID, 2, new BigDecimal("101")));
- assertEquals("amount", balance.field());
- assertEquals("exceeds_payment_balance", balance.code());
+ assertEquals(
+ RentPaymentValidationFailure.Rule.AMOUNT_MUST_NOT_EXCEED_PAYMENT_BALANCE, balance.rule());
RentPaymentValidationFailure dueBalance =
assertThrows(
RentPaymentValidationFailure.class,
() ->
service.allocate(
LANDLORD_ID, PAYMENT_ID, "operation-4", 4, DUE_ID, 2, new BigDecimal("41")));
- assertEquals("amount", dueBalance.field());
- assertEquals("exceeds_rent_due_balance", dueBalance.code());
+ assertEquals(
+ RentPaymentValidationFailure.Rule.AMOUNT_MUST_NOT_EXCEED_RENT_DUE_BALANCE,
+ dueBalance.rule());
verify(rentDues, never()).save(any());
verify(payments, never()).save(any());
diff --git a/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/RecordRentPaymentServiceTest.java b/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/RecordRentPaymentServiceTest.java
index 291a6be..d3fc1e3 100644
--- a/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/RecordRentPaymentServiceTest.java
+++ b/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/RecordRentPaymentServiceTest.java
@@ -219,8 +219,8 @@ void staleOrPaidDueAndCashFromTheNextParisDayCreateNoPayment() {
LocalDate.of(2026, 2, 11),
PARIS,
new BigDecimal("1000")));
- assertEquals("receivedAt", futureDate.field());
- assertEquals("future_date", futureDate.code());
+ assertEquals(
+ RentPaymentValidationFailure.Rule.RECEIVED_AT_MUST_NOT_BE_FUTURE, futureDate.rule());
due.allocate(due.total());
assertThrows(
RentPaymentConflict.class,
diff --git a/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/RefundRentPaymentServiceTest.java b/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/RefundRentPaymentServiceTest.java
index 1880dae..2ba244a 100644
--- a/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/RefundRentPaymentServiceTest.java
+++ b/backend/src/test/java/fr/nessar/lmnporganizer/rental/application/rent/RefundRentPaymentServiceTest.java
@@ -179,8 +179,8 @@ void futureDateAndStalePaymentVersionCreateNoRefund() {
new BigDecimal("50"),
LocalDate.of(2026, 2, 11),
PARIS));
- assertEquals("refundedAt", futureDate.field());
- assertEquals("future_date", futureDate.code());
+ assertEquals(
+ RentPaymentValidationFailure.Rule.REFUNDED_AT_MUST_NOT_BE_FUTURE, futureDate.rule());
assertThrows(
ConcurrentChange.class,
() ->
@@ -204,8 +204,9 @@ void futureDateAndStalePaymentVersionCreateNoRefund() {
new BigDecimal("1001"),
LocalDate.of(2026, 2, 9),
PARIS));
- assertEquals("amount", excessAmount.field());
- assertEquals("exceeds_unallocated_balance", excessAmount.code());
+ assertEquals(
+ RentPaymentValidationFailure.Rule.AMOUNT_MUST_NOT_EXCEED_UNALLOCATED_BALANCE,
+ excessAmount.rule());
verify(payments, never()).save(any());
verify(refunds, never()).save(any());