From 5f2b7afb5eb0d71c03a2bd4bbad985ca801bfbb7 Mon Sep 17 00:00:00 2001 From: vamshinerella Date: Fri, 18 Aug 2023 13:58:59 -0500 Subject: [PATCH] Adding retrieve payment api to Candidate sample application --- .../user/controller/PaymentController.java | 40 +++++++++ .../com/bravo/user/dao/model/Payment.java | 1 + .../user/dao/model/mapper/ResourceMapper.java | 12 ++- .../dao/repository/PaymentRepository.java | 13 +++ .../bravo/user/service/PaymentService.java | 45 ++++++++++ .../user/validator/PaymentValidator.java | 20 +++++ src/main/resources/data.sql | 15 ++++ .../controller/PaymentControllerTest.java | 83 +++++++++++++++++++ .../user/service/PaymentServiceTest.java | 82 ++++++++++++++++++ 9 files changed, 307 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/bravo/user/controller/PaymentController.java create mode 100644 src/main/java/com/bravo/user/dao/repository/PaymentRepository.java create mode 100644 src/main/java/com/bravo/user/service/PaymentService.java create mode 100644 src/main/java/com/bravo/user/validator/PaymentValidator.java create mode 100644 src/test/java/com/bravo/user/controller/PaymentControllerTest.java create mode 100644 src/test/java/com/bravo/user/service/PaymentServiceTest.java diff --git a/src/main/java/com/bravo/user/controller/PaymentController.java b/src/main/java/com/bravo/user/controller/PaymentController.java new file mode 100644 index 0000000..f74195f --- /dev/null +++ b/src/main/java/com/bravo/user/controller/PaymentController.java @@ -0,0 +1,40 @@ +package com.bravo.user.controller; + +import com.bravo.user.model.dto.PaymentDto; +import com.bravo.user.service.PaymentService; +import com.bravo.user.validator.PaymentValidator; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@Tag(name = "Payment", description = "Payment Actions") +@RequestMapping(value = "/payment") +public class PaymentController { + + private final PaymentService paymentService; + private final PaymentValidator paymentValidator; + public PaymentController(PaymentService paymentService, PaymentValidator paymentValidator) { + this.paymentService = paymentService; + this.paymentValidator = paymentValidator; + } + + @Operation(summary = "Retrieve Payment Information") + @ApiResponse(responseCode = "200", content = { + @Content(schema = @Schema(implementation = List.class), mediaType = "application/json") + }) + @ApiResponse(responseCode = "400", content = {@Content(schema = @Schema())}) + @GetMapping(value = "/retrieve/{userId}") + @ResponseBody + public List retrieve( + final @PathVariable String userId + ) { + paymentValidator.validateUserId(userId); + return paymentService.retrieveByUserID(userId); + } +} diff --git a/src/main/java/com/bravo/user/dao/model/Payment.java b/src/main/java/com/bravo/user/dao/model/Payment.java index adb4932..398fcad 100644 --- a/src/main/java/com/bravo/user/dao/model/Payment.java +++ b/src/main/java/com/bravo/user/dao/model/Payment.java @@ -12,6 +12,7 @@ public class Payment { @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") private String id; diff --git a/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java b/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java index 9fc44ef..f7951d0 100644 --- a/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java +++ b/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java @@ -8,12 +8,13 @@ import com.bravo.user.model.dto.PaymentDto; import com.bravo.user.model.dto.ProfileDto; import com.bravo.user.model.dto.UserReadDto; -import java.util.Collection; -import java.util.List; - +import org.apache.commons.lang3.StringUtils; import org.modelmapper.ModelMapper; import org.springframework.stereotype.Component; +import java.util.Collection; +import java.util.List; + @Component public class ResourceMapper { @@ -28,6 +29,7 @@ public > List convertAddresses(final T return addresses.stream().map(this::convertAddress).toList(); } + public AddressDto convertAddress(final Address address){ final AddressDto dto = modelMapper.map(address, AddressDto.class); dto.setAddress( @@ -49,7 +51,9 @@ public > List convertPayments(final T public PaymentDto convertPayment(final Payment payment){ final String cardNumber = payment.getCardNumber(); final PaymentDto dto = modelMapper.map(payment, PaymentDto.class); - dto.setCardNumberLast4(cardNumber.substring(cardNumber.length() - 5)); + if (!StringUtils.isAllBlank(cardNumber) && cardNumber.length() >5) { + dto.setCardNumberLast4(cardNumber.substring(cardNumber.length() - 5)); + } return dto; } diff --git a/src/main/java/com/bravo/user/dao/repository/PaymentRepository.java b/src/main/java/com/bravo/user/dao/repository/PaymentRepository.java new file mode 100644 index 0000000..48322f0 --- /dev/null +++ b/src/main/java/com/bravo/user/dao/repository/PaymentRepository.java @@ -0,0 +1,13 @@ +package com.bravo.user.dao.repository; + +import com.bravo.user.dao.model.Payment; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface PaymentRepository extends JpaRepository, JpaSpecificationExecutor { + List findByUserId(String id); +} diff --git a/src/main/java/com/bravo/user/service/PaymentService.java b/src/main/java/com/bravo/user/service/PaymentService.java new file mode 100644 index 0000000..49e4f71 --- /dev/null +++ b/src/main/java/com/bravo/user/service/PaymentService.java @@ -0,0 +1,45 @@ +package com.bravo.user.service; + +import com.bravo.user.dao.model.Payment; +import com.bravo.user.dao.model.mapper.ResourceMapper; +import com.bravo.user.dao.repository.PaymentRepository; +import com.bravo.user.exception.DataNotFoundException; +import com.bravo.user.model.dto.PaymentDto; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +@Service +public class PaymentService { + @Autowired + private final PaymentRepository paymentRepository; + private final ResourceMapper resourceMapper; + private static final Logger LOGGER = LoggerFactory.getLogger(PaymentService.class); + + public PaymentService(PaymentRepository paymentRepository, ResourceMapper resourceMapper) { + this.paymentRepository = paymentRepository; + this.resourceMapper = resourceMapper; + } + + public List retrieveByUserID(String id) { + LOGGER.warn("Payments for user DB : "+id); + List optionalPayments = paymentRepository.findByUserId(id); + List payments = resourceMapper.convertPayments(optionalPayments); + LOGGER.warn("Payments from DB : "+optionalPayments); + return payments; + } + + private Collection getPayment(Optional> payments) { + if(payments.isEmpty()){ + final String message = String.format("payments '%s' doesn't exist", payments); + LOGGER.warn(message); + throw new DataNotFoundException(message); + } + return payments.get(); + } +} diff --git a/src/main/java/com/bravo/user/validator/PaymentValidator.java b/src/main/java/com/bravo/user/validator/PaymentValidator.java new file mode 100644 index 0000000..60434f1 --- /dev/null +++ b/src/main/java/com/bravo/user/validator/PaymentValidator.java @@ -0,0 +1,20 @@ +package com.bravo.user.validator; + +import com.bravo.user.exception.BadRequestException; +import com.bravo.user.model.dto.UserSaveDto; +import com.bravo.user.utility.ValidatorUtil; +import java.util.Objects; +import org.springframework.stereotype.Component; +import org.springframework.validation.Errors; + +@Component +public class PaymentValidator extends CrudValidator { + + public void validateUserId(String id){ + if(ValidatorUtil.isInvalid(id)){ + throw new BadRequestException("'id' is required"); + } + } + + +} diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index c4868b9..baa047a 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -646,3 +646,18 @@ insert into address (id, user_id, line1, line2, city, state, zip) values ('42f33d30-f3f8-4743-a94e-4db11fdb747d', '008a4215-0b1d-445e-b655-a964039cbb5a', '412 Maple St', null, 'Dowagiac', 'Michigan', '49047'), ('579872ec-46f8-46b5-b809-d0724d965f0e', '00963d9b-f884-485e-9455-fcf30c6ac379', '237 Mountain Ter', 'Apt 10', 'Odenville', 'Alabama', '35120'), ('95a983d0-ba0e-4f30-afb6-667d4724b253', '00963d9b-f884-485e-9455-fcf30c6ac379', '107 Annettes Ct', null, 'Aydlett', 'North Carolina', '27916'); + + + +insert into payment (ID,USER_ID,CARD_NUMBER,EXPIRY_MONTH,EXPIRY_YEAR,UPDATED) values +('1','008a4215-0b1d-445e-b655-a964039cbb5a','1234654477881234','04','2017','2023-08-17 19:07:08.808026') +,('2','008a4215-0b1d-445e-b655-a964039cbb5a','1234654477882345','05','2023','2023-08-17 19:07:08.808026') +,('3','fd6d21f6-f1c2-473d-8ed7-f3f9c7550cc9','1234654477887890','08','2026','2023-08-17 19:07:08.808026') +,('4','fd6d21f6-f1c2-473d-8ed7-f3f9c7550cc9','378282246310005','08','2026','2023-08-17 19:07:08.808026') +,('5','f8f76b77-7007-47a5-9c50-5dfc26f59eb5','371449635398431','08','2026','2023-08-17 19:07:08.808026') +,('6','f8160123-1766-41c7-8056-2acbfd3c4f2a','378734493671000','08','2026','2023-08-17 19:07:08.808026') +,('7','f8730cc6-a89b-40ca-94b2-ff4f7b3e0044','6011111111111117','08','2026','2023-08-17 19:07:08.808026') +,('8','f97177e1-5fe1-4327-9978-9e9d48b23338','6011000990139424','08','2026','2023-08-17 19:07:08.808026') +,('9','fd152dd9-6fae-4cb2-a041-02162f200678','3566002020360505','08','2026','2023-08-17 19:07:08.808026') +,('10','fcee9b60-6a3f-4fae-b7b3-27bc70c68b6f','5555555555554444','08','2026','2023-08-17 19:07:08.808026') +,('11','fd9e22ef-20f1-4e1b-9f9e-3139fd13fa85','5105105105105100','08','2026','2023-08-17 19:07:08.808026'); \ No newline at end of file diff --git a/src/test/java/com/bravo/user/controller/PaymentControllerTest.java b/src/test/java/com/bravo/user/controller/PaymentControllerTest.java new file mode 100644 index 0000000..e36df03 --- /dev/null +++ b/src/test/java/com/bravo/user/controller/PaymentControllerTest.java @@ -0,0 +1,83 @@ +package com.bravo.user.controller; + +import com.bravo.user.App; +import com.bravo.user.model.dto.PaymentDto; +import com.bravo.user.service.PaymentService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ContextConfiguration(classes = { App.class }) +@ExtendWith(SpringExtension.class) +@SpringBootTest() +@AutoConfigureMockMvc +class PaymentControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private PaymentService paymentService; + + private List paymentDtos; + + @BeforeEach + public void beforeEach() { + final List ids = IntStream.range(1, 10).boxed().toList(); + + this.paymentDtos = ids.stream().map(id -> createPaymentDto(Integer.toString(id))) + .collect(Collectors.toList()); + } + + @Test + void getRetrieveByUserId() throws Exception { + final String userId = "123a-456b"; + + when(paymentService.retrieveByUserID(anyString())).thenReturn(paymentDtos); + + final ResultActions result = this.mockMvc.perform(get("/payment/retrieve/".concat(userId))) + .andExpect(status().isOk()); + + for (int i = 0; i < paymentDtos.size(); i++) { + result.andExpect(jsonPath(String.format("$[%d].id", i)).value(paymentDtos.get(i).getId())); + } + + verify(paymentService).retrieveByUserID(userId); + } + + @Test + void getRetrieveByUserId_Space() throws Exception { + this.mockMvc.perform(get("/payment/retrieve/ /")).andExpect(status().isNotFound()); + } + + @Test + void getRetrieveByUserId_Missing() throws Exception { + this.mockMvc.perform(get("/payment/retrieve")).andExpect(status().isNotFound()); + } + + private PaymentDto createPaymentDto(final String id) { + final PaymentDto paymentDto = new PaymentDto(); + paymentDto.setId(id); + return paymentDto; + } + +} diff --git a/src/test/java/com/bravo/user/service/PaymentServiceTest.java b/src/test/java/com/bravo/user/service/PaymentServiceTest.java new file mode 100644 index 0000000..7646722 --- /dev/null +++ b/src/test/java/com/bravo/user/service/PaymentServiceTest.java @@ -0,0 +1,82 @@ +package com.bravo.user.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import com.bravo.user.dao.model.Payment; +import com.bravo.user.dao.repository.PaymentRepository; +import com.bravo.user.model.dto.PaymentDto; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import com.bravo.user.App; +import com.bravo.user.dao.model.Address; +import com.bravo.user.dao.model.mapper.ResourceMapper; +import com.bravo.user.dao.repository.AddressRepository; +import com.bravo.user.model.dto.AddressDto; + +@ContextConfiguration(classes = { App.class }) +@ExtendWith(SpringExtension.class) +@SpringBootTest +class PaymentServiceTest { + + @Autowired + private PaymentService paymentService; + + @MockBean + private ResourceMapper resourceMapper; + + @MockBean + private PaymentRepository paymentRepository; + + private List dtoPayment; + + @BeforeEach + public void beforeEach() { + final List ids = IntStream.range(1, 10).boxed().collect(Collectors.toList()); + + final List daoPayment = ids.stream() + .map(id -> createAddress(Integer.toString(id))).collect(Collectors.toList()); + + when(paymentRepository.findByUserId(anyString())).thenReturn(daoPayment); + + this.dtoPayment = ids.stream().map(id -> createAddressDto(Integer.toString(id))) + .collect(Collectors.toList()); + + when(resourceMapper.convertPayments(daoPayment)).thenReturn(dtoPayment); + } + + @Test + void retrieveByUserId() { + final String userId = "123a-456b"; + final List results = paymentService.retrieveByUserID(userId); + assertEquals(dtoPayment, results); + + verify(paymentRepository).findByUserId(userId); + } + + private Payment createAddress(final String id) { + final Payment payment = new Payment(); + payment.setId(id); + return payment; + } + + private PaymentDto createAddressDto(final String id) { + final PaymentDto paymentDto = new PaymentDto(); + paymentDto.setId(id); + return paymentDto; + } + +}