diff --git a/payment-service/src/main/java/com/example/paymentservice/config/Initializer.java b/payment-service/src/main/java/com/example/paymentservice/config/Initializer.java index f2a3721c..ca19981e 100644 --- a/payment-service/src/main/java/com/example/paymentservice/config/Initializer.java +++ b/payment-service/src/main/java/com/example/paymentservice/config/Initializer.java @@ -36,6 +36,7 @@ public void run(String... args) { .setName(faker.name().fullName()) .setEmail(faker.name().lastName() + "@gmail.com") .setAddress(faker.address().fullAddress()) + .setPhone(faker.phoneNumber().phoneNumber()) .setAmountAvailable(count) .setAmountReserved(0); customerList.add(customer); diff --git a/payment-service/src/main/java/com/example/paymentservice/entities/Customer.java b/payment-service/src/main/java/com/example/paymentservice/entities/Customer.java index 77dcc630..ba8146e5 100644 --- a/payment-service/src/main/java/com/example/paymentservice/entities/Customer.java +++ b/payment-service/src/main/java/com/example/paymentservice/entities/Customer.java @@ -11,6 +11,8 @@ public class Customer { private String address; + private String phone; + private int amountAvailable; private int amountReserved; @@ -61,6 +63,15 @@ public Customer setAddress(final String address) { return this; } + public String getPhone() { + return phone; + } + + public Customer setPhone(String phone) { + this.phone = phone; + return this; + } + public Customer setAmountAvailable(final int amountAvailable) { this.amountAvailable = amountAvailable; return this; @@ -78,6 +89,8 @@ public String toString() { + this.getName() + ", email=" + this.getEmail() + + ", phone=" + + this.getPhone() + ", address=" + this.getAddress() + ", amountAvailable=" diff --git a/payment-service/src/main/java/com/example/paymentservice/mapper/CustomerMapper.java b/payment-service/src/main/java/com/example/paymentservice/mapper/CustomerMapper.java index 9976fc6e..58854004 100644 --- a/payment-service/src/main/java/com/example/paymentservice/mapper/CustomerMapper.java +++ b/payment-service/src/main/java/com/example/paymentservice/mapper/CustomerMapper.java @@ -15,6 +15,7 @@ public Customer toEntity(CustomerRequest customerRequest) { customer.setName(customerRequest.name()); customer.setEmail(customerRequest.email()); customer.setAddress(customerRequest.address()); + customer.setPhone(customerRequest.phone()); customer.setAmountAvailable(customerRequest.amountAvailable()); return customer; } @@ -24,6 +25,7 @@ public CustomerResponse toResponse(Customer customer) { customer.getId(), customer.getName(), customer.getEmail(), + customer.getPhone(), customer.getAddress(), customer.getAmountAvailable()); } @@ -33,6 +35,7 @@ public void mapCustomerWithRequest(Customer customer, CustomerRequest customerRe customer.setName(customerRequest.name()); customer.setAddress(customerRequest.address()); customer.setEmail(customerRequest.email()); + customer.setPhone(customerRequest.phone()); } public List toListResponse(List customerList) { diff --git a/payment-service/src/main/java/com/example/paymentservice/model/request/CustomerRequest.java b/payment-service/src/main/java/com/example/paymentservice/model/request/CustomerRequest.java index ae7cf4bd..a8d73947 100644 --- a/payment-service/src/main/java/com/example/paymentservice/model/request/CustomerRequest.java +++ b/payment-service/src/main/java/com/example/paymentservice/model/request/CustomerRequest.java @@ -9,5 +9,6 @@ public record CustomerRequest( @NotBlank(message = "Name cannot be Blank") String name, @NotBlank(message = "Email cannot be Blank") @Email(message = "supplied email is not valid") String email, + @NotBlank(message = "Customer Phone number is required") String phone, String address, @Positive(message = "AmountAvailable must be greater than 0") int amountAvailable) {} diff --git a/payment-service/src/main/java/com/example/paymentservice/model/response/CustomerResponse.java b/payment-service/src/main/java/com/example/paymentservice/model/response/CustomerResponse.java index 8d4c226f..d9b66f77 100644 --- a/payment-service/src/main/java/com/example/paymentservice/model/response/CustomerResponse.java +++ b/payment-service/src/main/java/com/example/paymentservice/model/response/CustomerResponse.java @@ -2,4 +2,9 @@ package com.example.paymentservice.model.response; public record CustomerResponse( - Long customerId, String name, String email, String address, int amountAvailable) {} + Long customerId, + String name, + String email, + String phone, + String address, + int amountAvailable) {} diff --git a/payment-service/src/main/java/com/example/paymentservice/repositories/CustomerRepository.java b/payment-service/src/main/java/com/example/paymentservice/repositories/CustomerRepository.java index 00b1e8ae..05d57aa9 100644 --- a/payment-service/src/main/java/com/example/paymentservice/repositories/CustomerRepository.java +++ b/payment-service/src/main/java/com/example/paymentservice/repositories/CustomerRepository.java @@ -14,6 +14,8 @@ public interface CustomerRepository { Optional findById(Long customerId); + Optional findByEmail(String email); + Customer save(Customer customer); void deleteById(Long id); diff --git a/payment-service/src/main/java/com/example/paymentservice/repositories/CustomerRepositoryImpl.java b/payment-service/src/main/java/com/example/paymentservice/repositories/CustomerRepositoryImpl.java index 2af2d025..521fb869 100644 --- a/payment-service/src/main/java/com/example/paymentservice/repositories/CustomerRepositoryImpl.java +++ b/payment-service/src/main/java/com/example/paymentservice/repositories/CustomerRepositoryImpl.java @@ -54,6 +54,7 @@ public Optional findByName(String name) { CUSTOMERS.ID, CUSTOMERS.NAME, CUSTOMERS.EMAIL, + CUSTOMERS.PHONE, CUSTOMERS.ADDRESS, CUSTOMERS.AMOUNT_AVAILABLE) .from(CUSTOMERS) @@ -68,6 +69,13 @@ public Optional findById(Long customerId) { .map(r -> r.into(Customer.class)); } + @Override + public Optional findByEmail(String customerEmail) { + return dslContext + .fetchOptional(CUSTOMERS, CUSTOMERS.EMAIL.eq(customerEmail)) + .map(r -> r.into(Customer.class)); + } + @Override @Transactional public Customer save(Customer customer) { @@ -86,6 +94,7 @@ public Customer save(Customer customer) { .set(CUSTOMERS.ADDRESS, customer.getAddress()) .set(CUSTOMERS.NAME, customer.getName()) .set(CUSTOMERS.EMAIL, customer.getEmail()) + .set(CUSTOMERS.PHONE, customer.getPhone()) .where(CUSTOMERS.ID.eq(customer.getId())) .returningResult() .fetchOneInto(Customer.class); diff --git a/payment-service/src/main/java/com/example/paymentservice/services/CustomerService.java b/payment-service/src/main/java/com/example/paymentservice/services/CustomerService.java index 57486aa1..17668803 100644 --- a/payment-service/src/main/java/com/example/paymentservice/services/CustomerService.java +++ b/payment-service/src/main/java/com/example/paymentservice/services/CustomerService.java @@ -72,8 +72,16 @@ public Optional findCustomerByName(String name) { @Transactional public CustomerResponse saveCustomer(CustomerRequest customerRequest) { - Customer customer = customerMapper.toEntity(customerRequest); - return customerMapper.toResponse(customerRepository.save(customer)); + Optional customerByEmail = + customerRepository.findByEmail(customerRequest.email()); + Customer customer; + if (customerByEmail.isPresent()) { + customer = customerByEmail.get(); + } else { + Customer requestCustomer = customerMapper.toEntity(customerRequest); + customer = customerRepository.save(requestCustomer); + } + return customerMapper.toResponse(customer); } @Transactional diff --git a/payment-service/src/main/resources/db/changelog/migration/01-create_customers_table.xml b/payment-service/src/main/resources/db/changelog/migration/01-create_customers_table.xml index 15fbda83..b31070a2 100644 --- a/payment-service/src/main/resources/db/changelog/migration/01-create_customers_table.xml +++ b/payment-service/src/main/resources/db/changelog/migration/01-create_customers_table.xml @@ -30,6 +30,9 @@ + + + diff --git a/payment-service/src/test/java/com/example/paymentservice/services/listener/KafkaListenerConfigIntegrationTest.java b/payment-service/src/test/java/com/example/paymentservice/services/listener/KafkaListenerConfigIntegrationTest.java index ef8d8395..a8fb5f82 100644 --- a/payment-service/src/test/java/com/example/paymentservice/services/listener/KafkaListenerConfigIntegrationTest.java +++ b/payment-service/src/test/java/com/example/paymentservice/services/listener/KafkaListenerConfigIntegrationTest.java @@ -37,6 +37,7 @@ void setUp() { new Customer() .setName("First Customer") .setEmail("first@customer.email") + .setPhone("1234567890") .setAddress("First Address") .setAmountAvailable(100) .setAmountReserved(10)); diff --git a/payment-service/src/test/java/com/example/paymentservice/web/controllers/CustomerControllerIT.java b/payment-service/src/test/java/com/example/paymentservice/web/controllers/CustomerControllerIT.java index 9aaa4018..1d0d047d 100644 --- a/payment-service/src/test/java/com/example/paymentservice/web/controllers/CustomerControllerIT.java +++ b/payment-service/src/test/java/com/example/paymentservice/web/controllers/CustomerControllerIT.java @@ -38,18 +38,21 @@ void setUp() { new Customer() .setName("First Customer") .setEmail("first@customer.email") + .setPhone("9876543210") .setAddress("First Address") .setAmountAvailable(100) .setAmountReserved(0), new Customer() .setName("Second Customer") .setEmail("second@customer.email") + .setPhone("9876543210") .setAddress("Second Address") .setAmountAvailable(100) .setAmountReserved(0), new Customer() .setName("Third Customer") .setEmail("third@customer.email") + .setPhone("9876543210") .setAddress("Third Address") .setAmountAvailable(100) .setAmountReserved(0)); @@ -83,6 +86,7 @@ void shouldFindCustomerById() throws Exception { .andExpect(jsonPath("$.customerId", is(customer.getId()), Long.class)) .andExpect(jsonPath("$.name", is(customer.getName()))) .andExpect(jsonPath("$.email", is(customer.getEmail()))) + .andExpect(jsonPath("$.phone", is(customer.getPhone()))) .andExpect(jsonPath("$.address", is(customer.getAddress()))) .andExpect(jsonPath("$.amountAvailable", is(customer.getAmountAvailable()))); } @@ -116,6 +120,7 @@ void shouldFindCustomerByName() throws Exception { .andExpect(jsonPath("$.customerId", is(customer.getId()), Long.class)) .andExpect(jsonPath("$.name", is(customer.getName()))) .andExpect(jsonPath("$.email", is(customer.getEmail()))) + .andExpect(jsonPath("$.phone", is(customer.getPhone()))) .andExpect(jsonPath("$.address", is(customer.getAddress()))) .andExpect(jsonPath("$.amountAvailable", is(customer.getAmountAvailable()))); } @@ -124,7 +129,11 @@ void shouldFindCustomerByName() throws Exception { void shouldCreateNewCustomer() throws Exception { CustomerRequest customerRequest = new CustomerRequest( - "New Customer", "firstnew@customerRequest.email", "First Address", 10_000); + "New Customer", + "firstnew@customerRequest.email", + "1234567890", + "First Address", + 10_000); this.mockMvc .perform( post("/api/customers") @@ -135,13 +144,39 @@ void shouldCreateNewCustomer() throws Exception { .andExpect(jsonPath("$.customerId", notNullValue(Long.class))) .andExpect(jsonPath("$.name", is(customerRequest.name()))) .andExpect(jsonPath("$.email", is(customerRequest.email()))) + .andExpect(jsonPath("$.phone", is(customerRequest.phone()))) + .andExpect(jsonPath("$.address", is(customerRequest.address()))) + .andExpect(jsonPath("$.amountAvailable", is(customerRequest.amountAvailable()))); + } + + @Test + void shouldReturnWithNoErrorCreatingExistingCustomer() throws Exception { + Customer customer = customerList.getFirst(); + CustomerRequest customerRequest = + new CustomerRequest( + customer.getName(), + customer.getEmail(), + customer.getPhone(), + customer.getAddress(), + customer.getAmountAvailable()); + this.mockMvc + .perform( + post("/api/customers") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(customerRequest))) + .andExpect(status().isCreated()) + .andExpect(header().exists(HttpHeaders.LOCATION)) + .andExpect(jsonPath("$.customerId", notNullValue(Long.class))) + .andExpect(jsonPath("$.name", is(customerRequest.name()))) + .andExpect(jsonPath("$.email", is(customerRequest.email()))) + .andExpect(jsonPath("$.phone", is(customerRequest.phone()))) .andExpect(jsonPath("$.address", is(customerRequest.address()))) .andExpect(jsonPath("$.amountAvailable", is(customerRequest.amountAvailable()))); } @Test void shouldReturn400WhenCreateNewCustomerWithoutNameAndEmail() throws Exception { - CustomerRequest customer = new CustomerRequest(null, null, null, 0); + CustomerRequest customer = new CustomerRequest(null, null, null, null, 0); this.mockMvc .perform( @@ -159,7 +194,7 @@ void shouldReturn400WhenCreateNewCustomerWithoutNameAndEmail() throws Exception is("https://zalando.github.io/problem/constraint-violation"))) .andExpect(jsonPath("$.title", is("Constraint Violation"))) .andExpect(jsonPath("$.status", is(400))) - .andExpect(jsonPath("$.violations", hasSize(3))) + .andExpect(jsonPath("$.violations", hasSize(4))) .andExpect(jsonPath("$.violations[0].field", is("amountAvailable"))) .andExpect( jsonPath( @@ -176,7 +211,8 @@ void shouldReturn400WhenCreateNewCustomerWithoutNameAndEmail() throws Exception void shouldUpdateCustomer() throws Exception { Long customerId = customerList.getFirst().getId(); CustomerRequest customerRequest = - new CustomerRequest("Updated text", "first@customer.email", "First Address", 500); + new CustomerRequest( + "Updated text", "first@customer.email", "1234567890", "First Address", 500); this.mockMvc .perform( @@ -188,6 +224,7 @@ void shouldUpdateCustomer() throws Exception { .andExpect(jsonPath("$.name", is(customerRequest.name()))) .andExpect(jsonPath("$.email", is(customerRequest.email()))) .andExpect(jsonPath("$.address", is(customerRequest.address()))) + .andExpect(jsonPath("$.phone", is(customerRequest.phone()))) .andExpect(jsonPath("$.amountAvailable", is(customerRequest.amountAvailable()))); } @@ -196,7 +233,11 @@ void shouldReturn404WhenUpdatingNonExistingCustomer() throws Exception { long customerId = customerList.getFirst().getId() + 99_999; CustomerRequest customerRequest = new CustomerRequest( - "Updated text", "first@customer.email", "First Address", 10_000); + "Updated text", + "first@customer.email", + "1234567890", + "First Address", + 10_000); this.mockMvc .perform( @@ -227,6 +268,7 @@ void shouldDeleteCustomer() throws Exception { .andExpect(jsonPath("$.name", is(customer.getName()))) .andExpect(jsonPath("$.email", is(customer.getEmail()))) .andExpect(jsonPath("$.address", is(customer.getAddress()))) + .andExpect(jsonPath("$.phone", is(customer.getPhone()))) .andExpect(jsonPath("$.amountAvailable", is(customer.getAmountAvailable()))); } diff --git a/payment-service/src/test/java/com/example/paymentservice/web/controllers/CustomerControllerTest.java b/payment-service/src/test/java/com/example/paymentservice/web/controllers/CustomerControllerTest.java index 9ed77b01..0c772e7c 100644 --- a/payment-service/src/test/java/com/example/paymentservice/web/controllers/CustomerControllerTest.java +++ b/payment-service/src/test/java/com/example/paymentservice/web/controllers/CustomerControllerTest.java @@ -114,6 +114,7 @@ private List getCustomerResponseList() { customer.getId(), customer.getName(), customer.getEmail(), + customer.getPhone(), customer.getAddress(), customer.getAmountAvailable())) .toList(); @@ -127,7 +128,12 @@ void shouldFindCustomerById() throws Exception { Long customerId = 1L; CustomerResponse customerResponse = new CustomerResponse( - customerId, "text 1", "junit@email.com", "junitAddress", 100); + customerId, + "text 1", + "junit@email.com", + "9876543210", + "junitAddress", + 100); given(customerService.findCustomerById(customerId)) .willReturn(Optional.of(customerResponse)); @@ -181,9 +187,11 @@ class Save { void shouldCreateNewCustomer() throws Exception { CustomerRequest customerRequest = - new CustomerRequest("junitName", "email@junit.com", "junitAddress", 10); + new CustomerRequest( + "junitName", "email@junit.com", "1234567890", "junitAddress", 10); CustomerResponse customerResponse = - new CustomerResponse(1L, "junitName", "email@junit.com", "junitAddress", 10); + new CustomerResponse( + 1L, "junitName", "email@junit.com", "9876543210", "junitAddress", 10); given(customerService.saveCustomer(any(CustomerRequest.class))) .willReturn(customerResponse); mockMvc.perform( @@ -196,7 +204,7 @@ void shouldCreateNewCustomer() throws Exception { @Test void shouldReturn400WhenCreateNewCustomerWithoutNameAndEmail() throws Exception { - CustomerRequest customerRequest = new CustomerRequest(null, null, null, 1); + CustomerRequest customerRequest = new CustomerRequest(null, null, null, null, 1); mockMvc.perform( post("/api/customers") @@ -213,7 +221,7 @@ void shouldReturn400WhenCreateNewCustomerWithoutNameAndEmail() throws Exception is("https://zalando.github.io/problem/constraint-violation"))) .andExpect(jsonPath("$.title", is("Constraint Violation"))) .andExpect(jsonPath("$.status", is(400))) - .andExpect(jsonPath("$.violations", hasSize(2))) + .andExpect(jsonPath("$.violations", hasSize(3))) .andExpect(jsonPath("$.violations[0].field", is("email"))) .andExpect(jsonPath("$.violations[0].message", is("Email cannot be Blank"))) .andExpect(jsonPath("$.violations[1].field", is("name"))) @@ -230,7 +238,11 @@ void shouldUpdateCustomer() throws Exception { CustomerRequest customerRequest = new CustomerRequest( - "customerUpdatedName", "junitEmail@email.com", "junitAddress", 100); + "customerUpdatedName", + "junitEmail@email.com", + "1234567890", + "junitAddress", + 100); given(customerService.updateCustomer(eq(1L), any(CustomerRequest.class))) .willReturn( @@ -238,6 +250,7 @@ void shouldUpdateCustomer() throws Exception { 1L, "customerUpdatedName", "junitEmail@email.com", + "9876543210", "junitAddress", 100)); @@ -254,7 +267,11 @@ void shouldReturn404WhenUpdatingNonExistingCustomer() throws Exception { Long customerId = 1L; CustomerRequest customerRequest = new CustomerRequest( - "customerUpdatedName", "junitEmail@email.com", "junitAddress", 100); + "customerUpdatedName", + "junitEmail@email.com", + "1234567890", + "junitAddress", + 100); given(customerService.updateCustomer(eq(customerId), any(CustomerRequest.class))) .willThrow(new CustomerNotFoundException(customerId)); @@ -282,7 +299,12 @@ void shouldDeleteCustomer() throws Exception { Long customerId = 1L; CustomerResponse customer = new CustomerResponse( - customerId, "Some text", "junit@email.com", "junitAddress", 0); + customerId, + "Some text", + "junit@email.com", + "9876543210", + "junitAddress", + 0); given(customerService.findCustomerById(customerId)).willReturn(Optional.of(customer)); doNothing().when(customerService).deleteCustomerById(customerId); diff --git a/test-em-all.sh b/test-em-all.sh index 0d043200..47cce9e5 100755 --- a/test-em-all.sh +++ b/test-em-all.sh @@ -147,7 +147,7 @@ function setupTestData() { body="{\"name\": \"$CUSTOMER_NAME" body+=\ -'","email": "docker@email.com","address": "docker Address","amountAvailable":1000}' +'","email": "docker@email.com","phone":"9876543210","address": "docker Address","amountAvailable":1000}' # Creating Customer recreateComposite "$CUSTOMER_NAME" "$body" "payment-service/api/customers" "POST"