diff --git a/checkstyle.xml b/checkstyle.xml index 9a6a928..416ea7e 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -26,6 +26,6 @@ - + diff --git a/payment-service-app/pom.xml b/payment-service-app/pom.xml index 09edf3d..3d57ea1 100644 --- a/payment-service-app/pom.xml +++ b/payment-service-app/pom.xml @@ -17,6 +17,13 @@ 21 + 3.0.0 + 1.18.36 + 1.6.3 + 1.6.3 + 3.14.0 + 3.3.0 + 4.32.0 @@ -34,28 +41,27 @@ org.springdoc springdoc-openapi-starter-webmvc-ui - 3.0.0 + ${springdoc.version} org.postgresql postgresql - org.mapstruct mapstruct - 1.6.3 + ${mapstruct.version} org.mapstruct mapstruct-processor - 1.6.3 + ${mapstruct-processor.version} provided org.projectlombok lombok - 1.18.36 + ${lombok.version} com.h2database @@ -86,20 +92,18 @@ org.apache.maven.plugins maven-compiler-plugin - 3.14.0 + ${maven-compiler-plugin.version} - 21 - 21 org.projectlombok lombok - 1.18.36 + ${lombok.version} org.mapstruct mapstruct-processor - 1.6.3 + ${mapstruct-processor.version} @@ -107,7 +111,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - 3.3.0 + ${maven-checkstyle-plugin.version} verify @@ -125,7 +129,7 @@ org.liquibase liquibase-maven-plugin - 4.32.0 + ${liquibase-maven-plugin.version} src/main/resources/liquibase.properties src/main/resources/liquibase-outputChangeLog.xml diff --git a/payment-service-app/src/main/java/com/iprody/controller/PaymentController.java b/payment-service-app/src/main/java/com/iprody/controller/PaymentController.java index b029e4b..6d673f1 100644 --- a/payment-service-app/src/main/java/com/iprody/controller/PaymentController.java +++ b/payment-service-app/src/main/java/com/iprody/controller/PaymentController.java @@ -3,34 +3,28 @@ import com.iprody.model.PaymentDto; import com.iprody.service.PaymentService; import com.iprody.specification.PaymentFilter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; +import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import java.net.URI; import java.util.List; import java.util.UUID; @RestController +@RequiredArgsConstructor @RequestMapping("/payments") public class PaymentController { private final PaymentService paymentService; - /** - * Use either "withMapper" or "withConverter" - * @param paymentService - */ - @Autowired - public PaymentController(@Qualifier("withMapper") PaymentService paymentService) { - this.paymentService = paymentService; - } - @GetMapping("/search") public Page searchPayments( @ModelAttribute PaymentFilter filter, @@ -49,17 +43,38 @@ public Page searchPayments( @GetMapping public ResponseEntity> fetchAll() { - return ResponseEntity.ok().body(this.paymentService.fetchAllPayments()); + return ResponseEntity.ok().body(this.paymentService.getPayments()); + } + + @PostMapping(path = "/add") + public ResponseEntity addPayment(@RequestBody PaymentDto paymentDto) { + final PaymentDto savedPayment = this.paymentService.create(paymentDto); + final URI location = ServletUriComponentsBuilder.fromCurrentRequest() + .path("/{id}") + .buildAndExpand(savedPayment.getGuid()) + .toUri(); + return ResponseEntity.created(location).body(savedPayment); } @GetMapping(path = "/{id}") - public ResponseEntity fetchPayment(@PathVariable UUID id) { - return ResponseEntity.ok().body(this.paymentService.fetchSinglePayment(id)); + public ResponseEntity getPayment(@PathVariable UUID id) { + return ResponseEntity.ok().body(this.paymentService.get(id)); } - @PostMapping(path = "/addPayment") - public ResponseEntity addPayment(@RequestBody PaymentDto paymentDto) { - return ResponseEntity.ok().body(this.paymentService.processPayment(paymentDto)); + @PutMapping(path = "/update/{id}") + public ResponseEntity updatePayment(@PathVariable UUID id, @RequestBody PaymentDto paymentDto) { + return ResponseEntity.ok().body(this.paymentService.update(id, paymentDto)); + } + + @PutMapping(path = "/update/{id}/{note}") + public ResponseEntity updatePaymentNote(@PathVariable UUID id, @PathVariable String note) { + return ResponseEntity.ok().body(this.paymentService.updateNote(id, note)); + } + + @DeleteMapping(path = "/delete/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deletePayment(@PathVariable UUID id) { + this.paymentService.delete(id); } } diff --git a/payment-service-app/src/main/java/com/iprody/exception/EntityNotFoundException.java b/payment-service-app/src/main/java/com/iprody/exception/EntityNotFoundException.java new file mode 100644 index 0000000..a2f1ce1 --- /dev/null +++ b/payment-service-app/src/main/java/com/iprody/exception/EntityNotFoundException.java @@ -0,0 +1,22 @@ +package com.iprody.exception; + +import lombok.Getter; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +import java.util.UUID; + +@Getter +@ResponseStatus(HttpStatus.NOT_FOUND) +public class EntityNotFoundException extends RuntimeException { + + private final String operation; + private final UUID entityId; + + public EntityNotFoundException(String message, String operation, UUID entityId) { + super(message); + this.operation = operation; + this.entityId = entityId; + } + +} diff --git a/payment-service-app/src/main/java/com/iprody/exception/ErrorResponse.java b/payment-service-app/src/main/java/com/iprody/exception/ErrorResponse.java new file mode 100644 index 0000000..c6b7323 --- /dev/null +++ b/payment-service-app/src/main/java/com/iprody/exception/ErrorResponse.java @@ -0,0 +1,23 @@ +package com.iprody.exception; + +import lombok.Getter; + +import java.time.Instant; +import java.util.UUID; + +@Getter +public class ErrorResponse { + + private final String error; + private final Instant timestamp; + private final String operation; + private final UUID entityId; + + public ErrorResponse(String error, String operation, UUID entityId) { + this.error = error; + this.timestamp = Instant.now(); + this.operation = operation; + this.entityId = entityId; + } + +} \ No newline at end of file diff --git a/payment-service-app/src/main/java/com/iprody/exception/GlobalExceptionHandler.java b/payment-service-app/src/main/java/com/iprody/exception/GlobalExceptionHandler.java index 177c167..3b56215 100644 --- a/payment-service-app/src/main/java/com/iprody/exception/GlobalExceptionHandler.java +++ b/payment-service-app/src/main/java/com/iprody/exception/GlobalExceptionHandler.java @@ -1,10 +1,13 @@ package com.iprody.exception; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; -@ControllerAdvice + +@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(AppException.class) @@ -14,4 +17,16 @@ public ResponseEntity handleAppException(AppException ex) { .body(ex.getMessage()); } + @ExceptionHandler(EntityNotFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public ErrorResponse handleNotFound(EntityNotFoundException ex) { + return new ErrorResponse(ex.getMessage(), ex.getOperation(), ex.getEntityId()); + } + + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ErrorResponse handleOther(Exception ex) { + return new ErrorResponse(ex.getMessage(), null, null); + } + } diff --git a/payment-service-app/src/main/java/com/iprody/service/PaymentService.java b/payment-service-app/src/main/java/com/iprody/service/PaymentService.java index bc52b6b..282000d 100644 --- a/payment-service-app/src/main/java/com/iprody/service/PaymentService.java +++ b/payment-service-app/src/main/java/com/iprody/service/PaymentService.java @@ -9,9 +9,12 @@ import java.util.UUID; public interface PaymentService { - List fetchAllPayments(); - PaymentDto fetchSinglePayment(UUID id); - PaymentDto processPayment(PaymentDto paymentDto); + PaymentDto create(PaymentDto paymentDto); + PaymentDto get(UUID id); List search(PaymentFilter filter); Page searchPaged(PaymentFilter filter, Pageable pageable); + List getPayments(); + PaymentDto update(UUID id, PaymentDto dto); + PaymentDto updateNote(UUID id, String updatedNote); + void delete(UUID id); } diff --git a/payment-service-app/src/main/java/com/iprody/service/PaymentServiceImpl_withMapper.java b/payment-service-app/src/main/java/com/iprody/service/PaymentServiceImpl.java similarity index 54% rename from payment-service-app/src/main/java/com/iprody/service/PaymentServiceImpl_withMapper.java rename to payment-service-app/src/main/java/com/iprody/service/PaymentServiceImpl.java index cb557dc..10c27e3 100644 --- a/payment-service-app/src/main/java/com/iprody/service/PaymentServiceImpl_withMapper.java +++ b/payment-service-app/src/main/java/com/iprody/service/PaymentServiceImpl.java @@ -1,6 +1,7 @@ package com.iprody.service; import com.iprody.exception.AppException; +import com.iprody.exception.EntityNotFoundException; import com.iprody.mapper.PaymentMapper; import com.iprody.model.PaymentDto; import com.iprody.persistence.PaymentEntity; @@ -14,13 +15,14 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; +import java.time.OffsetDateTime; import java.util.List; import java.util.UUID; -@Service("withMapper") +@Service @RequiredArgsConstructor -public class PaymentServiceImpl_withMapper implements PaymentService { +public class PaymentServiceImpl implements PaymentService { private final PaymentMapper paymentMapper; private final PaymentRepository paymentRepository; @@ -43,22 +45,22 @@ public Page searchPaged(PaymentFilter filter, Pageable pageable) { } @Override - public List fetchAllPayments() { - return paymentRepository.findAll().stream() + public List getPayments() { + return paymentRepository + .findAll().stream() .map(paymentMapper::toPaymentDto) .toList(); } @Override - public PaymentDto fetchSinglePayment(UUID id) { + public PaymentDto get(UUID id) { return paymentRepository.findById(id) .map(paymentMapper::toPaymentDto) - .orElseThrow(() -> new AppException( - HttpStatus.NOT_FOUND.value(), "Payment with the id '" + id + "' was not found")); + .orElseThrow(() -> new EntityNotFoundException("Платеж не найден", "get", id)); } @Override - public PaymentDto processPayment(PaymentDto paymentDto) { + public PaymentDto create(PaymentDto paymentDto) { if (paymentDto.getAmount().doubleValue() <= 0) { throw new AppException(HttpStatus.BAD_REQUEST.value(), "Payment is not valid"); } @@ -66,4 +68,34 @@ public PaymentDto processPayment(PaymentDto paymentDto) { return paymentMapper.toPaymentDto(paymentRepository.save(paymentEntity)); } + @Override + public PaymentDto update(UUID id, PaymentDto dto) { + paymentRepository.findById(id) + .orElseThrow(() -> new EntityNotFoundException("Платеж не найден", "update", id)); + final PaymentEntity updated = paymentMapper.toPaymentEntity(dto); + updated.setGuid(id); + return paymentMapper.toPaymentDto(paymentRepository.save(updated)); + } + + @Override + public PaymentDto updateNote(UUID id, String updatedNote) { + return paymentRepository.findById(id) + .map(p -> { + p.setNote(updatedNote); + p.setUpdatedAt(OffsetDateTime.now()); + return paymentMapper.toPaymentDto(paymentRepository.save(p)); + }) + .orElseThrow(() -> new EntityNotFoundException("Платеж не найден", "updateNote", id)); + } + + @Override + public void delete(UUID id) { + paymentRepository.findById(id) + .map(p -> { + paymentRepository.delete(p); + return id; + }) + .orElseThrow(() -> new EntityNotFoundException("Платеж не найден", "delete", id)); + } + } diff --git a/payment-service-app/src/main/java/com/iprody/service/PaymentServiceImpl_withConverter.java b/payment-service-app/src/main/java/com/iprody/service/PaymentServiceImpl_withConverter.java deleted file mode 100644 index 2593af8..0000000 --- a/payment-service-app/src/main/java/com/iprody/service/PaymentServiceImpl_withConverter.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.iprody.service; - -import com.iprody.converter.PaymentConverter; -import com.iprody.exception.AppException; -import com.iprody.model.PaymentDto; -import com.iprody.persistence.PaymentEntity; -import com.iprody.persistence.PaymentRepository; -import com.iprody.specification.PaymentFilter; -import com.iprody.specification.PaymentFilterFactory; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.UUID; - - -@Service("withConverter") -@RequiredArgsConstructor -public class PaymentServiceImpl_withConverter implements PaymentService { - - private final PaymentConverter paymentConverter; - private final PaymentRepository paymentRepository; - - @Override - public List search(PaymentFilter filter) { - final Specification spec = PaymentFilterFactory.fromFilter(filter); - return paymentRepository - .findAll(spec).stream() - .map(paymentConverter::toPaymentDto) - .toList(); - } - - @Override - public Page searchPaged(PaymentFilter filter, Pageable pageable) { - final Specification spec = PaymentFilterFactory.fromFilter(filter); - return paymentRepository - .findAll(spec, pageable) - .map(paymentConverter::toPaymentDto); - } - - @Override - public List fetchAllPayments() { - return paymentRepository.findAll().stream() - .map(paymentConverter::toPaymentDto) - .toList(); - } - - @Override - public PaymentDto fetchSinglePayment(UUID id) { - return paymentRepository.findById(id) - .map(paymentConverter::toPaymentDto) - .orElseThrow(() -> new AppException( - HttpStatus.NOT_FOUND.value(), "Payment with the id '" + id + "' was not found")); - } - - @Override - public PaymentDto processPayment(PaymentDto paymentDto) { - if (paymentDto.getAmount().doubleValue() <= 0) { - throw new AppException(HttpStatus.BAD_REQUEST.value(), "Payment is not valid"); - } - final var paymentEntity = paymentConverter.toPaymentEntity(paymentDto); - return paymentConverter.toPaymentDto(paymentRepository.save(paymentEntity)); - } - -} diff --git a/payment-service-app/src/main/resources/curl/add.json b/payment-service-app/src/main/resources/curl/add.json new file mode 100644 index 0000000..824a1b7 --- /dev/null +++ b/payment-service-app/src/main/resources/curl/add.json @@ -0,0 +1,11 @@ +{ + "guid": "01deac78-8673-4062-bc33-bdec273b553b", + "inquiryRefId": "01deac78-8673-4062-bc33-bdec273b553b", + "amount": "123", + "currency": "RUB", + "transactionRefId": "01deac78-8673-4062-bc33-bdec273b553b", + "status": "RECEIVED", + "note": "remark", + "createdAt": "2025-12-20T10:07:21.841Z", + "updatedAt": "2025-12-20T10:07:21.841Z" +} diff --git a/payment-service-app/src/main/resources/curl/endpoint_requests b/payment-service-app/src/main/resources/curl/endpoint_requests new file mode 100644 index 0000000..b95e4d1 --- /dev/null +++ b/payment-service-app/src/main/resources/curl/endpoint_requests @@ -0,0 +1,15 @@ +/* Get all payments */ +curl http://localhost:8099/payments + +/* Get payment by id */ +curl -v http://localhost:8099/payments/ac328a1a-1e60-4dd3-bee5-ed573d74c841 + +/* Add new payment */ +curl -v -H "Content-Type: application/json" -X POST --data @add.json http://localhost:8099/payments/add + +/* Update payment */ +curl -v -H "Content-Type: application/json" -X PUT --data @put.json \ + http://localhost:8099/payments/update/ac328a1a-1e60-4dd3-bee5-ed573d74c841 + +/* Delete payment */ +curl -v -X DELETE http://localhost:8099/payments/delete/ac328a1a-1e60-4dd3-bee5-ed573d74c841 diff --git a/payment-service-app/src/main/resources/curl/put.json b/payment-service-app/src/main/resources/curl/put.json new file mode 100644 index 0000000..96e719b --- /dev/null +++ b/payment-service-app/src/main/resources/curl/put.json @@ -0,0 +1,11 @@ +{ + "guid": "01deac78-8673-4062-bc33-bdec273b553b", + "inquiryRefId": "01deac78-8673-4062-bc33-bdec273b553b", + "amount": "345", + "currency": "EUR", + "transactionRefId": "01deac78-8673-4062-bc33-bdec273b553b", + "status": "RECEIVED", + "note": "updated", + "createdAt": "2025-12-20T10:07:21.841Z", + "updatedAt": "2025-12-20T11:07:00.000Z" +} \ No newline at end of file diff --git a/payment-service-app/src/test/java/com/iprody/service/PaymentControllerTest.java b/payment-service-app/src/test/java/com/iprody/service/PaymentControllerTest.java index 3654e08..7b8c323 100644 --- a/payment-service-app/src/test/java/com/iprody/service/PaymentControllerTest.java +++ b/payment-service-app/src/test/java/com/iprody/service/PaymentControllerTest.java @@ -45,11 +45,37 @@ void setUp() { initData(); } + private void initData() { + LocalDateTime now = LocalDateTime.now(); + dto_1 = new PaymentDto( + UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6"), + UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa7"), + BigDecimal.valueOf(100.89), + "EUR", + UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa8"), + PaymentStatus.RECEIVED, + "Some info 1", + OffsetDateTime.of(now, ZoneOffset.UTC), + OffsetDateTime.of(now, ZoneOffset.UTC) + ); + dto_2 = new PaymentDto( + UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afb6"), + UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afb7"), + BigDecimal.valueOf(200.51), + "USD", + UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afb8"), + PaymentStatus.APPROVED, + "Some info 2", + OffsetDateTime.of(now, ZoneOffset.UTC), + OffsetDateTime.of(now, ZoneOffset.UTC) + ); + } + @Test @DisplayName("GET /payments should return list of two PaymentDto") void findAll_ReturnsListOfTwoPayments() throws Exception { // when - when(paymentService.fetchAllPayments()).thenReturn(List.of(dto_1, dto_2)); + when(paymentService.getPayments()).thenReturn(List.of(dto_1, dto_2)); // then mockMvc.perform(get("/payments").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) @@ -67,7 +93,7 @@ void findAll_ReturnsListOfTwoPayments() throws Exception { @DisplayName("GET /payments should return empty list when there is no payments") void findAll_ReturnsEmptyList() throws Exception { // when - when(paymentService.fetchAllPayments()).thenReturn(List.of()); + when(paymentService.getPayments()).thenReturn(List.of()); // then mockMvc.perform(get("/payments") .accept(MediaType.APPLICATION_JSON)) @@ -81,42 +107,15 @@ void findAll_ReturnsEmptyList() throws Exception { void getById_ReturnsPayment_WhenFound() throws Exception { // given UUID id = dto_1.getGuid(); - String expectedUuid = "3fa85f64-5717-4562-b3fc-2c963f66afa6"; // when - when(paymentService.fetchSinglePayment(id)).thenReturn(dto_1); + when(paymentService.get(id)).thenReturn(dto_1); // then mockMvc.perform(get("/payments/{id}", id).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - //.andExpect(jsonPath("$.guid").value(UUID.fromString(expectedUuid))) + .andExpect(jsonPath("$.guid").value("3fa85f64-5717-4562-b3fc-2c963f66afa6")) .andExpect(jsonPath("$.amount").value(100.89)) .andExpect(jsonPath("$.note").value("Some info 1")); } - private void initData() { - LocalDateTime now = LocalDateTime.now(); - dto_1 = new PaymentDto( - UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6"), - UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa7"), - BigDecimal.valueOf(100.89), - "EUR", - UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa8"), - PaymentStatus.RECEIVED, - "Some info 1", - OffsetDateTime.of(now, ZoneOffset.UTC), - OffsetDateTime.of(now, ZoneOffset.UTC) - ); - dto_2 = new PaymentDto( - UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afb6"), - UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afb7"), - BigDecimal.valueOf(200.51), - "USD", - UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afb8"), - PaymentStatus.APPROVED, - "Some info 2", - OffsetDateTime.of(now, ZoneOffset.UTC), - OffsetDateTime.of(now, ZoneOffset.UTC) - ); - } - } diff --git a/payment-service-app/src/test/java/com/iprody/service/PaymentServiceTest.java b/payment-service-app/src/test/java/com/iprody/service/PaymentServiceTest.java index 5eafac4..894b430 100644 --- a/payment-service-app/src/test/java/com/iprody/service/PaymentServiceTest.java +++ b/payment-service-app/src/test/java/com/iprody/service/PaymentServiceTest.java @@ -1,7 +1,7 @@ package com.iprody.service; -import com.iprody.converter.PaymentConverter; -import com.iprody.exception.AppException; +import com.iprody.exception.EntityNotFoundException; +import com.iprody.mapper.PaymentMapper; import com.iprody.model.PaymentDto; import com.iprody.persistence.PaymentEntity; import com.iprody.persistence.PaymentRepository; @@ -34,13 +34,13 @@ class PaymentServiceTest { @InjectMocks - private PaymentServiceImpl_withConverter paymentService; + private PaymentServiceImpl paymentService; @Mock private PaymentRepository paymentRepository; @Mock - private PaymentConverter paymentConverter; + private PaymentMapper paymentMapper; private PaymentEntity paymentEntity1; private PaymentEntity paymentEntity2; @@ -106,15 +106,15 @@ void setUp() { } @Test - @DisplayName("fetchAllPayments should return list of payments when payments exist") - void fetchAllPayments_shouldReturnListOfPayments_whenPaymentsExist() { + @DisplayName("getPayments should return list of payments when payments exist") + void getPayments_shouldReturnListOfPayments_whenPaymentsExist() { // Given List entities = Arrays.asList(paymentEntity1, paymentEntity2); when(paymentRepository.findAll()).thenReturn(entities); - when(paymentConverter.toPaymentDto(paymentEntity1)).thenReturn(paymentDto1); - when(paymentConverter.toPaymentDto(paymentEntity2)).thenReturn(paymentDto2); + when(paymentMapper.toPaymentDto(paymentEntity1)).thenReturn(paymentDto1); + when(paymentMapper.toPaymentDto(paymentEntity2)).thenReturn(paymentDto2); // When - List result = paymentService.fetchAllPayments(); + List result = paymentService.getPayments(); // Then assertNotNull(result); assertEquals(2, result.size()); @@ -126,47 +126,32 @@ void fetchAllPayments_shouldReturnListOfPayments_whenPaymentsExist() { assertEquals("EUR", result.get(1).getCurrency()); verify(paymentRepository, times(1)).findAll(); - verify(paymentConverter, times(2)).toPaymentDto(any(PaymentEntity.class)); + verify(paymentMapper, times(2)).toPaymentDto(any(PaymentEntity.class)); } @Test - @DisplayName("fetchAllPayments should return empty list when no payments exist") - void fetchAllPayments_shouldReturnEmptyList_whenNoPaymentsExist() { + @DisplayName("getPayments should return empty list when no payments exist") + void getPayments_shouldReturnEmptyList_whenNoPaymentsExist() { // Given when(paymentRepository.findAll()).thenReturn(Collections.emptyList()); // When - List result = paymentService.fetchAllPayments(); + List result = paymentService.getPayments(); // Then assertNotNull(result); assertTrue(result.isEmpty()); verify(paymentRepository, times(1)).findAll(); - verify(paymentConverter, never()).toPaymentDto(any(PaymentEntity.class)); + verify(paymentMapper, never()).toPaymentDto(any(PaymentEntity.class)); } @Test - @DisplayName("fetchAllPayments should handle multiple payments correctly") - void fetchAllPayments_shouldHandleMultiplePayments() { - // Given - List entities = Arrays.asList(paymentEntity1, paymentEntity2); - when(paymentRepository.findAll()).thenReturn(entities); - when(paymentConverter.toPaymentDto(any(PaymentEntity.class))) - .thenReturn(paymentDto1, paymentDto2); - // When - List result = paymentService.fetchAllPayments(); - // Then - assertEquals(2, result.size()); - verify(paymentConverter, times(2)).toPaymentDto(any(PaymentEntity.class)); - } - - @Test - @DisplayName("fetchSinglePayment should return payment when payment exists") - void fetchSinglePayment_shouldReturnPayment_whenPaymentExists() { + @DisplayName("getPayment should return payment when payment exists") + void getPayment_shouldReturnPayment_whenExists() { // Given when(paymentRepository.findById(testUuid1)).thenReturn(Optional.of(paymentEntity1)); - when(paymentConverter.toPaymentDto(paymentEntity1)).thenReturn(paymentDto1); + when(paymentMapper.toPaymentDto(paymentEntity1)).thenReturn(paymentDto1); // When - PaymentDto result = paymentService.fetchSinglePayment(testUuid1); + PaymentDto result = paymentService.get(testUuid1); // Then assertNotNull(result); assertEquals(testUuid1, result.getGuid()); @@ -176,54 +161,25 @@ void fetchSinglePayment_shouldReturnPayment_whenPaymentExists() { assertEquals("Test payment 1", result.getNote()); verify(paymentRepository, times(1)).findById(testUuid1); - verify(paymentConverter, times(1)).toPaymentDto(paymentEntity1); + verify(paymentMapper, times(1)).toPaymentDto(paymentEntity1); } @Test - @DisplayName("fetchSinglePayment should throw NoSuchPaymentException when payment does not exist") - void fetchSinglePayment_shouldThrowException_whenPaymentDoesNotExist() { + @DisplayName("getPayment should throw NoSuchPaymentException when payment does not exist") + void getPayment_shouldThrowException_whenDoesNotExist() { // Given UUID nonExistentId = UUID.randomUUID(); when(paymentRepository.findById(nonExistentId)).thenReturn(Optional.empty()); // When - assertThrows(AppException.class, () -> paymentService.fetchSinglePayment(nonExistentId)); + assertThrows(EntityNotFoundException.class, () -> paymentService.get(nonExistentId)); // Then verify(paymentRepository, times(1)).findById(nonExistentId); - verify(paymentConverter, never()).toPaymentDto(any(PaymentEntity.class)); - } - - @Test - @DisplayName("fetchSinglePayment should handle different payment statuses") - void fetchSinglePayment_shouldHandleDifferentStatuses() { - // Given - PaymentEntity pendingEntity = PaymentEntity.builder() - .guid(testUuid1) - .inquiryRefId(UUID.randomUUID()) - .amount(new BigDecimal("100.00")) - .currency("USD") - .status(PaymentStatus.PENDING) - .createdAt(OffsetDateTime.now()) - .updatedAt(OffsetDateTime.now()) - .build(); - - PaymentDto pendingDto = PaymentDto.builder() - .guid(testUuid1) - .status(PaymentStatus.PENDING) - .build(); - - when(paymentRepository.findById(testUuid1)).thenReturn(Optional.of(pendingEntity)); - when(paymentConverter.toPaymentDto(pendingEntity)).thenReturn(pendingDto); - - // When - PaymentDto result = paymentService.fetchSinglePayment(testUuid1); - - // Then - assertEquals(PaymentStatus.PENDING, result.getStatus()); + verify(paymentMapper, never()).toPaymentDto(any(PaymentEntity.class)); } @Test - @DisplayName("processPayment should save and return payment") - void processPayment_shouldSaveAndReturnPayment() { + @DisplayName("create should save and return payment") + void createPayment_shouldSaveAndReturnPayment() { // Given UUID newUuid = UUID.randomUUID(); PaymentDto inputDto = PaymentDto.builder() @@ -266,12 +222,12 @@ void processPayment_shouldSaveAndReturnPayment() { .updatedAt(savedEntity.getUpdatedAt()) .build(); - when(paymentConverter.toPaymentEntity(inputDto)).thenReturn(entityToSave); + when(paymentMapper.toPaymentEntity(inputDto)).thenReturn(entityToSave); when(paymentRepository.save(entityToSave)).thenReturn(savedEntity); - when(paymentConverter.toPaymentDto(savedEntity)).thenReturn(expectedDto); + when(paymentMapper.toPaymentDto(savedEntity)).thenReturn(expectedDto); // When - PaymentDto result = paymentService.processPayment(inputDto); + PaymentDto result = paymentService.create(inputDto); // Then assertNotNull(result); @@ -280,118 +236,42 @@ void processPayment_shouldSaveAndReturnPayment() { assertEquals("GBP", result.getCurrency()); assertEquals(PaymentStatus.RECEIVED, result.getStatus()); - verify(paymentConverter, times(1)).toPaymentEntity(inputDto); + verify(paymentMapper, times(1)).toPaymentEntity(inputDto); verify(paymentRepository, times(1)).save(entityToSave); - verify(paymentConverter, times(1)).toPaymentDto(savedEntity); + verify(paymentMapper, times(1)).toPaymentDto(savedEntity); } - @Test - @DisplayName("processPayment should handle payment with all fields populated") - void processPayment_shouldHandleCompletePayment() { - // Given - UUID guid = UUID.randomUUID(); - UUID inquiryRefId = UUID.randomUUID(); - UUID transactionRefId = UUID.randomUUID(); - OffsetDateTime now = OffsetDateTime.now(); - - PaymentDto inputDto = PaymentDto.builder() - .guid(guid) - .inquiryRefId(inquiryRefId) - .amount(new BigDecimal("500.50")) - .currency("USD") - .transactionRefId(transactionRefId) - .status(PaymentStatus.APPROVED) - .note("Complete payment with all fields") - .createdAt(now) - .updatedAt(now) - .build(); - - PaymentEntity entityToSave = PaymentEntity.builder() - .guid(guid) - .inquiryRefId(inquiryRefId) - .amount(new BigDecimal("500.50")) - .currency("USD") - .transactionRefId(transactionRefId) - .status(PaymentStatus.APPROVED) - .note("Complete payment with all fields") - .createdAt(now) - .updatedAt(now) - .build(); - - when(paymentConverter.toPaymentEntity(inputDto)).thenReturn(entityToSave); - when(paymentRepository.save(entityToSave)).thenReturn(entityToSave); - when(paymentConverter.toPaymentDto(entityToSave)).thenReturn(inputDto); - - // When - PaymentDto result = paymentService.processPayment(inputDto); - - // Then - assertNotNull(result); - assertEquals(guid, result.getGuid()); - assertEquals(inquiryRefId, result.getInquiryRefId()); - assertEquals(transactionRefId, result.getTransactionRefId()); - assertEquals(new BigDecimal("500.50"), result.getAmount()); - assertEquals("USD", result.getCurrency()); - assertEquals(PaymentStatus.APPROVED, result.getStatus()); - assertEquals("Complete payment with all fields", result.getNote()); - assertEquals(now, result.getCreatedAt()); - assertEquals(now, result.getUpdatedAt()); - } - - @Test - @DisplayName("processPayment should handle payment with minimal fields") - void processPayment_shouldHandleMinimalPayment() { + @ParameterizedTest + @MethodSource("statusProvider") + @DisplayName("get should handle different payment statuses") + void get_shouldHandleDifferentStatuses(PaymentStatus status) { // Given - PaymentDto inputDto = PaymentDto.builder() + PaymentEntity paymentEntity = PaymentEntity.builder() + .guid(testUuid1) .inquiryRefId(UUID.randomUUID()) - .amount(new BigDecimal("10.00")) - .currency("USD") - .status(PaymentStatus.RECEIVED) - .build(); - - PaymentEntity entityToSave = PaymentEntity.builder() - .inquiryRefId(inputDto.getInquiryRefId()) - .amount(new BigDecimal("10.00")) - .currency("USD") - .status(PaymentStatus.RECEIVED) - .build(); - - PaymentEntity savedEntity = PaymentEntity.builder() - .guid(UUID.randomUUID()) - .inquiryRefId(inputDto.getInquiryRefId()) - .amount(new BigDecimal("10.00")) + .amount(new BigDecimal("100.00")) .currency("USD") - .status(PaymentStatus.RECEIVED) + .status(status) .createdAt(OffsetDateTime.now()) .updatedAt(OffsetDateTime.now()) .build(); - PaymentDto savedDto = PaymentDto.builder() - .guid(savedEntity.getGuid()) - .inquiryRefId(inputDto.getInquiryRefId()) - .amount(new BigDecimal("10.00")) - .currency("USD") - .status(PaymentStatus.RECEIVED) - .createdAt(savedEntity.getCreatedAt()) - .updatedAt(savedEntity.getUpdatedAt()) + PaymentDto paymentDto = PaymentDto.builder() + .guid(testUuid1) + .status(status) .build(); - when(paymentConverter.toPaymentEntity(inputDto)).thenReturn(entityToSave); - when(paymentRepository.save(entityToSave)).thenReturn(savedEntity); - when(paymentConverter.toPaymentDto(savedEntity)).thenReturn(savedDto); + when(paymentRepository.findById(testUuid1)).thenReturn(Optional.of(paymentEntity)); + when(paymentMapper.toPaymentDto(paymentEntity)).thenReturn(paymentDto); // When - PaymentDto result = paymentService.processPayment(inputDto); + PaymentDto result = paymentService.get(testUuid1); // Then - assertNotNull(result); - assertNotNull(result.getGuid()); - assertEquals(new BigDecimal("10.00"), result.getAmount()); - assertEquals("USD", result.getCurrency()); - assertEquals(PaymentStatus.RECEIVED, result.getStatus()); + assertEquals(status, result.getStatus()); } - static Stream statusProvider() { + private static Stream statusProvider() { return Stream.of( PaymentStatus.RECEIVED, PaymentStatus.PENDING, @@ -401,34 +281,4 @@ static Stream statusProvider() { ); } - @ParameterizedTest - @MethodSource("statusProvider") - @DisplayName("fetchSinglePayment should handle different payment statuses") - void fetchSinglePayment_shouldHandleDifferentStatuses_1(PaymentStatus status) { - // Given - PaymentEntity pendingEntity = PaymentEntity.builder() - .guid(testUuid1) - .inquiryRefId(UUID.randomUUID()) - .amount(new BigDecimal("100.00")) - .currency("USD") - .status(status) - .createdAt(OffsetDateTime.now()) - .updatedAt(OffsetDateTime.now()) - .build(); - - PaymentDto pendingDto = PaymentDto.builder() - .guid(testUuid1) - .status(status) - .build(); - - when(paymentRepository.findById(testUuid1)).thenReturn(Optional.of(pendingEntity)); - when(paymentConverter.toPaymentDto(pendingEntity)).thenReturn(pendingDto); - - // When - PaymentDto result = paymentService.fetchSinglePayment(testUuid1); - - // Then - assertEquals(status, result.getStatus()); - } - }