feat: enhance lease and rent payment management
- Added methods in LeaseRepository to find leases by apartment ID and exclude a specific lease ID. - Introduced a method in RentPaymentRepository to delete all payments by lease ID. - Updated LeaseService to handle overlapping leases and generate rent payments upon lease creation. - Implemented rent payment deletion in LeaseService when a lease is deleted. - Enhanced RentPaymentService to generate rent payments with pro-rata calculations for partial months. - Modified RentPaymentController to accept rent and charges when marking payments as paid. - Created RentPaymentPaidRequest DTO for validating rent payment requests. - Added a RentPaymentValidationDialog for confirming payment amounts before processing. - Updated frontend components to support new rent payment features, including validation and date filtering for leases. - Adjusted tests to cover new functionalities and ensure proper integration of rent payment management.
This commit is contained in:
1 parent
479012d661
commit
9cfb55d79c
25 files changed
+389
-175
No files matched your search
@@ -8,11 +8,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConditionalOnProperty(
|
||||
name = "lmnp.data-initializer.enabled",
|
||||
havingValue = "true",
|
||||
matchIfMissing = true
|
||||
)
|
||||
@ConditionalOnProperty(name = "lmnp.data-initializer.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public class DataInitializer implements ApplicationRunner {
|
||||
|
||||
private final LandlordRepository landlordRepository;
|
||||
@@ -25,13 +21,12 @@ public class DataInitializer implements ApplicationRunner {
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
if (!landlordRepository.existsById("default-landlord")) {
|
||||
Landlord defaultLandlord = new Landlord(
|
||||
"default-landlord",
|
||||
"Bailleur",
|
||||
"LMNP",
|
||||
"bailleur@example.com",
|
||||
"0102030405",
|
||||
"123 Rue de la Gestion, Paris"
|
||||
);
|
||||
"default-landlord",
|
||||
"Bailleur",
|
||||
"LMNP",
|
||||
"bailleur@example.com",
|
||||
"0102030405",
|
||||
"123 Rue de la Gestion, Paris");
|
||||
landlordRepository.save(defaultLandlord);
|
||||
System.out.println("Default landlord profile initialized in database.");
|
||||
}
|
||||
|
||||
+4
-2
@@ -6,6 +6,8 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import fr.nessar.lmnporganizer.backend.dto.RentPaymentPaidRequest;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -26,8 +28,8 @@ public class RentPaymentController {
|
||||
}
|
||||
|
||||
@PutMapping("/{id}/paid")
|
||||
public ResponseEntity<RentPaymentResponse> markPaid(@PathVariable String id) {
|
||||
return rentPaymentService.markPaid(id);
|
||||
public ResponseEntity<RentPaymentResponse> markPaid(@PathVariable String id, @RequestBody RentPaymentPaidRequest request) {
|
||||
return rentPaymentService.markPaid(id, request.getRent(), request.getCharges());
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/receipt")
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package fr.nessar.lmnporganizer.backend.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class RentPaymentPaidRequest {
|
||||
|
||||
@NotNull
|
||||
private BigDecimal rent;
|
||||
|
||||
@NotNull
|
||||
private BigDecimal charges;
|
||||
|
||||
public RentPaymentPaidRequest() {
|
||||
}
|
||||
|
||||
public RentPaymentPaidRequest(BigDecimal rent, BigDecimal charges) {
|
||||
this.rent = rent;
|
||||
this.charges = charges;
|
||||
}
|
||||
|
||||
public BigDecimal getRent() {
|
||||
return rent;
|
||||
}
|
||||
|
||||
public void setRent(BigDecimal rent) {
|
||||
this.rent = rent;
|
||||
}
|
||||
|
||||
public BigDecimal getCharges() {
|
||||
return charges;
|
||||
}
|
||||
|
||||
public void setCharges(BigDecimal charges) {
|
||||
this.charges = charges;
|
||||
}
|
||||
}
|
||||
@@ -10,4 +10,6 @@ import java.util.List;
|
||||
@Repository
|
||||
public interface LeaseRepository extends MongoRepository<Lease, String> {
|
||||
List<Lease> findAllByStatus(LeaseStatus status);
|
||||
List<Lease> findAllByApartmentId(String apartmentId);
|
||||
List<Lease> findAllByApartmentIdAndIdNot(String apartmentId, String id);
|
||||
}
|
||||
+2
@@ -13,4 +13,6 @@ public interface RentPaymentRepository extends MongoRepository<RentPayment, Stri
|
||||
List<RentPayment> findAllByLeaseIdAndMonthBetween(String leaseId, String firstMonth, String lastMonth);
|
||||
|
||||
List<RentPayment> findAllByOrderByDueDateAsc();
|
||||
|
||||
void deleteAllByLeaseId(String leaseId);
|
||||
}
|
||||
@@ -28,16 +28,19 @@ public class LeaseService {
|
||||
private final LeasePdfService leasePdfService;
|
||||
private final PhoneNumberNormalizer phoneNumberNormalizer;
|
||||
private final LeaseMapper leaseMapper;
|
||||
private final RentPaymentService rentPaymentService;
|
||||
|
||||
public LeaseService(LeaseRepository leaseRepository, ApartmentRepository apartmentRepository,
|
||||
TenantRepository tenantRepository, LeasePdfService leasePdfService,
|
||||
PhoneNumberNormalizer phoneNumberNormalizer, LeaseMapper leaseMapper) {
|
||||
PhoneNumberNormalizer phoneNumberNormalizer, LeaseMapper leaseMapper,
|
||||
RentPaymentService rentPaymentService) {
|
||||
this.leaseRepository = leaseRepository;
|
||||
this.apartmentRepository = apartmentRepository;
|
||||
this.tenantRepository = tenantRepository;
|
||||
this.leasePdfService = leasePdfService;
|
||||
this.phoneNumberNormalizer = phoneNumberNormalizer;
|
||||
this.leaseMapper = leaseMapper;
|
||||
this.rentPaymentService = rentPaymentService;
|
||||
}
|
||||
|
||||
public List<LeaseResponse> getAll() {
|
||||
@@ -54,9 +57,14 @@ public class LeaseService {
|
||||
if (!referencesExist(lease)) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
if (hasOverlappingLease(lease, null)) {
|
||||
return ResponseEntity.status(HttpStatus.CONFLICT).build();
|
||||
}
|
||||
lease.setLandlordId("default-landlord");
|
||||
normalizeGuarantorPhones(lease);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(leaseMapper.toResponse(leaseRepository.save(lease)));
|
||||
lease = leaseRepository.save(lease);
|
||||
rentPaymentService.generateForLease(lease);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(leaseMapper.toResponse(lease));
|
||||
}
|
||||
|
||||
public ResponseEntity<LeaseResponse> update(String id, LeaseRequest request) {
|
||||
@@ -64,6 +72,9 @@ public class LeaseService {
|
||||
if (!referencesExist(details)) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
if (hasOverlappingLease(details, id)) {
|
||||
return ResponseEntity.status(HttpStatus.CONFLICT).build();
|
||||
}
|
||||
return leaseRepository.findById(id).map(lease -> {
|
||||
leaseMapper.update(request, lease);
|
||||
lease.setLandlordId("default-landlord");
|
||||
@@ -76,6 +87,7 @@ public class LeaseService {
|
||||
if (!leaseRepository.existsById(id)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
rentPaymentService.deleteForLease(id);
|
||||
leaseRepository.deleteById(id);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
@@ -114,4 +126,17 @@ public class LeaseService {
|
||||
private void normalizeGuarantorPhones(Lease lease) {
|
||||
lease.getGuarantors().forEach(guarantor -> guarantor.setPhone(phoneNumberNormalizer.normalize(guarantor.getPhone())));
|
||||
}
|
||||
|
||||
private boolean hasOverlappingLease(Lease newLease, String excludeId) {
|
||||
if (newLease.getStartDate() == null || newLease.getEndDate() == null) return false;
|
||||
List<Lease> existingLeases = excludeId == null
|
||||
? leaseRepository.findAllByApartmentId(newLease.getApartmentId())
|
||||
: leaseRepository.findAllByApartmentIdAndIdNot(newLease.getApartmentId(), excludeId);
|
||||
|
||||
return existingLeases.stream().anyMatch(existing ->
|
||||
existing.getStartDate() != null && existing.getEndDate() != null &&
|
||||
!newLease.getStartDate().isAfter(existing.getEndDate()) &&
|
||||
!newLease.getEndDate().isBefore(existing.getStartDate())
|
||||
);
|
||||
}
|
||||
}
|
||||
+46
-16
@@ -4,7 +4,6 @@ import fr.nessar.lmnporganizer.backend.dto.RentPaymentResponse;
|
||||
import fr.nessar.lmnporganizer.backend.model.Apartment;
|
||||
import fr.nessar.lmnporganizer.backend.model.Landlord;
|
||||
import fr.nessar.lmnporganizer.backend.model.Lease;
|
||||
import fr.nessar.lmnporganizer.backend.model.LeaseStatus;
|
||||
import fr.nessar.lmnporganizer.backend.model.RentPayment;
|
||||
import fr.nessar.lmnporganizer.backend.model.Tenant;
|
||||
import fr.nessar.lmnporganizer.backend.repository.ApartmentRepository;
|
||||
@@ -38,9 +37,9 @@ public class RentPaymentService {
|
||||
private final Clock clock;
|
||||
|
||||
public RentPaymentService(RentPaymentRepository rentPaymentRepository, LeaseRepository leaseRepository,
|
||||
ApartmentRepository apartmentRepository, LandlordRepository landlordRepository,
|
||||
TenantRepository tenantRepository,
|
||||
RentReceiptPdfService rentReceiptPdfService, Clock clock) {
|
||||
ApartmentRepository apartmentRepository, LandlordRepository landlordRepository,
|
||||
TenantRepository tenantRepository,
|
||||
RentReceiptPdfService rentReceiptPdfService, Clock clock) {
|
||||
this.rentPaymentRepository = rentPaymentRepository;
|
||||
this.leaseRepository = leaseRepository;
|
||||
this.apartmentRepository = apartmentRepository;
|
||||
@@ -51,13 +50,14 @@ public class RentPaymentService {
|
||||
}
|
||||
|
||||
public List<RentPaymentResponse> getAll() {
|
||||
generateForActiveLeases();
|
||||
return rentPaymentRepository.findAllByOrderByDueDateAsc().stream().map(this::toResponse).toList();
|
||||
}
|
||||
|
||||
public ResponseEntity<RentPaymentResponse> markPaid(String id) {
|
||||
public ResponseEntity<RentPaymentResponse> markPaid(String id, java.math.BigDecimal rent, java.math.BigDecimal charges) {
|
||||
return rentPaymentRepository.findById(id).map(payment -> {
|
||||
if (payment.getPaidAt() == null) {
|
||||
payment.setRent(rent);
|
||||
payment.setCharges(charges);
|
||||
payment.setPaidAt(LocalDate.now(clock));
|
||||
payment = rentPaymentRepository.save(payment);
|
||||
}
|
||||
@@ -67,11 +67,14 @@ public class RentPaymentService {
|
||||
|
||||
public ResponseEntity<byte[]> downloadReceipt(String id) {
|
||||
RentPayment payment = rentPaymentRepository.findById(id).orElse(null);
|
||||
if (payment == null) return ResponseEntity.notFound().build();
|
||||
if (payment.getPaidAt() == null) return ResponseEntity.status(HttpStatus.CONFLICT).build();
|
||||
if (payment == null)
|
||||
return ResponseEntity.notFound().build();
|
||||
if (payment.getPaidAt() == null)
|
||||
return ResponseEntity.status(HttpStatus.CONFLICT).build();
|
||||
|
||||
Lease lease = leaseRepository.findById(payment.getLeaseId()).orElse(null);
|
||||
if (lease == null) return ResponseEntity.notFound().build();
|
||||
if (lease == null)
|
||||
return ResponseEntity.notFound().build();
|
||||
Apartment apartment = apartmentRepository.findById(lease.getApartmentId()).orElse(null);
|
||||
Landlord landlord = landlordRepository.findById(payment.getLandlordId()).orElse(null);
|
||||
List<Tenant> tenants = tenantsFor(lease.getTenantIds());
|
||||
@@ -86,14 +89,15 @@ public class RentPaymentService {
|
||||
.body(rentReceiptPdfService.generate(payment, lease, apartment, landlord, tenants));
|
||||
}
|
||||
|
||||
private void generateForActiveLeases() {
|
||||
leaseRepository.findAllByStatus(LeaseStatus.ACTIVE).forEach(this::generateForLease);
|
||||
public void deleteForLease(String leaseId) {
|
||||
rentPaymentRepository.deleteAllByLeaseId(leaseId);
|
||||
}
|
||||
|
||||
private void generateForLease(Lease lease) {
|
||||
public void generateForLease(Lease lease) {
|
||||
if (lease.getStartDate() == null || lease.getEndDate() == null || lease.getMonthlyRent() == null
|
||||
|| lease.getMonthlyCharges() == null
|
||||
|| lease.getEndDate().isBefore(lease.getStartDate())) return;
|
||||
|| lease.getEndDate().isBefore(lease.getStartDate()))
|
||||
return;
|
||||
|
||||
YearMonth firstMonth = YearMonth.from(lease.getStartDate());
|
||||
YearMonth lastMonth = YearMonth.from(lease.getEndDate());
|
||||
@@ -103,15 +107,41 @@ public class RentPaymentService {
|
||||
List<RentPayment> missingPayments = new ArrayList<>();
|
||||
for (YearMonth month = firstMonth; !month.isAfter(lastMonth); month = month.plusMonths(1)) {
|
||||
if (!existingMonths.contains(month.toString())) {
|
||||
java.math.BigDecimal rent = lease.getMonthlyRent();
|
||||
java.math.BigDecimal charges = lease.getMonthlyCharges();
|
||||
|
||||
if (month.equals(firstMonth) && month.equals(lastMonth)) {
|
||||
int daysOccupied = lease.getEndDate().getDayOfMonth() - lease.getStartDate().getDayOfMonth() + 1;
|
||||
int daysInMonth = month.lengthOfMonth();
|
||||
rent = proRata(rent, daysInMonth, daysOccupied);
|
||||
charges = proRata(charges, daysInMonth, daysOccupied);
|
||||
} else if (month.equals(firstMonth)) {
|
||||
int daysOccupied = month.lengthOfMonth() - lease.getStartDate().getDayOfMonth() + 1;
|
||||
int daysInMonth = month.lengthOfMonth();
|
||||
rent = proRata(rent, daysInMonth, daysOccupied);
|
||||
charges = proRata(charges, daysInMonth, daysOccupied);
|
||||
} else if (month.equals(lastMonth)) {
|
||||
int daysOccupied = lease.getEndDate().getDayOfMonth();
|
||||
int daysInMonth = month.lengthOfMonth();
|
||||
rent = proRata(rent, daysInMonth, daysOccupied);
|
||||
charges = proRata(charges, daysInMonth, daysOccupied);
|
||||
}
|
||||
|
||||
missingPayments.add(new RentPayment(null, lease.getLandlordId(), lease.getId(), month.toString(),
|
||||
dueDate(lease, month), lease.getMonthlyRent(), lease.getMonthlyCharges(), null));
|
||||
dueDate(lease, month), rent, charges, null));
|
||||
}
|
||||
}
|
||||
if (!missingPayments.isEmpty()) rentPaymentRepository.saveAll(missingPayments);
|
||||
if (!missingPayments.isEmpty())
|
||||
rentPaymentRepository.saveAll(missingPayments);
|
||||
}
|
||||
|
||||
private java.math.BigDecimal proRata(java.math.BigDecimal amount, int daysInMonth, int daysOccupied) {
|
||||
return amount.multiply(new java.math.BigDecimal(daysOccupied))
|
||||
.divide(new java.math.BigDecimal(daysInMonth), 2, java.math.RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private LocalDate dueDate(Lease lease, YearMonth month) {
|
||||
return month.atDay(Math.min(lease.getStartDate().getDayOfMonth(), month.lengthOfMonth()));
|
||||
return month.plusMonths(1).atDay(5);
|
||||
}
|
||||
|
||||
private RentPaymentResponse toResponse(RentPayment payment) {
|
||||
|
||||
+5
@@ -8,6 +8,7 @@ import fr.nessar.lmnporganizer.backend.model.Tenant;
|
||||
import fr.nessar.lmnporganizer.backend.repository.ApartmentRepository;
|
||||
import fr.nessar.lmnporganizer.backend.repository.LeaseRepository;
|
||||
import fr.nessar.lmnporganizer.backend.repository.TenantRepository;
|
||||
import fr.nessar.lmnporganizer.backend.service.RentPaymentService;
|
||||
import org.apache.pdfbox.Loader;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.text.PDFTextStripper;
|
||||
@@ -45,6 +46,9 @@ class LeaseControllerTest {
|
||||
@MockitoBean
|
||||
private TenantRepository tenantRepository;
|
||||
|
||||
@MockitoBean
|
||||
private RentPaymentService rentPaymentService;
|
||||
|
||||
@Test
|
||||
void whenCreateLease_thenLinksApartmentTenantsAndGuarantors() throws Exception {
|
||||
when(apartmentRepository.existsById("apartment-1")).thenReturn(true);
|
||||
@@ -126,6 +130,7 @@ class LeaseControllerTest {
|
||||
mockMvc.perform(delete("/api/leases/lease-1").with(oidcLogin()))
|
||||
.andExpect(status().isNoContent());
|
||||
|
||||
verify(rentPaymentService).deleteForLease("lease-1");
|
||||
verify(leaseRepository).deleteById("lease-1");
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -80,7 +80,10 @@ class RentPaymentControllerTest {
|
||||
when(rentPaymentRepository.findById("payment-1")).thenReturn(Optional.of(payment(null)));
|
||||
when(rentPaymentRepository.save(any(RentPayment.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
mockMvc.perform(put("/api/rent-payments/payment-1/paid").with(oidcLogin()))
|
||||
mockMvc.perform(put("/api/rent-payments/payment-1/paid")
|
||||
.contentType(org.springframework.http.MediaType.APPLICATION_JSON)
|
||||
.content("{\"rent\": 850.00, \"charges\": 50.00}")
|
||||
.with(oidcLogin()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.status").value("PAID"));
|
||||
}
|
||||
@@ -89,7 +92,10 @@ class RentPaymentControllerTest {
|
||||
void whenUnknownRentPaymentIsMarkedPaid_thenNotFound() throws Exception {
|
||||
when(rentPaymentRepository.findById("missing")).thenReturn(Optional.empty());
|
||||
|
||||
mockMvc.perform(put("/api/rent-payments/missing/paid").with(oidcLogin()))
|
||||
mockMvc.perform(put("/api/rent-payments/missing/paid")
|
||||
.contentType(org.springframework.http.MediaType.APPLICATION_JSON)
|
||||
.content("{\"rent\": 850.00, \"charges\": 50.00}")
|
||||
.with(oidcLogin()))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
|
||||
+11
-30
@@ -71,46 +71,27 @@ class RentPaymentServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void generatesARecordForEachMonthOfAnActiveLease() {
|
||||
void generatesARecordForEachMonthOfALease() {
|
||||
Lease lease = lease(LocalDate.of(2099, 1, 31), LocalDate.of(2099, 3, 31));
|
||||
when(leaseRepository.findAllByStatus(LeaseStatus.ACTIVE)).thenReturn(List.of(lease));
|
||||
when(rentPaymentRepository.findAllByLeaseIdAndMonthBetween("lease-1", "2099-01", "2099-03"))
|
||||
.thenReturn(List.of());
|
||||
when(rentPaymentRepository.findAllByOrderByDueDateAsc()).thenReturn(List.of(
|
||||
payment("payment-1", "2099-01", LocalDate.of(2099, 1, 31), null),
|
||||
payment("payment-2", "2099-02", LocalDate.of(2099, 2, 28), null),
|
||||
payment("payment-3", "2099-03", LocalDate.of(2099, 3, 31), null)));
|
||||
|
||||
List<RentPaymentResponse> payments = service.getAll();
|
||||
service.generateForLease(lease);
|
||||
|
||||
assertEquals(3, payments.size());
|
||||
assertEquals("2099-01", payments.getFirst().month());
|
||||
assertEquals(new BigDecimal("900.00"), payments.getFirst().total());
|
||||
assertEquals(RentPaymentStatus.UPCOMING, payments.getFirst().status());
|
||||
verify(rentPaymentRepository).saveAll(argThat(generatedPayments -> {
|
||||
List<RentPayment> records = StreamSupport.stream(generatedPayments.spliterator(), false).toList();
|
||||
return records.stream().map(RentPayment::getMonth).toList().equals(List.of("2099-01", "2099-02", "2099-03"))
|
||||
&& records.get(1).getDueDate().equals(LocalDate.of(2099, 2, 28));
|
||||
&& records.get(1).getDueDate().equals(LocalDate.of(2099, 3, 5))
|
||||
&& records.get(0).getRent().equals(new BigDecimal("27.42"))
|
||||
&& records.get(0).getCharges().equals(new BigDecimal("1.61"))
|
||||
&& records.get(2).getRent().equals(new BigDecimal("850.00"));
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generatesEachRentPaymentOnlyOnceAcrossRepeatedCalls() {
|
||||
Lease lease = lease(LocalDate.of(2099, 1, 31), LocalDate.of(2099, 3, 31));
|
||||
List<RentPayment> existingPayments = List.of(
|
||||
payment("payment-1", "2099-01", LocalDate.of(2099, 1, 31), null),
|
||||
payment("payment-2", "2099-02", LocalDate.of(2099, 2, 28), null),
|
||||
payment("payment-3", "2099-03", LocalDate.of(2099, 3, 31), null));
|
||||
when(leaseRepository.findAllByStatus(LeaseStatus.ACTIVE)).thenReturn(List.of(lease));
|
||||
when(rentPaymentRepository.findAllByLeaseIdAndMonthBetween("lease-1", "2099-01", "2099-03"))
|
||||
.thenReturn(List.of())
|
||||
.thenReturn(existingPayments);
|
||||
when(rentPaymentRepository.findAllByOrderByDueDateAsc()).thenReturn(existingPayments);
|
||||
|
||||
service.getAll();
|
||||
service.getAll();
|
||||
|
||||
verify(rentPaymentRepository, times(1)).saveAll(anyList());
|
||||
void deletesRecordsForALease() {
|
||||
service.deleteForLease("lease-1");
|
||||
verify(rentPaymentRepository).deleteAllByLeaseId("lease-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -119,7 +100,7 @@ class RentPaymentServiceTest {
|
||||
when(rentPaymentRepository.findById("payment-1")).thenReturn(Optional.of(payment));
|
||||
when(rentPaymentRepository.save(any(RentPayment.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
ResponseEntity<RentPaymentResponse> response = service.markPaid("payment-1");
|
||||
ResponseEntity<RentPaymentResponse> response = service.markPaid("payment-1", new BigDecimal("850.00"), new BigDecimal("50.00"));
|
||||
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertNotNull(response.getBody());
|
||||
@@ -127,7 +108,7 @@ class RentPaymentServiceTest {
|
||||
assertEquals(LocalDate.of(2026, 7, 17), response.getBody().paidAt());
|
||||
verify(rentPaymentRepository).save(payment);
|
||||
|
||||
service.markPaid("payment-1");
|
||||
service.markPaid("payment-1", new BigDecimal("850.00"), new BigDecimal("50.00"));
|
||||
verify(rentPaymentRepository, times(1)).save(payment);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user