diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderAddressInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderAddressInfo.java new file mode 100644 index 0000000..86a6d2a --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderAddressInfo.java @@ -0,0 +1,9 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.order; + +public record OrderAddressInfo( + String street, + String city, + String postalCode, + String country +) { +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderDTO.java new file mode 100644 index 0000000..ae33548 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderDTO.java @@ -0,0 +1,10 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.order; + +import java.util.UUID; + +public record OrderDTO( + UUID orderId, + double totalAmount, + int earnedLoyaltyPoints +) { +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderInfo.java new file mode 100644 index 0000000..9358ceb --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderInfo.java @@ -0,0 +1,12 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.order; + +import java.util.List; +import java.util.UUID; + +public record OrderInfo( + UUID customerId, + List orderLines, + OrderAddressInfo deliveryAddress, + PaymentMode paymentMode +) { +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderLineInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderLineInfo.java new file mode 100644 index 0000000..b6c6c7d --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/OrderLineInfo.java @@ -0,0 +1,7 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.order; + +public record OrderLineInfo( + String bookIsbn, + int quantity +) { +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/PaymentMode.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/PaymentMode.java new file mode 100644 index 0000000..c0e1060 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/PaymentMode.java @@ -0,0 +1,7 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.order; + +public enum PaymentMode { + CB, + PAYPAL, + POINTS_FIDELITE +} diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCase.java new file mode 100644 index 0000000..6fde73b --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCase.java @@ -0,0 +1,53 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.order.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderLineInfo; +import java.util.UUID; + +public final class OrderUseCase { + + private final CustomerRepository customerRepository; + private final BookRepository bookRepository; + + public OrderUseCase(CustomerRepository customerRepository, BookRepository bookRepository) { + this.customerRepository = customerRepository; + this.bookRepository = bookRepository; + } + + public OrderDTO placeOrder(OrderInfo orderInfo) throws CustomerNotFoundException { + Customer customer = customerRepository.findById(orderInfo.customerId()) + .orElseThrow(() -> new CustomerNotFoundException(orderInfo.customerId())); + + double totalAmount = 0; + for (OrderLineInfo orderLine : orderInfo.orderLines()) { + Book book = bookRepository.findByIsbn(orderLine.bookIsbn()) + .orElseThrow(() -> new IllegalArgumentException("Book not found")); + totalAmount += book.getPrice() * orderLine.quantity(); + Book updatedBook = Book.builder() + .isbn(book.getIsbn()) + .title(book.getTitle()) + .author(book.getAuthor()) + .publisher(book.getPublisher()) + .categories(book.getCategories()) + .description(book.getDescription()) + .langue(book.getLangue()) + .publicationDate(book.getPublicationDate()) + .price(book.getPrice()) + .stock(book.getStock() - orderLine.quantity()) + .build(); + bookRepository.save(updatedBook); + } + + int earnedLoyaltyPoints = (int) totalAmount; + customer.addLoyaltyPoints(earnedLoyaltyPoints); + customerRepository.save(customer); + + return new OrderDTO(UUID.randomUUID(), totalAmount, earnedLoyaltyPoints); + } +} diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCaseTest.java new file mode 100644 index 0000000..d399cd6 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCaseTest.java @@ -0,0 +1,90 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.order.usecase; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderAddressInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderLineInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.order.PaymentMode; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class OrderUseCaseTest { + + @Mock + private CustomerRepository customerRepository; + + @Mock + private BookRepository bookRepository; + + @InjectMocks + private OrderUseCase orderUseCase; + + @Test + @DisplayName("Should place order and return expected amount and loyalty points") + void shouldPlaceOrderAndReturnExpectedAmountAndLoyaltyPoints() throws CustomerNotFoundException { + UUID customerId = UUID.randomUUID(); + Customer customer = Customer.builder() + .id(customerId) + .firstName("Jane") + .lastName("Doe") + .phoneNumber("0612345678") + .loyaltyPoints(10) + .build(); + + Book cleanCode = Book.builder() + .isbn("9780132350884") + .title("Clean Code") + .author("Robert C. Martin") + .publisher("Prentice Hall") + .categories(List.of("Programming")) + .description("A handbook of agile software craftsmanship") + .langue("fr") + .price(40.0) + .stock(10) + .build(); + + OrderInfo orderInfo = new OrderInfo( + customerId, + List.of(new OrderLineInfo("9780132350884", 2)), + new OrderAddressInfo("1 rue de Paris", "Paris", "75000", "France"), + PaymentMode.CB + ); + + when(customerRepository.findById(customerId)).thenReturn(Optional.of(customer)); + when(bookRepository.findByIsbn("9780132350884")).thenReturn(Optional.of(cleanCode)); + when(bookRepository.save(any(Book.class))).thenAnswer(invocation -> invocation.getArgument(0)); + when(customerRepository.save(any(Customer.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + OrderDTO orderDTO = orderUseCase.placeOrder(orderInfo); + + assertNotNull(orderDTO); + assertNotNull(orderDTO.orderId()); + assertEquals(80.0, orderDTO.totalAmount()); + assertEquals(80, orderDTO.earnedLoyaltyPoints()); + assertEquals(90, customer.getLoyaltyPoints()); + verify(customerRepository, times(1)).findById(customerId); + verify(bookRepository, times(1)).findByIsbn("9780132350884"); + verify(bookRepository, times(1)).save(any(Book.class)); + verify(customerRepository, times(1)).save(customer); + } +}