Compare commits

...

3 Commits

Author SHA1 Message Date
AISSI-JUDE-CHRIST 4815d2d0ba Suite des tests pour passer les commandes, correction des tests 2026-04-17 17:23:02 +02:00
AISSI-JUDE-CHRIST 7b4b8124a7 stock insufisant & tests à corriger 2026-04-14 14:25:47 +02:00
AISSI-JUDE-CHRIST 84b2880b1d Passer des commandes 2026-04-14 13:56:39 +02:00
9 changed files with 304 additions and 7 deletions
@@ -1,14 +1,13 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
import java.text.MessageFormat;
import java.util.UUID;
public class BookNotFoundException {
public class BookNotFoundException extends Exception {
public static final String THE_BOOK_WITH_ID_DOES_NOT_EXISTS = "The book with id {0} does not exist";
public BookNotFoundException(UUID uuid) {
super(); //super(MessageFormat.format(THE_BOOK_WITH_ID_DOES_NOT_EXISTS, uuid)); à corriger
}
public static final String THE_BOOK_WITH_ISBN_DOES_NOT_EXIST =
"The book with isbn {0} does not exist";
public BookNotFoundException(String isbn) {
super(MessageFormat.format(THE_BOOK_WITH_ISBN_DOES_NOT_EXIST, isbn));
}
}
@@ -0,0 +1,9 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order;
public record OrderAddressInfo(
String street,
String city,
String postalCode,
String country
) {
}
@@ -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
) {
}
@@ -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<OrderLineInfo> orderLines,
OrderAddressInfo deliveryAddress,
PaymentMode paymentMode
) {
}
@@ -0,0 +1,7 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order;
public record OrderLineInfo(
String bookIsbn,
int quantity
) {
}
@@ -0,0 +1,7 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order;
public enum PaymentMode {
CB,
PAYPAL,
POINTS_FIDELITE
}
@@ -0,0 +1,9 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
public class InsufficientStockException extends Exception {
public InsufficientStockException(String bookIsbn, int requested, int available) {
super("Insufficient stock for book " + bookIsbn + ": requested=" + requested
+ ", available=" + available);
}
}
@@ -0,0 +1,59 @@
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.exception.BookNotFoundException;
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 fr.iut_fbleau.but3.dev62.mylibrary.order.exception.InsufficientStockException;
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, InsufficientStockException, BookNotFoundException {
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 BookNotFoundException(orderLine.bookIsbn()));
if (orderLine.quantity() > book.getStock()) {
throw new InsufficientStockException(book.getIsbn(), orderLine.quantity(), book.getStock());
}
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);
}
}
@@ -0,0 +1,185 @@
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.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.never;
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.exception.BookNotFoundException;
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 fr.iut_fbleau.but3.dev62.mylibrary.order.exception.InsufficientStockException;
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, InsufficientStockException, BookNotFoundException {
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);
}
@Test
@DisplayName("Should throw when requested quantity is greater than available stock")
void shouldThrowWhenRequestedQuantityIsGreaterThanAvailableStock() throws BookNotFoundException {
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(1)
.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));
assertThrows(InsufficientStockException.class, () -> orderUseCase.placeOrder(orderInfo));
verify(customerRepository, times(1)).findById(customerId);
verify(bookRepository, times(1)).findByIsbn("9780132350884");
verify(bookRepository, never()).save(any(Book.class));
verify(customerRepository, never()).save(any(Customer.class));
}
@Test
@DisplayName("Should throw when customer does not exist")
void shouldThrowWhenCustomerDoesNotExist() {
UUID customerId = UUID.randomUUID();
OrderInfo orderInfo = new OrderInfo(
customerId,
List.of(new OrderLineInfo("9780132350884", 1)),
new OrderAddressInfo("1 rue de Paris", "Paris", "75000", "France"),
PaymentMode.CB
);
when(customerRepository.findById(customerId)).thenReturn(Optional.empty());
assertThrows(CustomerNotFoundException.class, () -> orderUseCase.placeOrder(orderInfo));
verify(customerRepository, times(1)).findById(customerId);
verify(bookRepository, never()).findByIsbn(any(String.class));
verify(bookRepository, never()).save(any(Book.class));
verify(customerRepository, never()).save(any(Customer.class));
}
@Test
@DisplayName("Should throw when ordered book does not exist")
void shouldThrowWhenOrderedBookDoesNotExist() {
UUID customerId = UUID.randomUUID();
Customer customer = Customer.builder()
.id(customerId)
.firstName("Jane")
.lastName("Doe")
.phoneNumber("0612345678")
.loyaltyPoints(10)
.build();
String unknownIsbn = "9999999999999";
OrderInfo orderInfo = new OrderInfo(
customerId,
List.of(new OrderLineInfo(unknownIsbn, 1)),
new OrderAddressInfo("1 rue de Paris", "Paris", "75000", "France"),
PaymentMode.CB
);
when(customerRepository.findById(customerId)).thenReturn(Optional.of(customer));
when(bookRepository.findByIsbn(unknownIsbn)).thenReturn(Optional.empty());
assertThrows(BookNotFoundException.class, () -> orderUseCase.placeOrder(orderInfo));
verify(customerRepository, times(1)).findById(customerId);
verify(bookRepository, times(1)).findByIsbn(unknownIsbn);
verify(bookRepository, never()).save(any(Book.class));
verify(customerRepository, never()).save(any(Customer.class));
}
}