réparation clone

This commit is contained in:
2026-04-22 13:21:16 +02:00
parent 2c777021b9
commit ed39f635bf
32 changed files with 1753 additions and 1753 deletions
@@ -1,24 +1,24 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book; package fr.iut_fbleau.but3.dev62.mylibrary.book;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
@Builder @Builder
@Getter @Getter
public class BookDTO { public class BookDTO {
private final UUID id; private final UUID id;
private final String isbn; private final String isbn;
private final String title; private final String title;
private final String author; private final String author;
private final String publisher; private final String publisher;
private final LocalDate publicationDate; private final LocalDate publicationDate;
private final BigDecimal price; private final BigDecimal price;
private final int stock; private final int stock;
private final List<String> categories; private final List<String> categories;
private final String description; private final String description;
private final String language; private final String language;
} }
@@ -1,19 +1,19 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book; package fr.iut_fbleau.but3.dev62.mylibrary.book;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
public record BookInfo( public record BookInfo(
String isbn, String isbn,
String title, String title,
String author, String author,
String publisher, String publisher,
LocalDate publicationDate, LocalDate publicationDate,
BigDecimal price, BigDecimal price,
int initialStock, int initialStock,
List<String> categories, List<String> categories,
String description, String description,
String language String language
) { ) {
} }
@@ -1,42 +1,42 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.converter; package fr.iut_fbleau.but3.dev62.mylibrary.book.converter;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO; import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
public final class BookConverter { public final class BookConverter {
private BookConverter() { private BookConverter() {
} }
public static Book toDomain(BookInfo bookInfo) { public static Book toDomain(BookInfo bookInfo) {
return Book.builder() return Book.builder()
.isbn(bookInfo.isbn()) .isbn(bookInfo.isbn())
.title(bookInfo.title()) .title(bookInfo.title())
.author(bookInfo.author()) .author(bookInfo.author())
.publisher(bookInfo.publisher()) .publisher(bookInfo.publisher())
.publicationDate(bookInfo.publicationDate()) .publicationDate(bookInfo.publicationDate())
.price(bookInfo.price()) .price(bookInfo.price())
.stock(bookInfo.initialStock()) .stock(bookInfo.initialStock())
.categories(bookInfo.categories()) .categories(bookInfo.categories())
.description(bookInfo.description()) .description(bookInfo.description())
.language(bookInfo.language()) .language(bookInfo.language())
.build(); .build();
} }
public static BookDTO toDTO(Book book) { public static BookDTO toDTO(Book book) {
return BookDTO.builder() return BookDTO.builder()
.id(book.getId()) .id(book.getId())
.isbn(book.getIsbn()) .isbn(book.getIsbn())
.title(book.getTitle()) .title(book.getTitle())
.author(book.getAuthor()) .author(book.getAuthor())
.publisher(book.getPublisher()) .publisher(book.getPublisher())
.publicationDate(book.getPublicationDate()) .publicationDate(book.getPublicationDate())
.price(book.getPrice()) .price(book.getPrice())
.stock(book.getStock()) .stock(book.getStock())
.categories(book.getCategories()) .categories(book.getCategories())
.description(book.getDescription()) .description(book.getDescription())
.language(book.getLanguage()) .language(book.getLanguage())
.build(); .build();
} }
} }
@@ -1,30 +1,30 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.entity; package fr.iut_fbleau.but3.dev62.mylibrary.book.entity;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
@Builder @Builder
@Getter @Getter
public class Book { public class Book {
private UUID id; private UUID id;
private String isbn; private String isbn;
private String title; private String title;
private String author; private String author;
private String publisher; private String publisher;
private LocalDate publicationDate; private LocalDate publicationDate;
private BigDecimal price; private BigDecimal price;
private int stock; private int stock;
private List<String> categories; private List<String> categories;
private String description; private String description;
private String language; private String language;
public void setRandomUUID() { public void setRandomUUID() {
this.id = UUID.randomUUID(); this.id = UUID.randomUUID();
} }
} }
@@ -1,14 +1,14 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.exception; package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.UUID; import java.util.UUID;
public class BookNotFoundException extends Exception { public class BookNotFoundException extends Exception {
public static final String THE_BOOK_WITH_ID_DOES_NOT_EXIST_MESSAGE = "The book with id {0} does not exist"; public static final String THE_BOOK_WITH_ID_DOES_NOT_EXIST_MESSAGE = "The book with id {0} does not exist";
public BookNotFoundException(UUID uuid) { public BookNotFoundException(UUID uuid) {
super(MessageFormat.format(THE_BOOK_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid)); super(MessageFormat.format(THE_BOOK_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid));
} }
} }
@@ -1,9 +1,9 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.exception; package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
public class NotValidBookException extends Exception { public class NotValidBookException extends Exception {
public NotValidBookException(String message) { public NotValidBookException(String message) {
super(message); super(message);
} }
} }
@@ -1,51 +1,51 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.repository; package fr.iut_fbleau.but3.dev62.mylibrary.book.repository;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
public final class BookRepository { public final class BookRepository {
private final List<Book> books = new ArrayList<>(); private final List<Book> books = new ArrayList<>();
public List<Book> findAll() { public List<Book> findAll() {
return books; return books;
} }
public void deleteAll() { public void deleteAll() {
books.clear(); books.clear();
} }
public Book save(Book newBook) { public Book save(Book newBook) {
Optional<Book> optionalBookWithSameId = this.findById(newBook.getId()); Optional<Book> optionalBookWithSameId = this.findById(newBook.getId());
optionalBookWithSameId.ifPresentOrElse(books::remove, newBook::setRandomUUID); optionalBookWithSameId.ifPresentOrElse(books::remove, newBook::setRandomUUID);
this.books.add(newBook); this.books.add(newBook);
return newBook; return newBook;
} }
public Optional<Book> findById(UUID uuid) { public Optional<Book> findById(UUID uuid) {
return this.books.stream() return this.books.stream()
.filter(book -> book.getId().equals(uuid)) .filter(book -> book.getId().equals(uuid))
.findFirst(); .findFirst();
} }
public boolean existsById(UUID uuid) { public boolean existsById(UUID uuid) {
return this.books.stream() return this.books.stream()
.anyMatch(book -> book.getId().equals(uuid)); .anyMatch(book -> book.getId().equals(uuid));
} }
public Optional<Book> findByIsbn(String isbn) { public Optional<Book> findByIsbn(String isbn) {
return this.books.stream() return this.books.stream()
.filter(book -> book.getIsbn().equals(isbn)) .filter(book -> book.getIsbn().equals(isbn))
.findFirst(); .findFirst();
} }
public void delete(Book book) { public void delete(Book book) {
this.books.remove(book); this.books.remove(book);
} }
} }
@@ -1,67 +1,67 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase; package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO; import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.book.converter.BookConverter; import fr.iut_fbleau.but3.dev62.mylibrary.book.converter.BookConverter;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; 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.exception.BookNotFoundException;
import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException; import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException;
import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.book.validator.BookValidator; import fr.iut_fbleau.but3.dev62.mylibrary.book.validator.BookValidator;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public final class BookUseCase { public final class BookUseCase {
private final BookRepository bookRepository; private final BookRepository bookRepository;
public BookUseCase(BookRepository bookRepository) { public BookUseCase(BookRepository bookRepository) {
this.bookRepository = bookRepository; this.bookRepository = bookRepository;
} }
public String registerBook(BookInfo bookInfo) throws NotValidBookException { public String registerBook(BookInfo bookInfo) throws NotValidBookException {
BookValidator.validate(bookInfo); BookValidator.validate(bookInfo);
Book bookToRegister = BookConverter.toDomain(bookInfo); Book bookToRegister = BookConverter.toDomain(bookInfo);
Book registeredBook = bookRepository.save(bookToRegister); Book registeredBook = bookRepository.save(bookToRegister);
return registeredBook.getIsbn(); return registeredBook.getIsbn();
} }
public Optional<BookDTO> findBookByIsbn(String isbn) { public Optional<BookDTO> findBookByIsbn(String isbn) {
Optional<Book> optionalBook = bookRepository.findByIsbn(isbn); Optional<Book> optionalBook = bookRepository.findByIsbn(isbn);
return optionalBook.map(BookConverter::toDTO); return optionalBook.map(BookConverter::toDTO);
} }
public BookDTO updateBook(UUID uuid, BookInfo bookInfo) throws BookNotFoundException, NotValidBookException { public BookDTO updateBook(UUID uuid, BookInfo bookInfo) throws BookNotFoundException, NotValidBookException {
BookValidator.validate(bookInfo); BookValidator.validate(bookInfo);
Book existingBook = getBookIfNotFoundThrowException(uuid); Book existingBook = getBookIfNotFoundThrowException(uuid);
Book updatedBook = Book.builder() Book updatedBook = Book.builder()
.id(uuid) .id(uuid)
.isbn(bookInfo.isbn()) .isbn(bookInfo.isbn())
.title(bookInfo.title()) .title(bookInfo.title())
.author(bookInfo.author()) .author(bookInfo.author())
.publisher(bookInfo.publisher()) .publisher(bookInfo.publisher())
.publicationDate(bookInfo.publicationDate()) .publicationDate(bookInfo.publicationDate())
.price(bookInfo.price()) .price(bookInfo.price())
.stock(existingBook.getStock()) .stock(existingBook.getStock())
.categories(bookInfo.categories()) .categories(bookInfo.categories())
.description(bookInfo.description()) .description(bookInfo.description())
.language(bookInfo.language()) .language(bookInfo.language())
.build(); .build();
Book saved = bookRepository.save(updatedBook); Book saved = bookRepository.save(updatedBook);
return BookConverter.toDTO(saved); return BookConverter.toDTO(saved);
} }
public void deleteBook(UUID uuid) throws BookNotFoundException { public void deleteBook(UUID uuid) throws BookNotFoundException {
Book bookToDelete = getBookIfNotFoundThrowException(uuid); Book bookToDelete = getBookIfNotFoundThrowException(uuid);
bookRepository.delete(bookToDelete); bookRepository.delete(bookToDelete);
} }
private Book getBookIfNotFoundThrowException(UUID uuid) throws BookNotFoundException { private Book getBookIfNotFoundThrowException(UUID uuid) throws BookNotFoundException {
Optional<Book> optionalBook = bookRepository.findById(uuid); Optional<Book> optionalBook = bookRepository.findById(uuid);
if (optionalBook.isEmpty()) { if (optionalBook.isEmpty()) {
throw new BookNotFoundException(uuid); throw new BookNotFoundException(uuid);
} }
return optionalBook.get(); return optionalBook.get();
} }
} }
@@ -1,59 +1,59 @@
package fr.iut_fbleau.but3.dev62.mylibrary.book.validator; package fr.iut_fbleau.but3.dev62.mylibrary.book.validator;
import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException; import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException;
import java.math.BigDecimal; import java.math.BigDecimal;
public final class BookValidator { public final class BookValidator {
public static final String ISBN_IS_NOT_VALID = "ISBN is not valid"; public static final String ISBN_IS_NOT_VALID = "ISBN is not valid";
public static final String PRICE_MUST_BE_POSITIVE = "Price must be positive"; public static final String PRICE_MUST_BE_POSITIVE = "Price must be positive";
public static final String TITLE_CANNOT_BE_BLANK = "Title cannot be blank"; public static final String TITLE_CANNOT_BE_BLANK = "Title cannot be blank";
public static final String AUTHOR_CANNOT_BE_BLANK = "Author cannot be blank"; public static final String AUTHOR_CANNOT_BE_BLANK = "Author cannot be blank";
public static final String PUBLISHER_CANNOT_BE_BLANK = "Publisher cannot be blank"; public static final String PUBLISHER_CANNOT_BE_BLANK = "Publisher cannot be blank";
public static final String ISBN_REGEX = "\\d{13}"; public static final String ISBN_REGEX = "\\d{13}";
private BookValidator() { private BookValidator() {
} }
public static void validate(BookInfo bookInfo) throws NotValidBookException { public static void validate(BookInfo bookInfo) throws NotValidBookException {
validateIsbn(bookInfo); validateIsbn(bookInfo);
validateTitle(bookInfo); validateTitle(bookInfo);
validateAuthor(bookInfo); validateAuthor(bookInfo);
validatePublisher(bookInfo); validatePublisher(bookInfo);
validatePrice(bookInfo); validatePrice(bookInfo);
} }
private static void validateIsbn(BookInfo bookInfo) throws NotValidBookException { private static void validateIsbn(BookInfo bookInfo) throws NotValidBookException {
if (bookInfo.isbn() == null || bookInfo.isbn().isBlank()) { if (bookInfo.isbn() == null || bookInfo.isbn().isBlank()) {
throw new NotValidBookException(ISBN_IS_NOT_VALID); throw new NotValidBookException(ISBN_IS_NOT_VALID);
} }
if (!bookInfo.isbn().matches(ISBN_REGEX)) { if (!bookInfo.isbn().matches(ISBN_REGEX)) {
throw new NotValidBookException(ISBN_IS_NOT_VALID); throw new NotValidBookException(ISBN_IS_NOT_VALID);
} }
} }
private static void validateTitle(BookInfo bookInfo) throws NotValidBookException { private static void validateTitle(BookInfo bookInfo) throws NotValidBookException {
if (bookInfo.title() == null || bookInfo.title().isBlank()) { if (bookInfo.title() == null || bookInfo.title().isBlank()) {
throw new NotValidBookException(TITLE_CANNOT_BE_BLANK); throw new NotValidBookException(TITLE_CANNOT_BE_BLANK);
} }
} }
private static void validateAuthor(BookInfo bookInfo) throws NotValidBookException { private static void validateAuthor(BookInfo bookInfo) throws NotValidBookException {
if (bookInfo.author() == null || bookInfo.author().isBlank()) { if (bookInfo.author() == null || bookInfo.author().isBlank()) {
throw new NotValidBookException(AUTHOR_CANNOT_BE_BLANK); throw new NotValidBookException(AUTHOR_CANNOT_BE_BLANK);
} }
} }
private static void validatePublisher(BookInfo bookInfo) throws NotValidBookException { private static void validatePublisher(BookInfo bookInfo) throws NotValidBookException {
if (bookInfo.publisher() == null || bookInfo.publisher().isBlank()) { if (bookInfo.publisher() == null || bookInfo.publisher().isBlank()) {
throw new NotValidBookException(PUBLISHER_CANNOT_BE_BLANK); throw new NotValidBookException(PUBLISHER_CANNOT_BE_BLANK);
} }
} }
private static void validatePrice(BookInfo bookInfo) throws NotValidBookException { private static void validatePrice(BookInfo bookInfo) throws NotValidBookException {
if (bookInfo.price() == null || bookInfo.price().compareTo(BigDecimal.ZERO) <= 0) { if (bookInfo.price() == null || bookInfo.price().compareTo(BigDecimal.ZERO) <= 0) {
throw new NotValidBookException(PRICE_MUST_BE_POSITIVE); throw new NotValidBookException(PRICE_MUST_BE_POSITIVE);
} }
} }
} }
@@ -1,5 +1,5 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order; package fr.iut_fbleau.but3.dev62.mylibrary.order;
public record AdresseLivraison(String rue, String ville, String codePostal, String pays) { public record AdresseLivraison(String rue, String ville, String codePostal, String pays) {
} }
@@ -1,7 +1,7 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order; package fr.iut_fbleau.but3.dev62.mylibrary.order;
import java.util.UUID; import java.util.UUID;
public record LigneCommandeInfo(UUID livreId, int quantite) { public record LigneCommandeInfo(UUID livreId, int quantite) {
} }
@@ -1,8 +1,8 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order; package fr.iut_fbleau.but3.dev62.mylibrary.order;
public enum ModePaiement { public enum ModePaiement {
CB, CB,
PAYPAL, PAYPAL,
POINTS_FIDELITE POINTS_FIDELITE
} }
@@ -1,15 +1,15 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order; package fr.iut_fbleau.but3.dev62.mylibrary.order;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
@Builder @Builder
@Getter @Getter
public class OrderDTO { public class OrderDTO {
private final UUID commandeId; private final UUID commandeId;
private final BigDecimal montantTotal; private final BigDecimal montantTotal;
private final int pointsFideliteGagnes; private final int pointsFideliteGagnes;
} }
@@ -1,13 +1,13 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order; package fr.iut_fbleau.but3.dev62.mylibrary.order;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
public record OrderInfo( public record OrderInfo(
UUID clientId, UUID clientId,
List<LigneCommandeInfo> lignesCommande, List<LigneCommandeInfo> lignesCommande,
AdresseLivraison adresseLivraison, AdresseLivraison adresseLivraison,
ModePaiement modePaiement ModePaiement modePaiement
) { ) {
} }
@@ -1,34 +1,34 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.converter; package fr.iut_fbleau.but3.dev62.mylibrary.order.converter;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO; 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.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.LigneCommande; import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.LigneCommande;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order; import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
public final class OrderConverter { public final class OrderConverter {
private OrderConverter() { private OrderConverter() {
} }
public static Order toDomain(OrderInfo orderInfo, List<LigneCommande> lignes, public static Order toDomain(OrderInfo orderInfo, List<LigneCommande> lignes,
BigDecimal montantTotal, int pointsFideliteGagnes) { BigDecimal montantTotal, int pointsFideliteGagnes) {
return Order.builder() return Order.builder()
.clientId(orderInfo.clientId()) .clientId(orderInfo.clientId())
.lignesCommande(lignes) .lignesCommande(lignes)
.adresseLivraison(orderInfo.adresseLivraison()) .adresseLivraison(orderInfo.adresseLivraison())
.modePaiement(orderInfo.modePaiement()) .modePaiement(orderInfo.modePaiement())
.montantTotal(montantTotal) .montantTotal(montantTotal)
.pointsFideliteGagnes(pointsFideliteGagnes) .pointsFideliteGagnes(pointsFideliteGagnes)
.build(); .build();
} }
public static OrderDTO toDTO(Order order) { public static OrderDTO toDTO(Order order) {
return OrderDTO.builder() return OrderDTO.builder()
.commandeId(order.getId()) .commandeId(order.getId())
.montantTotal(order.getMontantTotal()) .montantTotal(order.getMontantTotal())
.pointsFideliteGagnes(order.getPointsFideliteGagnes()) .pointsFideliteGagnes(order.getPointsFideliteGagnes())
.build(); .build();
} }
} }
@@ -1,15 +1,15 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.entity; package fr.iut_fbleau.but3.dev62.mylibrary.order.entity;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
@Builder @Builder
@Getter @Getter
public class LigneCommande { public class LigneCommande {
private UUID livreId; private UUID livreId;
private int quantite; private int quantite;
private BigDecimal prixUnitaire; private BigDecimal prixUnitaire;
} }
@@ -1,26 +1,26 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.entity; package fr.iut_fbleau.but3.dev62.mylibrary.order.entity;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison; import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison;
import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement; import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
@Builder @Builder
@Getter @Getter
public class Order { public class Order {
private UUID id; private UUID id;
private UUID clientId; private UUID clientId;
private List<LigneCommande> lignesCommande; private List<LigneCommande> lignesCommande;
private AdresseLivraison adresseLivraison; private AdresseLivraison adresseLivraison;
private ModePaiement modePaiement; private ModePaiement modePaiement;
private BigDecimal montantTotal; private BigDecimal montantTotal;
private int pointsFideliteGagnes; private int pointsFideliteGagnes;
public void setRandomUUID() { public void setRandomUUID() {
this.id = UUID.randomUUID(); this.id = UUID.randomUUID();
} }
} }
@@ -1,9 +1,9 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception; package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
public class NotValidOrderException extends Exception { public class NotValidOrderException extends Exception {
public NotValidOrderException(String message) { public NotValidOrderException(String message) {
super(message); super(message);
} }
} }
@@ -1,14 +1,14 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception; package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.UUID; import java.util.UUID;
public class OrderNotFoundException extends Exception { public class OrderNotFoundException extends Exception {
public static final String THE_ORDER_WITH_ID_DOES_NOT_EXIST_MESSAGE = "The order with id {0} does not exist"; public static final String THE_ORDER_WITH_ID_DOES_NOT_EXIST_MESSAGE = "The order with id {0} does not exist";
public OrderNotFoundException(UUID uuid) { public OrderNotFoundException(UUID uuid) {
super(MessageFormat.format(THE_ORDER_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid)); super(MessageFormat.format(THE_ORDER_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid));
} }
} }
@@ -1,50 +1,50 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.repository; package fr.iut_fbleau.but3.dev62.mylibrary.order.repository;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order; import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
public final class OrderRepository { public final class OrderRepository {
private final List<Order> orders = new ArrayList<>(); private final List<Order> orders = new ArrayList<>();
public List<Order> findAll() { public List<Order> findAll() {
return orders; return orders;
} }
public void deleteAll() { public void deleteAll() {
orders.clear(); orders.clear();
} }
public Order save(Order newOrder) { public Order save(Order newOrder) {
Optional<Order> existing = this.findById(newOrder.getId()); Optional<Order> existing = this.findById(newOrder.getId());
existing.ifPresentOrElse(orders::remove, newOrder::setRandomUUID); existing.ifPresentOrElse(orders::remove, newOrder::setRandomUUID);
this.orders.add(newOrder); this.orders.add(newOrder);
return newOrder; return newOrder;
} }
public Optional<Order> findById(UUID uuid) { public Optional<Order> findById(UUID uuid) {
return this.orders.stream() return this.orders.stream()
.filter(order -> order.getId().equals(uuid)) .filter(order -> order.getId().equals(uuid))
.findFirst(); .findFirst();
} }
public boolean existsById(UUID uuid) { public boolean existsById(UUID uuid) {
return this.orders.stream() return this.orders.stream()
.anyMatch(order -> order.getId().equals(uuid)); .anyMatch(order -> order.getId().equals(uuid));
} }
public List<Order> findByClientId(UUID clientId) { public List<Order> findByClientId(UUID clientId) {
return this.orders.stream() return this.orders.stream()
.filter(order -> order.getClientId().equals(clientId)) .filter(order -> order.getClientId().equals(clientId))
.toList(); .toList();
} }
public void delete(Order order) { public void delete(Order order) {
this.orders.remove(order); this.orders.remove(order);
} }
} }
@@ -1,79 +1,79 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.usecase; 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.entity.Book;
import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; 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.entity.Customer;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException; 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.customer.repository.CustomerRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo; import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement; import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO; 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.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.converter.OrderConverter; import fr.iut_fbleau.but3.dev62.mylibrary.order.converter.OrderConverter;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.LigneCommande; import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.LigneCommande;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order; import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException; import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository; import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.order.validator.OrderValidator; import fr.iut_fbleau.but3.dev62.mylibrary.order.validator.OrderValidator;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public final class OrderUseCase { public final class OrderUseCase {
private final OrderRepository orderRepository; private final OrderRepository orderRepository;
private final CustomerRepository customerRepository; private final CustomerRepository customerRepository;
private final BookRepository bookRepository; private final BookRepository bookRepository;
public OrderUseCase(OrderRepository orderRepository, CustomerRepository customerRepository, public OrderUseCase(OrderRepository orderRepository, CustomerRepository customerRepository,
BookRepository bookRepository) { BookRepository bookRepository) {
this.orderRepository = orderRepository; this.orderRepository = orderRepository;
this.customerRepository = customerRepository; this.customerRepository = customerRepository;
this.bookRepository = bookRepository; this.bookRepository = bookRepository;
} }
public OrderDTO passerCommande(OrderInfo orderInfo) public OrderDTO passerCommande(OrderInfo orderInfo)
throws NotValidOrderException, CustomerNotFoundException { throws NotValidOrderException, CustomerNotFoundException {
OrderValidator.validate(orderInfo); OrderValidator.validate(orderInfo);
Customer customer = customerRepository.findById(orderInfo.clientId()) Customer customer = customerRepository.findById(orderInfo.clientId())
.orElseThrow(() -> new CustomerNotFoundException(orderInfo.clientId())); .orElseThrow(() -> new CustomerNotFoundException(orderInfo.clientId()));
List<LigneCommande> lignes = new ArrayList<>(); List<LigneCommande> lignes = new ArrayList<>();
BigDecimal montantTotal = BigDecimal.ZERO; BigDecimal montantTotal = BigDecimal.ZERO;
for (LigneCommandeInfo ligneInfo : orderInfo.lignesCommande()) { for (LigneCommandeInfo ligneInfo : orderInfo.lignesCommande()) {
Book book = bookRepository.findById(ligneInfo.livreId()) Book book = bookRepository.findById(ligneInfo.livreId())
.orElseThrow(() -> new NotValidOrderException("Book not found: " + ligneInfo.livreId())); .orElseThrow(() -> new NotValidOrderException("Book not found: " + ligneInfo.livreId()));
BigDecimal prixLigne = book.getPrice().multiply(BigDecimal.valueOf(ligneInfo.quantite())); BigDecimal prixLigne = book.getPrice().multiply(BigDecimal.valueOf(ligneInfo.quantite()));
montantTotal = montantTotal.add(prixLigne); montantTotal = montantTotal.add(prixLigne);
lignes.add(LigneCommande.builder() lignes.add(LigneCommande.builder()
.livreId(ligneInfo.livreId()) .livreId(ligneInfo.livreId())
.quantite(ligneInfo.quantite()) .quantite(ligneInfo.quantite())
.prixUnitaire(book.getPrice()) .prixUnitaire(book.getPrice())
.build()); .build());
} }
int pointsGagnes = montantTotal.intValue(); int pointsGagnes = montantTotal.intValue();
if (orderInfo.modePaiement() == ModePaiement.POINTS_FIDELITE) { if (orderInfo.modePaiement() == ModePaiement.POINTS_FIDELITE) {
customer.addLoyaltyPoints(-montantTotal.intValue()); customer.addLoyaltyPoints(-montantTotal.intValue());
} else { } else {
customer.addLoyaltyPoints(pointsGagnes); customer.addLoyaltyPoints(pointsGagnes);
} }
customerRepository.save(customer); customerRepository.save(customer);
Order order = OrderConverter.toDomain(orderInfo, lignes, montantTotal, pointsGagnes); Order order = OrderConverter.toDomain(orderInfo, lignes, montantTotal, pointsGagnes);
Order savedOrder = orderRepository.save(order); Order savedOrder = orderRepository.save(order);
return OrderConverter.toDTO(savedOrder); return OrderConverter.toDTO(savedOrder);
} }
public Optional<OrderDTO> findOrderById(UUID uuid) { public Optional<OrderDTO> findOrderById(UUID uuid) {
return orderRepository.findById(uuid).map(OrderConverter::toDTO); return orderRepository.findById(uuid).map(OrderConverter::toDTO);
} }
} }
@@ -1,53 +1,53 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.validator; package fr.iut_fbleau.but3.dev62.mylibrary.order.validator;
import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo; import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo; import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException; import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
public final class OrderValidator { public final class OrderValidator {
public static final String CLIENT_ID_CANNOT_BE_NULL = "Client id cannot be null"; public static final String CLIENT_ID_CANNOT_BE_NULL = "Client id cannot be null";
public static final String LIGNES_COMMANDE_CANNOT_BE_EMPTY = "Order must have at least one item"; public static final String LIGNES_COMMANDE_CANNOT_BE_EMPTY = "Order must have at least one item";
public static final String QUANTITE_MUST_BE_POSITIVE = "Quantity must be positive"; public static final String QUANTITE_MUST_BE_POSITIVE = "Quantity must be positive";
public static final String MODE_PAIEMENT_CANNOT_BE_NULL = "Payment method cannot be null"; public static final String MODE_PAIEMENT_CANNOT_BE_NULL = "Payment method cannot be null";
public static final String ADRESSE_LIVRAISON_CANNOT_BE_NULL = "Delivery address cannot be null"; public static final String ADRESSE_LIVRAISON_CANNOT_BE_NULL = "Delivery address cannot be null";
private OrderValidator() { private OrderValidator() {
} }
public static void validate(OrderInfo orderInfo) throws NotValidOrderException { public static void validate(OrderInfo orderInfo) throws NotValidOrderException {
validateClientId(orderInfo); validateClientId(orderInfo);
validateLignesCommande(orderInfo); validateLignesCommande(orderInfo);
validateAdresseLivraison(orderInfo); validateAdresseLivraison(orderInfo);
validateModePaiement(orderInfo); validateModePaiement(orderInfo);
} }
private static void validateClientId(OrderInfo orderInfo) throws NotValidOrderException { private static void validateClientId(OrderInfo orderInfo) throws NotValidOrderException {
if (orderInfo.clientId() == null) { if (orderInfo.clientId() == null) {
throw new NotValidOrderException(CLIENT_ID_CANNOT_BE_NULL); throw new NotValidOrderException(CLIENT_ID_CANNOT_BE_NULL);
} }
} }
private static void validateLignesCommande(OrderInfo orderInfo) throws NotValidOrderException { private static void validateLignesCommande(OrderInfo orderInfo) throws NotValidOrderException {
if (orderInfo.lignesCommande() == null || orderInfo.lignesCommande().isEmpty()) { if (orderInfo.lignesCommande() == null || orderInfo.lignesCommande().isEmpty()) {
throw new NotValidOrderException(LIGNES_COMMANDE_CANNOT_BE_EMPTY); throw new NotValidOrderException(LIGNES_COMMANDE_CANNOT_BE_EMPTY);
} }
for (LigneCommandeInfo ligne : orderInfo.lignesCommande()) { for (LigneCommandeInfo ligne : orderInfo.lignesCommande()) {
if (ligne.quantite() <= 0) { if (ligne.quantite() <= 0) {
throw new NotValidOrderException(QUANTITE_MUST_BE_POSITIVE); throw new NotValidOrderException(QUANTITE_MUST_BE_POSITIVE);
} }
} }
} }
private static void validateAdresseLivraison(OrderInfo orderInfo) throws NotValidOrderException { private static void validateAdresseLivraison(OrderInfo orderInfo) throws NotValidOrderException {
if (orderInfo.adresseLivraison() == null) { if (orderInfo.adresseLivraison() == null) {
throw new NotValidOrderException(ADRESSE_LIVRAISON_CANNOT_BE_NULL); throw new NotValidOrderException(ADRESSE_LIVRAISON_CANNOT_BE_NULL);
} }
} }
private static void validateModePaiement(OrderInfo orderInfo) throws NotValidOrderException { private static void validateModePaiement(OrderInfo orderInfo) throws NotValidOrderException {
if (orderInfo.modePaiement() == null) { if (orderInfo.modePaiement() == null) {
throw new NotValidOrderException(MODE_PAIEMENT_CANNOT_BE_NULL); throw new NotValidOrderException(MODE_PAIEMENT_CANNOT_BE_NULL);
} }
} }
} }
@@ -1,223 +1,223 @@
package fr.iut_fbleau.but3.dev62.mylibrary.features.order; package fr.iut_fbleau.but3.dev62.mylibrary.features.order;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; 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.book.repository.BookRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer; 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.exception.CustomerNotFoundException;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository; import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison; import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison;
import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo; import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement; import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO; 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.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException; import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository; import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.order.usecase.OrderUseCase; import fr.iut_fbleau.but3.dev62.mylibrary.order.usecase.OrderUseCase;
import io.cucumber.datatable.DataTable; import io.cucumber.datatable.DataTable;
import io.cucumber.java.Before; import io.cucumber.java.Before;
import io.cucumber.java.en.And; import io.cucumber.java.en.And;
import io.cucumber.java.en.Given; import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then; import io.cucumber.java.en.Then;
import io.cucumber.java.en.When; import io.cucumber.java.en.When;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
public class OrderSteps { public class OrderSteps {
private final CustomerRepository customerRepository = new CustomerRepository(); private final CustomerRepository customerRepository = new CustomerRepository();
private final BookRepository bookRepository = new BookRepository(); private final BookRepository bookRepository = new BookRepository();
private final OrderRepository orderRepository = new OrderRepository(); private final OrderRepository orderRepository = new OrderRepository();
private final OrderUseCase orderUseCase = new OrderUseCase(orderRepository, customerRepository, bookRepository); private final OrderUseCase orderUseCase = new OrderUseCase(orderRepository, customerRepository, bookRepository);
private final Map<String, UUID> customerPhoneUUID = new HashMap<>(); private final Map<String, UUID> customerPhoneUUID = new HashMap<>();
private final Map<String, UUID> bookIsbnUUID = new HashMap<>(); private final Map<String, UUID> bookIsbnUUID = new HashMap<>();
private OrderDTO orderResult; private OrderDTO orderResult;
private NotValidOrderException notValidOrderException; private NotValidOrderException notValidOrderException;
private boolean customerNotFoundThrown = false; private boolean customerNotFoundThrown = false;
@Before @Before
public void setUp() { public void setUp() {
customerRepository.deleteAll(); customerRepository.deleteAll();
bookRepository.deleteAll(); bookRepository.deleteAll();
orderRepository.deleteAll(); orderRepository.deleteAll();
customerPhoneUUID.clear(); customerPhoneUUID.clear();
bookIsbnUUID.clear(); bookIsbnUUID.clear();
orderResult = null; orderResult = null;
notValidOrderException = null; notValidOrderException = null;
customerNotFoundThrown = false; customerNotFoundThrown = false;
} }
@Given("the system has the following customers for order:") @Given("the system has the following customers for order:")
public void theSystemHasTheFollowingCustomersForOrder(DataTable dataTable) { public void theSystemHasTheFollowingCustomersForOrder(DataTable dataTable) {
List<Map<String, String>> customers = dataTable.asMaps(String.class, String.class); List<Map<String, String>> customers = dataTable.asMaps(String.class, String.class);
for (Map<String, String> customer : customers) { for (Map<String, String> customer : customers) {
String phone = customer.get("numeroTelephone"); String phone = customer.get("numeroTelephone");
Customer newCustomer = Customer.builder() Customer newCustomer = Customer.builder()
.firstName(customer.get("prenom")) .firstName(customer.get("prenom"))
.lastName(customer.get("nom")) .lastName(customer.get("nom"))
.phoneNumber(phone) .phoneNumber(phone)
.loyaltyPoints(Integer.parseInt(customer.get("pointsFidelite"))) .loyaltyPoints(Integer.parseInt(customer.get("pointsFidelite")))
.build(); .build();
Customer saved = customerRepository.save(newCustomer); Customer saved = customerRepository.save(newCustomer);
customerPhoneUUID.put(phone, saved.getId()); customerPhoneUUID.put(phone, saved.getId());
} }
assertEquals(customers.size(), customerRepository.findAll().size()); assertEquals(customers.size(), customerRepository.findAll().size());
} }
@And("the catalog has the following books for order:") @And("the catalog has the following books for order:")
public void theCatalogHasTheFollowingBooksForOrder(DataTable dataTable) { public void theCatalogHasTheFollowingBooksForOrder(DataTable dataTable) {
List<Map<String, String>> books = dataTable.asMaps(String.class, String.class); List<Map<String, String>> books = dataTable.asMaps(String.class, String.class);
for (Map<String, String> book : books) { for (Map<String, String> book : books) {
String isbn = book.get("isbn"); String isbn = book.get("isbn");
Book newBook = Book.builder() Book newBook = Book.builder()
.isbn(isbn) .isbn(isbn)
.title(book.get("titre")) .title(book.get("titre"))
.author(book.get("auteur")) .author(book.get("auteur"))
.publisher(book.get("editeur")) .publisher(book.get("editeur"))
.publicationDate(LocalDate.parse(book.get("datePublication"))) .publicationDate(LocalDate.parse(book.get("datePublication")))
.price(new BigDecimal(book.get("prix"))) .price(new BigDecimal(book.get("prix")))
.stock(Integer.parseInt(book.get("stockInitial"))) .stock(Integer.parseInt(book.get("stockInitial")))
.categories(List.of(book.get("categories").split(";"))) .categories(List.of(book.get("categories").split(";")))
.description(book.get("description")) .description(book.get("description"))
.language(book.get("langue")) .language(book.get("langue"))
.build(); .build();
Book saved = bookRepository.save(newBook); Book saved = bookRepository.save(newBook);
bookIsbnUUID.put(isbn, saved.getId()); bookIsbnUUID.put(isbn, saved.getId());
} }
assertEquals(books.size(), bookRepository.findAll().size()); assertEquals(books.size(), bookRepository.findAll().size());
} }
@When("I place an order for customer {string} with:") @When("I place an order for customer {string} with:")
public void iPlaceAnOrderForCustomerWith(String phoneNumber, DataTable dataTable) public void iPlaceAnOrderForCustomerWith(String phoneNumber, DataTable dataTable)
throws NotValidOrderException, CustomerNotFoundException { throws NotValidOrderException, CustomerNotFoundException {
Map<String, String> row = dataTable.asMaps(String.class, String.class).getFirst(); Map<String, String> row = dataTable.asMaps(String.class, String.class).getFirst();
UUID customerId = customerPhoneUUID.get(phoneNumber); UUID customerId = customerPhoneUUID.get(phoneNumber);
UUID livreId = bookIsbnUUID.get(row.get("livreIsbn")); UUID livreId = bookIsbnUUID.get(row.get("livreIsbn"));
AdresseLivraison adresse = new AdresseLivraison( AdresseLivraison adresse = new AdresseLivraison(
row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays") row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays")
); );
OrderInfo orderInfo = new OrderInfo( OrderInfo orderInfo = new OrderInfo(
customerId, customerId,
List.of(new LigneCommandeInfo(livreId, Integer.parseInt(row.get("quantite")))), List.of(new LigneCommandeInfo(livreId, Integer.parseInt(row.get("quantite")))),
adresse, adresse,
ModePaiement.valueOf(row.get("modePaiement")) ModePaiement.valueOf(row.get("modePaiement"))
); );
orderResult = orderUseCase.passerCommande(orderInfo); orderResult = orderUseCase.passerCommande(orderInfo);
} }
@Then("a new order is created") @Then("a new order is created")
public void aNewOrderIsCreated() { public void aNewOrderIsCreated() {
assertNotNull(orderResult); assertNotNull(orderResult);
assertNotNull(orderResult.getCommandeId()); assertNotNull(orderResult.getCommandeId());
} }
@And("the order total is {double}") @And("the order total is {double}")
public void theOrderTotalIs(double expectedTotal) { public void theOrderTotalIs(double expectedTotal) {
assertEquals(0, new BigDecimal(String.valueOf(expectedTotal)).compareTo(orderResult.getMontantTotal())); assertEquals(0, new BigDecimal(String.valueOf(expectedTotal)).compareTo(orderResult.getMontantTotal()));
} }
@And("the customer {string} now has {int} loyalty points") @And("the customer {string} now has {int} loyalty points")
public void theCustomerNowHasLoyaltyPoints(String phoneNumber, int expectedPoints) { public void theCustomerNowHasLoyaltyPoints(String phoneNumber, int expectedPoints) {
UUID customerId = customerPhoneUUID.get(phoneNumber); UUID customerId = customerPhoneUUID.get(phoneNumber);
Customer customer = customerRepository.findById(customerId).orElseThrow(); Customer customer = customerRepository.findById(customerId).orElseThrow();
assertEquals(expectedPoints, customer.getLoyaltyPoints()); assertEquals(expectedPoints, customer.getLoyaltyPoints());
} }
@When("I try to place an order for customer {string} with no items:") @When("I try to place an order for customer {string} with no items:")
public void iTryToPlaceAnOrderForCustomerWithNoItems(String phoneNumber, DataTable dataTable) { public void iTryToPlaceAnOrderForCustomerWithNoItems(String phoneNumber, DataTable dataTable) {
Map<String, String> row = dataTable.asMaps(String.class, String.class).getFirst(); Map<String, String> row = dataTable.asMaps(String.class, String.class).getFirst();
UUID customerId = customerPhoneUUID.get(phoneNumber); UUID customerId = customerPhoneUUID.get(phoneNumber);
AdresseLivraison adresse = new AdresseLivraison( AdresseLivraison adresse = new AdresseLivraison(
row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays") row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays")
); );
OrderInfo orderInfo = new OrderInfo( OrderInfo orderInfo = new OrderInfo(
customerId, List.of(), adresse, ModePaiement.valueOf(row.get("modePaiement")) customerId, List.of(), adresse, ModePaiement.valueOf(row.get("modePaiement"))
); );
notValidOrderException = assertThrows(NotValidOrderException.class, notValidOrderException = assertThrows(NotValidOrderException.class,
() -> orderUseCase.passerCommande(orderInfo)); () -> orderUseCase.passerCommande(orderInfo));
} }
@When("I try to place an order for customer {string} with invalid quantity:") @When("I try to place an order for customer {string} with invalid quantity:")
public void iTryToPlaceAnOrderForCustomerWithInvalidQuantity(String phoneNumber, DataTable dataTable) { public void iTryToPlaceAnOrderForCustomerWithInvalidQuantity(String phoneNumber, DataTable dataTable) {
Map<String, String> row = dataTable.asMaps(String.class, String.class).getFirst(); Map<String, String> row = dataTable.asMaps(String.class, String.class).getFirst();
UUID customerId = customerPhoneUUID.get(phoneNumber); UUID customerId = customerPhoneUUID.get(phoneNumber);
UUID livreId = bookIsbnUUID.get(row.get("livreIsbn")); UUID livreId = bookIsbnUUID.get(row.get("livreIsbn"));
AdresseLivraison adresse = new AdresseLivraison( AdresseLivraison adresse = new AdresseLivraison(
row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays") row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays")
); );
OrderInfo orderInfo = new OrderInfo( OrderInfo orderInfo = new OrderInfo(
customerId, customerId,
List.of(new LigneCommandeInfo(livreId, Integer.parseInt(row.get("quantite")))), List.of(new LigneCommandeInfo(livreId, Integer.parseInt(row.get("quantite")))),
adresse, adresse,
ModePaiement.valueOf(row.get("modePaiement")) ModePaiement.valueOf(row.get("modePaiement"))
); );
notValidOrderException = assertThrows(NotValidOrderException.class, notValidOrderException = assertThrows(NotValidOrderException.class,
() -> orderUseCase.passerCommande(orderInfo)); () -> orderUseCase.passerCommande(orderInfo));
} }
@When("I try to place an order for an unknown customer with:") @When("I try to place an order for an unknown customer with:")
public void iTryToPlaceAnOrderForAnUnknownCustomerWith(DataTable dataTable) { public void iTryToPlaceAnOrderForAnUnknownCustomerWith(DataTable dataTable) {
Map<String, String> row = dataTable.asMaps(String.class, String.class).getFirst(); Map<String, String> row = dataTable.asMaps(String.class, String.class).getFirst();
UUID unknownId = UUID.randomUUID(); UUID unknownId = UUID.randomUUID();
UUID livreId = bookIsbnUUID.get(row.get("livreIsbn")); UUID livreId = bookIsbnUUID.get(row.get("livreIsbn"));
AdresseLivraison adresse = new AdresseLivraison( AdresseLivraison adresse = new AdresseLivraison(
row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays") row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays")
); );
OrderInfo orderInfo = new OrderInfo( OrderInfo orderInfo = new OrderInfo(
unknownId, unknownId,
List.of(new LigneCommandeInfo(livreId, Integer.parseInt(row.get("quantite")))), List.of(new LigneCommandeInfo(livreId, Integer.parseInt(row.get("quantite")))),
adresse, adresse,
ModePaiement.valueOf(row.get("modePaiement")) ModePaiement.valueOf(row.get("modePaiement"))
); );
try { try {
orderUseCase.passerCommande(orderInfo); orderUseCase.passerCommande(orderInfo);
} catch (CustomerNotFoundException e) { } catch (CustomerNotFoundException e) {
customerNotFoundThrown = true; customerNotFoundThrown = true;
} catch (NotValidOrderException e) { } catch (NotValidOrderException e) {
notValidOrderException = e; notValidOrderException = e;
} }
} }
@Then("the order placement fails") @Then("the order placement fails")
public void theOrderPlacementFails() { public void theOrderPlacementFails() {
assertNotNull(notValidOrderException); assertNotNull(notValidOrderException);
} }
@Then("the order placement fails with customer not found") @Then("the order placement fails with customer not found")
public void theOrderPlacementFailsWithCustomerNotFound() { public void theOrderPlacementFailsWithCustomerNotFound() {
assertTrue(customerNotFoundThrown); assertTrue(customerNotFoundThrown);
} }
@And("I receive a validation order error containing {string}") @And("I receive a validation order error containing {string}")
public void iReceiveAValidationOrderErrorContaining(String errorMessage) { public void iReceiveAValidationOrderErrorContaining(String errorMessage) {
assertEquals(errorMessage, notValidOrderException.getMessage()); assertEquals(errorMessage, notValidOrderException.getMessage());
} }
} }
@@ -1,94 +1,94 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.converter; package fr.iut_fbleau.but3.dev62.mylibrary.order.converter;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison; import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison;
import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo; import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement; import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO; 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.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.LigneCommande; import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.LigneCommande;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order; import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@DisplayName("OrderConverter Unit Tests") @DisplayName("OrderConverter Unit Tests")
class OrderConverterTest { class OrderConverterTest {
private final UUID clientId = UUID.randomUUID(); private final UUID clientId = UUID.randomUUID();
private final UUID livreId = UUID.randomUUID(); private final UUID livreId = UUID.randomUUID();
private final AdresseLivraison adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France"); private final AdresseLivraison adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France");
@Nested @Nested
@DisplayName("toDomain() method tests") @DisplayName("toDomain() method tests")
class ToDomainTests { class ToDomainTests {
@Test @Test
@DisplayName("Should convert OrderInfo to Order domain object") @DisplayName("Should convert OrderInfo to Order domain object")
void shouldConvertOrderInfoToDomain() { void shouldConvertOrderInfoToDomain() {
OrderInfo orderInfo = new OrderInfo( OrderInfo orderInfo = new OrderInfo(
clientId, clientId,
List.of(new LigneCommandeInfo(livreId, 2)), List.of(new LigneCommandeInfo(livreId, 2)),
adresse, adresse,
ModePaiement.CB ModePaiement.CB
); );
List<LigneCommande> lignes = List.of( List<LigneCommande> lignes = List.of(
LigneCommande.builder() LigneCommande.builder()
.livreId(livreId) .livreId(livreId)
.quantite(2) .quantite(2)
.prixUnitaire(new BigDecimal("12.90")) .prixUnitaire(new BigDecimal("12.90"))
.build() .build()
); );
Order result = OrderConverter.toDomain(orderInfo, lignes, new BigDecimal("25.80"), 25); Order result = OrderConverter.toDomain(orderInfo, lignes, new BigDecimal("25.80"), 25);
assertNotNull(result); assertNotNull(result);
assertEquals(clientId, result.getClientId()); assertEquals(clientId, result.getClientId());
assertEquals(adresse, result.getAdresseLivraison()); assertEquals(adresse, result.getAdresseLivraison());
assertEquals(ModePaiement.CB, result.getModePaiement()); assertEquals(ModePaiement.CB, result.getModePaiement());
assertEquals(new BigDecimal("25.80"), result.getMontantTotal()); assertEquals(new BigDecimal("25.80"), result.getMontantTotal());
assertEquals(25, result.getPointsFideliteGagnes()); assertEquals(25, result.getPointsFideliteGagnes());
assertEquals(1, result.getLignesCommande().size()); assertEquals(1, result.getLignesCommande().size());
} }
@Test @Test
@DisplayName("Should have null ID after toDomain (set by repository)") @DisplayName("Should have null ID after toDomain (set by repository)")
void shouldHaveNullIdAfterToDomain() { void shouldHaveNullIdAfterToDomain() {
OrderInfo orderInfo = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), adresse, ModePaiement.CB); OrderInfo orderInfo = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), adresse, ModePaiement.CB);
Order result = OrderConverter.toDomain(orderInfo, List.of(), BigDecimal.ZERO, 0); Order result = OrderConverter.toDomain(orderInfo, List.of(), BigDecimal.ZERO, 0);
assertNull(result.getId()); assertNull(result.getId());
} }
} }
@Nested @Nested
@DisplayName("toDTO() method tests") @DisplayName("toDTO() method tests")
class ToDTOTests { class ToDTOTests {
@Test @Test
@DisplayName("Should convert Order domain object to OrderDTO with all fields mapped correctly") @DisplayName("Should convert Order domain object to OrderDTO with all fields mapped correctly")
void shouldConvertOrderToDTO() { void shouldConvertOrderToDTO() {
UUID orderId = UUID.randomUUID(); UUID orderId = UUID.randomUUID();
Order order = Order.builder() Order order = Order.builder()
.id(orderId) .id(orderId)
.clientId(clientId) .clientId(clientId)
.montantTotal(new BigDecimal("25.80")) .montantTotal(new BigDecimal("25.80"))
.pointsFideliteGagnes(25) .pointsFideliteGagnes(25)
.build(); .build();
OrderDTO result = OrderConverter.toDTO(order); OrderDTO result = OrderConverter.toDTO(order);
assertNotNull(result); assertNotNull(result);
assertEquals(orderId, result.getCommandeId()); assertEquals(orderId, result.getCommandeId());
assertEquals(new BigDecimal("25.80"), result.getMontantTotal()); assertEquals(new BigDecimal("25.80"), result.getMontantTotal());
assertEquals(25, result.getPointsFideliteGagnes()); assertEquals(25, result.getPointsFideliteGagnes());
} }
} }
} }
@@ -1,81 +1,81 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.entity; package fr.iut_fbleau.but3.dev62.mylibrary.order.entity;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison; import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison;
import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement; import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
class OrderTest { class OrderTest {
@Test @Test
@DisplayName("Builder should create a valid Order instance") @DisplayName("Builder should create a valid Order instance")
void testOrderBuilder() { void testOrderBuilder() {
UUID id = UUID.randomUUID(); UUID id = UUID.randomUUID();
UUID clientId = UUID.randomUUID(); UUID clientId = UUID.randomUUID();
AdresseLivraison adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France"); AdresseLivraison adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France");
Order order = Order.builder() Order order = Order.builder()
.id(id) .id(id)
.clientId(clientId) .clientId(clientId)
.adresseLivraison(adresse) .adresseLivraison(adresse)
.modePaiement(ModePaiement.CB) .modePaiement(ModePaiement.CB)
.montantTotal(new BigDecimal("25.80")) .montantTotal(new BigDecimal("25.80"))
.pointsFideliteGagnes(25) .pointsFideliteGagnes(25)
.lignesCommande(List.of()) .lignesCommande(List.of())
.build(); .build();
assertEquals(id, order.getId()); assertEquals(id, order.getId());
assertEquals(clientId, order.getClientId()); assertEquals(clientId, order.getClientId());
assertEquals(adresse, order.getAdresseLivraison()); assertEquals(adresse, order.getAdresseLivraison());
assertEquals(ModePaiement.CB, order.getModePaiement()); assertEquals(ModePaiement.CB, order.getModePaiement());
assertEquals(new BigDecimal("25.80"), order.getMontantTotal()); assertEquals(new BigDecimal("25.80"), order.getMontantTotal());
assertEquals(25, order.getPointsFideliteGagnes()); assertEquals(25, order.getPointsFideliteGagnes());
} }
@Test @Test
@DisplayName("setRandomUUID should set a new non-null UUID") @DisplayName("setRandomUUID should set a new non-null UUID")
void testSetRandomUUID() { void testSetRandomUUID() {
Order order = Order.builder().build(); Order order = Order.builder().build();
UUID originalId = order.getId(); UUID originalId = order.getId();
order.setRandomUUID(); order.setRandomUUID();
assertNotNull(order.getId()); assertNotNull(order.getId());
assertNotEquals(originalId, order.getId()); assertNotEquals(originalId, order.getId());
} }
@Test @Test
@DisplayName("Two setRandomUUID calls should produce different UUIDs") @DisplayName("Two setRandomUUID calls should produce different UUIDs")
void testSetRandomUUIDTwice() { void testSetRandomUUIDTwice() {
Order order = Order.builder().build(); Order order = Order.builder().build();
order.setRandomUUID(); order.setRandomUUID();
UUID firstId = order.getId(); UUID firstId = order.getId();
order.setRandomUUID(); order.setRandomUUID();
UUID secondId = order.getId(); UUID secondId = order.getId();
assertNotEquals(firstId, secondId); assertNotEquals(firstId, secondId);
} }
@Test @Test
@DisplayName("Builder should create a valid LigneCommande instance") @DisplayName("Builder should create a valid LigneCommande instance")
void testLigneCommandeBuilder() { void testLigneCommandeBuilder() {
UUID livreId = UUID.randomUUID(); UUID livreId = UUID.randomUUID();
LigneCommande ligne = LigneCommande.builder() LigneCommande ligne = LigneCommande.builder()
.livreId(livreId) .livreId(livreId)
.quantite(3) .quantite(3)
.prixUnitaire(new BigDecimal("12.90")) .prixUnitaire(new BigDecimal("12.90"))
.build(); .build();
assertEquals(livreId, ligne.getLivreId()); assertEquals(livreId, ligne.getLivreId());
assertEquals(3, ligne.getQuantite()); assertEquals(3, ligne.getQuantite());
assertEquals(new BigDecimal("12.90"), ligne.getPrixUnitaire()); assertEquals(new BigDecimal("12.90"), ligne.getPrixUnitaire());
} }
} }
@@ -1,61 +1,61 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception; package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource; import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
class NotValidOrderExceptionTest { class NotValidOrderExceptionTest {
@Test @Test
@DisplayName("Exception should be created with the provided message") @DisplayName("Exception should be created with the provided message")
void testExceptionCreation() { void testExceptionCreation() {
String errorMessage = "Order data is not valid"; String errorMessage = "Order data is not valid";
NotValidOrderException exception = new NotValidOrderException(errorMessage); NotValidOrderException exception = new NotValidOrderException(errorMessage);
assertEquals(errorMessage, exception.getMessage()); assertEquals(errorMessage, exception.getMessage());
} }
@ParameterizedTest @ParameterizedTest
@ValueSource(strings = { @ValueSource(strings = {
"Client id cannot be null", "Client id cannot be null",
"Order must have at least one item", "Order must have at least one item",
"Quantity must be positive", "Quantity must be positive",
"Payment method cannot be null", "Payment method cannot be null",
"Delivery address cannot be null" "Delivery address cannot be null"
}) })
@DisplayName("Exception should handle different validation messages") @DisplayName("Exception should handle different validation messages")
void testExceptionWithDifferentMessages(String errorMessage) { void testExceptionWithDifferentMessages(String errorMessage) {
NotValidOrderException exception = new NotValidOrderException(errorMessage); NotValidOrderException exception = new NotValidOrderException(errorMessage);
assertEquals(errorMessage, exception.getMessage()); assertEquals(errorMessage, exception.getMessage());
} }
@Test @Test
@DisplayName("Exception should be properly thrown and caught") @DisplayName("Exception should be properly thrown and caught")
void testExceptionCanBeThrownAndCaught() { void testExceptionCanBeThrownAndCaught() {
String errorMessage = "Order must have at least one item"; String errorMessage = "Order must have at least one item";
Exception exception = assertThrows(NotValidOrderException.class, () -> { Exception exception = assertThrows(NotValidOrderException.class, () -> {
throw new NotValidOrderException(errorMessage); throw new NotValidOrderException(errorMessage);
}); });
assertEquals(errorMessage, exception.getMessage()); assertEquals(errorMessage, exception.getMessage());
} }
@Test @Test
@DisplayName("Exception should be catchable as a general Exception") @DisplayName("Exception should be catchable as a general Exception")
void testExceptionInheritance() { void testExceptionInheritance() {
String errorMessage = "Quantity must be positive"; String errorMessage = "Quantity must be positive";
try { try {
throw new NotValidOrderException(errorMessage); throw new NotValidOrderException(errorMessage);
} catch (Exception e) { } catch (Exception e) {
assertEquals(NotValidOrderException.class, e.getClass()); assertEquals(NotValidOrderException.class, e.getClass());
assertEquals(errorMessage, e.getMessage()); assertEquals(errorMessage, e.getMessage());
} }
} }
} }
@@ -1,47 +1,47 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception; package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.UUID; import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
class OrderNotFoundExceptionTest { class OrderNotFoundExceptionTest {
@Test @Test
@DisplayName("Exception message should contain the UUID provided") @DisplayName("Exception message should contain the UUID provided")
void testExceptionMessageContainsUUID() { void testExceptionMessageContainsUUID() {
UUID uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
OrderNotFoundException exception = new OrderNotFoundException(uuid); OrderNotFoundException exception = new OrderNotFoundException(uuid);
String expectedMessage = String.format("The order with id %s does not exist", uuid); String expectedMessage = String.format("The order with id %s does not exist", uuid);
assertEquals(expectedMessage, exception.getMessage()); assertEquals(expectedMessage, exception.getMessage());
} }
@Test @Test
@DisplayName("Exception should use the correct constant message format") @DisplayName("Exception should use the correct constant message format")
void testExceptionUsesConstantMessageFormat() { void testExceptionUsesConstantMessageFormat() {
UUID uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
OrderNotFoundException exception = new OrderNotFoundException(uuid); OrderNotFoundException exception = new OrderNotFoundException(uuid);
assertEquals("The order with id {0} does not exist", assertEquals("The order with id {0} does not exist",
OrderNotFoundException.THE_ORDER_WITH_ID_DOES_NOT_EXIST_MESSAGE); OrderNotFoundException.THE_ORDER_WITH_ID_DOES_NOT_EXIST_MESSAGE);
assertTrue(exception.getMessage().contains(uuid.toString())); assertTrue(exception.getMessage().contains(uuid.toString()));
} }
@Test @Test
@DisplayName("Exception should be properly thrown and caught") @DisplayName("Exception should be properly thrown and caught")
void testExceptionCanBeThrownAndCaught() { void testExceptionCanBeThrownAndCaught() {
UUID uuid = UUID.randomUUID(); UUID uuid = UUID.randomUUID();
try { try {
throw new OrderNotFoundException(uuid); throw new OrderNotFoundException(uuid);
} catch (OrderNotFoundException e) { } catch (OrderNotFoundException e) {
String expectedMessage = String.format("The order with id %s does not exist", uuid); String expectedMessage = String.format("The order with id %s does not exist", uuid);
assertEquals(expectedMessage, e.getMessage()); assertEquals(expectedMessage, e.getMessage());
} }
} }
} }
@@ -1,202 +1,202 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.repository; package fr.iut_fbleau.but3.dev62.mylibrary.order.repository;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison; import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison;
import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement; import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order; import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
class OrderRepositoryTest { class OrderRepositoryTest {
private OrderRepository repository; private OrderRepository repository;
private Order order1; private Order order1;
private Order order2; private Order order2;
private UUID clientId1; private UUID clientId1;
private UUID clientId2; private UUID clientId2;
@BeforeEach @BeforeEach
void setUp() { void setUp() {
repository = new OrderRepository(); repository = new OrderRepository();
clientId1 = UUID.randomUUID(); clientId1 = UUID.randomUUID();
clientId2 = UUID.randomUUID(); clientId2 = UUID.randomUUID();
AdresseLivraison adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France"); AdresseLivraison adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France");
order1 = Order.builder() order1 = Order.builder()
.clientId(clientId1) .clientId(clientId1)
.adresseLivraison(adresse) .adresseLivraison(adresse)
.modePaiement(ModePaiement.CB) .modePaiement(ModePaiement.CB)
.montantTotal(new BigDecimal("25.80")) .montantTotal(new BigDecimal("25.80"))
.pointsFideliteGagnes(25) .pointsFideliteGagnes(25)
.lignesCommande(List.of()) .lignesCommande(List.of())
.build(); .build();
order1.setRandomUUID(); order1.setRandomUUID();
order2 = Order.builder() order2 = Order.builder()
.clientId(clientId2) .clientId(clientId2)
.adresseLivraison(adresse) .adresseLivraison(adresse)
.modePaiement(ModePaiement.PAYPAL) .modePaiement(ModePaiement.PAYPAL)
.montantTotal(new BigDecimal("9.50")) .montantTotal(new BigDecimal("9.50"))
.pointsFideliteGagnes(9) .pointsFideliteGagnes(9)
.lignesCommande(List.of()) .lignesCommande(List.of())
.build(); .build();
order2.setRandomUUID(); order2.setRandomUUID();
} }
@Test @Test
@DisplayName("New repository should be empty") @DisplayName("New repository should be empty")
void testNewRepositoryIsEmpty() { void testNewRepositoryIsEmpty() {
assertTrue(repository.findAll().isEmpty()); assertTrue(repository.findAll().isEmpty());
assertEquals(0, repository.findAll().size()); assertEquals(0, repository.findAll().size());
} }
@Nested @Nested
@DisplayName("Save operations") @DisplayName("Save operations")
class SaveOperations { class SaveOperations {
@Test @Test
@DisplayName("Save should add a new order") @DisplayName("Save should add a new order")
void testSaveNewOrder() { void testSaveNewOrder() {
Order saved = repository.save(order1); Order saved = repository.save(order1);
assertEquals(1, repository.findAll().size()); assertEquals(1, repository.findAll().size());
assertEquals(order1.getId(), saved.getId()); assertEquals(order1.getId(), saved.getId());
} }
@Test @Test
@DisplayName("Save should update existing order with same ID") @DisplayName("Save should update existing order with same ID")
void testSaveUpdatesExistingOrder() { void testSaveUpdatesExistingOrder() {
repository.save(order1); repository.save(order1);
UUID id = order1.getId(); UUID id = order1.getId();
Order updatedOrder = Order.builder() Order updatedOrder = Order.builder()
.id(id) .id(id)
.clientId(clientId1) .clientId(clientId1)
.adresseLivraison(new AdresseLivraison("2 rue de Lyon", "Lyon", "69001", "France")) .adresseLivraison(new AdresseLivraison("2 rue de Lyon", "Lyon", "69001", "France"))
.modePaiement(ModePaiement.PAYPAL) .modePaiement(ModePaiement.PAYPAL)
.montantTotal(new BigDecimal("50.00")) .montantTotal(new BigDecimal("50.00"))
.pointsFideliteGagnes(50) .pointsFideliteGagnes(50)
.lignesCommande(List.of()) .lignesCommande(List.of())
.build(); .build();
Order saved = repository.save(updatedOrder); Order saved = repository.save(updatedOrder);
assertEquals(1, repository.findAll().size()); assertEquals(1, repository.findAll().size());
assertEquals(id, saved.getId()); assertEquals(id, saved.getId());
assertEquals(new BigDecimal("50.00"), saved.getMontantTotal()); assertEquals(new BigDecimal("50.00"), saved.getMontantTotal());
} }
@Test @Test
@DisplayName("Save multiple orders should add all of them") @DisplayName("Save multiple orders should add all of them")
void testSaveMultipleOrders() { void testSaveMultipleOrders() {
repository.save(order1); repository.save(order1);
repository.save(order2); repository.save(order2);
assertEquals(2, repository.findAll().size()); assertEquals(2, repository.findAll().size());
} }
} }
@Nested @Nested
@DisplayName("Find operations") @DisplayName("Find operations")
class FindOperations { class FindOperations {
@BeforeEach @BeforeEach
void setUpOrders() { void setUpOrders() {
repository.save(order1); repository.save(order1);
repository.save(order2); repository.save(order2);
} }
@Test @Test
@DisplayName("FindAll should return all orders") @DisplayName("FindAll should return all orders")
void testFindAll() { void testFindAll() {
assertEquals(2, repository.findAll().size()); assertEquals(2, repository.findAll().size());
} }
@Test @Test
@DisplayName("FindById should return order with matching ID") @DisplayName("FindById should return order with matching ID")
void testFindById() { void testFindById() {
Optional<Order> found = repository.findById(order1.getId()); Optional<Order> found = repository.findById(order1.getId());
assertTrue(found.isPresent()); assertTrue(found.isPresent());
assertEquals(order1.getId(), found.get().getId()); assertEquals(order1.getId(), found.get().getId());
} }
@Test @Test
@DisplayName("FindById should return empty Optional when ID doesn't exist") @DisplayName("FindById should return empty Optional when ID doesn't exist")
void testFindByIdNotFound() { void testFindByIdNotFound() {
Optional<Order> found = repository.findById(UUID.randomUUID()); Optional<Order> found = repository.findById(UUID.randomUUID());
assertTrue(found.isEmpty()); assertTrue(found.isEmpty());
} }
@Test @Test
@DisplayName("FindByClientId should return all orders for a client") @DisplayName("FindByClientId should return all orders for a client")
void testFindByClientId() { void testFindByClientId() {
List<Order> found = repository.findByClientId(clientId1); List<Order> found = repository.findByClientId(clientId1);
assertEquals(1, found.size()); assertEquals(1, found.size());
assertEquals(order1.getId(), found.getFirst().getId()); assertEquals(order1.getId(), found.getFirst().getId());
} }
@Test @Test
@DisplayName("ExistsById should return true when ID exists") @DisplayName("ExistsById should return true when ID exists")
void testExistsByIdExists() { void testExistsByIdExists() {
assertTrue(repository.existsById(order1.getId())); assertTrue(repository.existsById(order1.getId()));
} }
@Test @Test
@DisplayName("ExistsById should return false when ID doesn't exist") @DisplayName("ExistsById should return false when ID doesn't exist")
void testExistsByIdNotExists() { void testExistsByIdNotExists() {
assertFalse(repository.existsById(UUID.randomUUID())); assertFalse(repository.existsById(UUID.randomUUID()));
} }
} }
@Nested @Nested
@DisplayName("Delete operations") @DisplayName("Delete operations")
class DeleteOperations { class DeleteOperations {
@BeforeEach @BeforeEach
void setUpOrders() { void setUpOrders() {
repository.save(order1); repository.save(order1);
repository.save(order2); repository.save(order2);
} }
@Test @Test
@DisplayName("Delete should remove the specified order") @DisplayName("Delete should remove the specified order")
void testDelete() { void testDelete() {
repository.delete(order1); repository.delete(order1);
assertEquals(1, repository.findAll().size()); assertEquals(1, repository.findAll().size());
assertFalse(repository.findAll().contains(order1)); assertFalse(repository.findAll().contains(order1));
assertTrue(repository.findAll().contains(order2)); assertTrue(repository.findAll().contains(order2));
} }
@Test @Test
@DisplayName("DeleteAll should remove all orders") @DisplayName("DeleteAll should remove all orders")
void testDeleteAll() { void testDeleteAll() {
repository.deleteAll(); repository.deleteAll();
assertTrue(repository.findAll().isEmpty()); assertTrue(repository.findAll().isEmpty());
} }
@Test @Test
@DisplayName("Delete should not throw exception when order doesn't exist") @DisplayName("Delete should not throw exception when order doesn't exist")
void testDeleteNonExistentOrder() { void testDeleteNonExistentOrder() {
Order nonExistent = Order.builder().build(); Order nonExistent = Order.builder().build();
nonExistent.setRandomUUID(); nonExistent.setRandomUUID();
assertDoesNotThrow(() -> repository.delete(nonExistent)); assertDoesNotThrow(() -> repository.delete(nonExistent));
assertEquals(2, repository.findAll().size()); assertEquals(2, repository.findAll().size());
} }
} }
} }
@@ -1,226 +1,226 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.usecase; 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.entity.Book;
import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; 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.entity.Customer;
import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException; 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.customer.repository.CustomerRepository;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison; import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison;
import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo; import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement; import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO; 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.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order; import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException; import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository; import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
class OrderUseCaseTest { class OrderUseCaseTest {
@Mock @Mock
private OrderRepository orderRepository; private OrderRepository orderRepository;
@Mock @Mock
private CustomerRepository customerRepository; private CustomerRepository customerRepository;
@Mock @Mock
private BookRepository bookRepository; private BookRepository bookRepository;
@InjectMocks @InjectMocks
private OrderUseCase orderUseCase; private OrderUseCase orderUseCase;
private UUID customerId; private UUID customerId;
private UUID bookId; private UUID bookId;
private Customer testCustomer; private Customer testCustomer;
private Book testBook; private Book testBook;
private AdresseLivraison adresse; private AdresseLivraison adresse;
private OrderInfo validOrderInfo; private OrderInfo validOrderInfo;
@BeforeEach @BeforeEach
void setUp() { void setUp() {
customerId = UUID.randomUUID(); customerId = UUID.randomUUID();
bookId = UUID.randomUUID(); bookId = UUID.randomUUID();
testCustomer = Customer.builder() testCustomer = Customer.builder()
.id(customerId) .id(customerId)
.firstName("Marie") .firstName("Marie")
.lastName("Dupont") .lastName("Dupont")
.phoneNumber("0612345678") .phoneNumber("0612345678")
.loyaltyPoints(100) .loyaltyPoints(100)
.build(); .build();
testBook = Book.builder() testBook = Book.builder()
.id(bookId) .id(bookId)
.isbn("9782016289308") .isbn("9782016289308")
.title("Le Petit Prince") .title("Le Petit Prince")
.author("Antoine de Saint-Exupery") .author("Antoine de Saint-Exupery")
.publisher("Gallimard") .publisher("Gallimard")
.publicationDate(LocalDate.of(1943, 4, 6)) .publicationDate(LocalDate.of(1943, 4, 6))
.price(new BigDecimal("12.90")) .price(new BigDecimal("12.90"))
.stock(10) .stock(10)
.categories(List.of("Roman")) .categories(List.of("Roman"))
.description("Un classique") .description("Un classique")
.language("FR") .language("FR")
.build(); .build();
adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France"); adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France");
validOrderInfo = new OrderInfo( validOrderInfo = new OrderInfo(
customerId, customerId,
List.of(new LigneCommandeInfo(bookId, 2)), List.of(new LigneCommandeInfo(bookId, 2)),
adresse, adresse,
ModePaiement.CB ModePaiement.CB
); );
} }
@Nested @Nested
@DisplayName("PasserCommande tests") @DisplayName("PasserCommande tests")
class PasserCommandeTests { class PasserCommandeTests {
@Test @Test
@DisplayName("Should place order when valid data is provided") @DisplayName("Should place order when valid data is provided")
void testPasserCommandeWithValidData() throws NotValidOrderException, CustomerNotFoundException { void testPasserCommandeWithValidData() throws NotValidOrderException, CustomerNotFoundException {
when(customerRepository.findById(customerId)).thenReturn(Optional.of(testCustomer)); when(customerRepository.findById(customerId)).thenReturn(Optional.of(testCustomer));
when(bookRepository.findById(bookId)).thenReturn(Optional.of(testBook)); when(bookRepository.findById(bookId)).thenReturn(Optional.of(testBook));
when(customerRepository.save(any(Customer.class))).thenReturn(testCustomer); when(customerRepository.save(any(Customer.class))).thenReturn(testCustomer);
UUID orderId = UUID.randomUUID(); UUID orderId = UUID.randomUUID();
Order savedOrder = Order.builder() Order savedOrder = Order.builder()
.id(orderId) .id(orderId)
.clientId(customerId) .clientId(customerId)
.montantTotal(new BigDecimal("25.80")) .montantTotal(new BigDecimal("25.80"))
.pointsFideliteGagnes(25) .pointsFideliteGagnes(25)
.build(); .build();
when(orderRepository.save(any(Order.class))).thenReturn(savedOrder); when(orderRepository.save(any(Order.class))).thenReturn(savedOrder);
OrderDTO result = orderUseCase.passerCommande(validOrderInfo); OrderDTO result = orderUseCase.passerCommande(validOrderInfo);
assertNotNull(result); assertNotNull(result);
assertEquals(orderId, result.getCommandeId()); assertEquals(orderId, result.getCommandeId());
verify(orderRepository, times(1)).save(any(Order.class)); verify(orderRepository, times(1)).save(any(Order.class));
verify(customerRepository, times(1)).save(any(Customer.class)); verify(customerRepository, times(1)).save(any(Customer.class));
} }
@Test @Test
@DisplayName("Should throw exception when customer does not exist") @DisplayName("Should throw exception when customer does not exist")
void testPasserCommandeWithUnknownCustomer() { void testPasserCommandeWithUnknownCustomer() {
when(customerRepository.findById(customerId)).thenReturn(Optional.empty()); when(customerRepository.findById(customerId)).thenReturn(Optional.empty());
assertThrows(CustomerNotFoundException.class, assertThrows(CustomerNotFoundException.class,
() -> orderUseCase.passerCommande(validOrderInfo)); () -> orderUseCase.passerCommande(validOrderInfo));
verify(orderRepository, never()).save(any(Order.class)); verify(orderRepository, never()).save(any(Order.class));
} }
@Test @Test
@DisplayName("Should throw exception when order has no items") @DisplayName("Should throw exception when order has no items")
void testPasserCommandeWithNoItems() { void testPasserCommandeWithNoItems() {
OrderInfo emptyOrder = new OrderInfo(customerId, List.of(), adresse, ModePaiement.CB); OrderInfo emptyOrder = new OrderInfo(customerId, List.of(), adresse, ModePaiement.CB);
assertThrows(NotValidOrderException.class, assertThrows(NotValidOrderException.class,
() -> orderUseCase.passerCommande(emptyOrder)); () -> orderUseCase.passerCommande(emptyOrder));
verify(orderRepository, never()).save(any(Order.class)); verify(orderRepository, never()).save(any(Order.class));
} }
@Test @Test
@DisplayName("Should throw exception when quantity is zero or negative") @DisplayName("Should throw exception when quantity is zero or negative")
void testPasserCommandeWithInvalidQuantity() { void testPasserCommandeWithInvalidQuantity() {
OrderInfo invalidQty = new OrderInfo( OrderInfo invalidQty = new OrderInfo(
customerId, customerId,
List.of(new LigneCommandeInfo(bookId, 0)), List.of(new LigneCommandeInfo(bookId, 0)),
adresse, adresse,
ModePaiement.CB ModePaiement.CB
); );
assertThrows(NotValidOrderException.class, assertThrows(NotValidOrderException.class,
() -> orderUseCase.passerCommande(invalidQty)); () -> orderUseCase.passerCommande(invalidQty));
verify(orderRepository, never()).save(any(Order.class)); verify(orderRepository, never()).save(any(Order.class));
} }
@Test @Test
@DisplayName("Should throw exception when clientId is null") @DisplayName("Should throw exception when clientId is null")
void testPasserCommandeWithNullClientId() { void testPasserCommandeWithNullClientId() {
OrderInfo nullClient = new OrderInfo( OrderInfo nullClient = new OrderInfo(
null, null,
List.of(new LigneCommandeInfo(bookId, 1)), List.of(new LigneCommandeInfo(bookId, 1)),
adresse, adresse,
ModePaiement.CB ModePaiement.CB
); );
assertThrows(NotValidOrderException.class, assertThrows(NotValidOrderException.class,
() -> orderUseCase.passerCommande(nullClient)); () -> orderUseCase.passerCommande(nullClient));
verify(orderRepository, never()).save(any(Order.class)); verify(orderRepository, never()).save(any(Order.class));
} }
@Test @Test
@DisplayName("Should throw exception when payment method is null") @DisplayName("Should throw exception when payment method is null")
void testPasserCommandeWithNullModePaiement() { void testPasserCommandeWithNullModePaiement() {
OrderInfo nullPayment = new OrderInfo( OrderInfo nullPayment = new OrderInfo(
customerId, customerId,
List.of(new LigneCommandeInfo(bookId, 1)), List.of(new LigneCommandeInfo(bookId, 1)),
adresse, adresse,
null null
); );
assertThrows(NotValidOrderException.class, assertThrows(NotValidOrderException.class,
() -> orderUseCase.passerCommande(nullPayment)); () -> orderUseCase.passerCommande(nullPayment));
verify(orderRepository, never()).save(any(Order.class)); verify(orderRepository, never()).save(any(Order.class));
} }
} }
@Nested @Nested
@DisplayName("FindOrder tests") @DisplayName("FindOrder tests")
class FindOrderTests { class FindOrderTests {
@Test @Test
@DisplayName("Should return order when ID exists") @DisplayName("Should return order when ID exists")
void testFindOrderById() { void testFindOrderById() {
UUID orderId = UUID.randomUUID(); UUID orderId = UUID.randomUUID();
Order order = Order.builder() Order order = Order.builder()
.id(orderId) .id(orderId)
.clientId(customerId) .clientId(customerId)
.montantTotal(new BigDecimal("25.80")) .montantTotal(new BigDecimal("25.80"))
.pointsFideliteGagnes(25) .pointsFideliteGagnes(25)
.build(); .build();
when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); when(orderRepository.findById(orderId)).thenReturn(Optional.of(order));
Optional<OrderDTO> result = orderUseCase.findOrderById(orderId); Optional<OrderDTO> result = orderUseCase.findOrderById(orderId);
assertTrue(result.isPresent()); assertTrue(result.isPresent());
assertEquals(orderId, result.get().getCommandeId()); assertEquals(orderId, result.get().getCommandeId());
} }
@Test @Test
@DisplayName("Should return empty Optional when ID does not exist") @DisplayName("Should return empty Optional when ID does not exist")
void testFindOrderByIdNotFound() { void testFindOrderByIdNotFound() {
UUID nonExistentId = UUID.randomUUID(); UUID nonExistentId = UUID.randomUUID();
when(orderRepository.findById(nonExistentId)).thenReturn(Optional.empty()); when(orderRepository.findById(nonExistentId)).thenReturn(Optional.empty());
Optional<OrderDTO> result = orderUseCase.findOrderById(nonExistentId); Optional<OrderDTO> result = orderUseCase.findOrderById(nonExistentId);
assertTrue(result.isEmpty()); assertTrue(result.isEmpty());
} }
} }
} }
@@ -1,155 +1,155 @@
package fr.iut_fbleau.but3.dev62.mylibrary.order.validator; package fr.iut_fbleau.but3.dev62.mylibrary.order.validator;
import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison; import fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison;
import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo; import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement; import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement;
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo; import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo;
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException; import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
class OrderValidatorTest { class OrderValidatorTest {
private final UUID clientId = UUID.randomUUID(); private final UUID clientId = UUID.randomUUID();
private final UUID livreId = UUID.randomUUID(); private final UUID livreId = UUID.randomUUID();
private final AdresseLivraison adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France"); private final AdresseLivraison adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France");
private OrderInfo validOrder() { private OrderInfo validOrder() {
return new OrderInfo( return new OrderInfo(
clientId, clientId,
List.of(new LigneCommandeInfo(livreId, 1)), List.of(new LigneCommandeInfo(livreId, 1)),
adresse, adresse,
ModePaiement.CB ModePaiement.CB
); );
} }
@Test @Test
@DisplayName("Should validate order with valid data") @DisplayName("Should validate order with valid data")
void testValidateValidOrder() { void testValidateValidOrder() {
assertDoesNotThrow(() -> OrderValidator.validate(validOrder())); assertDoesNotThrow(() -> OrderValidator.validate(validOrder()));
} }
@Nested @Nested
@DisplayName("ClientId validation tests") @DisplayName("ClientId validation tests")
class ClientIdValidationTests { class ClientIdValidationTests {
@Test @Test
@DisplayName("Should throw exception when clientId is null") @DisplayName("Should throw exception when clientId is null")
void testValidateNullClientId() { void testValidateNullClientId() {
OrderInfo order = new OrderInfo(null, List.of(new LigneCommandeInfo(livreId, 1)), adresse, ModePaiement.CB); OrderInfo order = new OrderInfo(null, List.of(new LigneCommandeInfo(livreId, 1)), adresse, ModePaiement.CB);
NotValidOrderException exception = assertThrows(NotValidOrderException.class, NotValidOrderException exception = assertThrows(NotValidOrderException.class,
() -> OrderValidator.validate(order)); () -> OrderValidator.validate(order));
assertEquals(OrderValidator.CLIENT_ID_CANNOT_BE_NULL, exception.getMessage()); assertEquals(OrderValidator.CLIENT_ID_CANNOT_BE_NULL, exception.getMessage());
} }
} }
@Nested @Nested
@DisplayName("LignesCommande validation tests") @DisplayName("LignesCommande validation tests")
class LignesCommandeValidationTests { class LignesCommandeValidationTests {
@Test @Test
@DisplayName("Should throw exception when lignesCommande is empty") @DisplayName("Should throw exception when lignesCommande is empty")
void testValidateEmptyLignesCommande() { void testValidateEmptyLignesCommande() {
OrderInfo order = new OrderInfo(clientId, List.of(), adresse, ModePaiement.CB); OrderInfo order = new OrderInfo(clientId, List.of(), adresse, ModePaiement.CB);
NotValidOrderException exception = assertThrows(NotValidOrderException.class, NotValidOrderException exception = assertThrows(NotValidOrderException.class,
() -> OrderValidator.validate(order)); () -> OrderValidator.validate(order));
assertEquals(OrderValidator.LIGNES_COMMANDE_CANNOT_BE_EMPTY, exception.getMessage()); assertEquals(OrderValidator.LIGNES_COMMANDE_CANNOT_BE_EMPTY, exception.getMessage());
} }
@Test @Test
@DisplayName("Should throw exception when lignesCommande is null") @DisplayName("Should throw exception when lignesCommande is null")
void testValidateNullLignesCommande() { void testValidateNullLignesCommande() {
OrderInfo order = new OrderInfo(clientId, null, adresse, ModePaiement.CB); OrderInfo order = new OrderInfo(clientId, null, adresse, ModePaiement.CB);
NotValidOrderException exception = assertThrows(NotValidOrderException.class, NotValidOrderException exception = assertThrows(NotValidOrderException.class,
() -> OrderValidator.validate(order)); () -> OrderValidator.validate(order));
assertEquals(OrderValidator.LIGNES_COMMANDE_CANNOT_BE_EMPTY, exception.getMessage()); assertEquals(OrderValidator.LIGNES_COMMANDE_CANNOT_BE_EMPTY, exception.getMessage());
} }
@Test @Test
@DisplayName("Should throw exception when quantite is zero") @DisplayName("Should throw exception when quantite is zero")
void testValidateZeroQuantite() { void testValidateZeroQuantite() {
OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 0)), adresse, ModePaiement.CB); OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 0)), adresse, ModePaiement.CB);
NotValidOrderException exception = assertThrows(NotValidOrderException.class, NotValidOrderException exception = assertThrows(NotValidOrderException.class,
() -> OrderValidator.validate(order)); () -> OrderValidator.validate(order));
assertEquals(OrderValidator.QUANTITE_MUST_BE_POSITIVE, exception.getMessage()); assertEquals(OrderValidator.QUANTITE_MUST_BE_POSITIVE, exception.getMessage());
} }
@Test @Test
@DisplayName("Should throw exception when quantite is negative") @DisplayName("Should throw exception when quantite is negative")
void testValidateNegativeQuantite() { void testValidateNegativeQuantite() {
OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, -1)), adresse, ModePaiement.CB); OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, -1)), adresse, ModePaiement.CB);
NotValidOrderException exception = assertThrows(NotValidOrderException.class, NotValidOrderException exception = assertThrows(NotValidOrderException.class,
() -> OrderValidator.validate(order)); () -> OrderValidator.validate(order));
assertEquals(OrderValidator.QUANTITE_MUST_BE_POSITIVE, exception.getMessage()); assertEquals(OrderValidator.QUANTITE_MUST_BE_POSITIVE, exception.getMessage());
} }
} }
@Nested @Nested
@DisplayName("AdresseLivraison validation tests") @DisplayName("AdresseLivraison validation tests")
class AdresseLivraisonValidationTests { class AdresseLivraisonValidationTests {
@Test @Test
@DisplayName("Should throw exception when adresseLivraison is null") @DisplayName("Should throw exception when adresseLivraison is null")
void testValidateNullAdresseLivraison() { void testValidateNullAdresseLivraison() {
OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), null, ModePaiement.CB); OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), null, ModePaiement.CB);
NotValidOrderException exception = assertThrows(NotValidOrderException.class, NotValidOrderException exception = assertThrows(NotValidOrderException.class,
() -> OrderValidator.validate(order)); () -> OrderValidator.validate(order));
assertEquals(OrderValidator.ADRESSE_LIVRAISON_CANNOT_BE_NULL, exception.getMessage()); assertEquals(OrderValidator.ADRESSE_LIVRAISON_CANNOT_BE_NULL, exception.getMessage());
} }
} }
@Nested @Nested
@DisplayName("ModePaiement validation tests") @DisplayName("ModePaiement validation tests")
class ModePaiementValidationTests { class ModePaiementValidationTests {
@Test @Test
@DisplayName("Should throw exception when modePaiement is null") @DisplayName("Should throw exception when modePaiement is null")
void testValidateNullModePaiement() { void testValidateNullModePaiement() {
OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), adresse, null); OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), adresse, null);
NotValidOrderException exception = assertThrows(NotValidOrderException.class, NotValidOrderException exception = assertThrows(NotValidOrderException.class,
() -> OrderValidator.validate(order)); () -> OrderValidator.validate(order));
assertEquals(OrderValidator.MODE_PAIEMENT_CANNOT_BE_NULL, exception.getMessage()); assertEquals(OrderValidator.MODE_PAIEMENT_CANNOT_BE_NULL, exception.getMessage());
} }
@Test @Test
@DisplayName("Should validate with CB payment method") @DisplayName("Should validate with CB payment method")
void testValidateWithCB() { void testValidateWithCB() {
OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), adresse, ModePaiement.CB); OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), adresse, ModePaiement.CB);
assertDoesNotThrow(() -> OrderValidator.validate(order)); assertDoesNotThrow(() -> OrderValidator.validate(order));
} }
@Test @Test
@DisplayName("Should validate with PAYPAL payment method") @DisplayName("Should validate with PAYPAL payment method")
void testValidateWithPaypal() { void testValidateWithPaypal() {
OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), adresse, ModePaiement.PAYPAL); OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), adresse, ModePaiement.PAYPAL);
assertDoesNotThrow(() -> OrderValidator.validate(order)); assertDoesNotThrow(() -> OrderValidator.validate(order));
} }
@Test @Test
@DisplayName("Should validate with POINTS_FIDELITE payment method") @DisplayName("Should validate with POINTS_FIDELITE payment method")
void testValidateWithPointsFidelite() { void testValidateWithPointsFidelite() {
OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), adresse, ModePaiement.POINTS_FIDELITE); OrderInfo order = new OrderInfo(clientId, List.of(new LigneCommandeInfo(livreId, 1)), adresse, ModePaiement.POINTS_FIDELITE);
assertDoesNotThrow(() -> OrderValidator.validate(order)); assertDoesNotThrow(() -> OrderValidator.validate(order));
} }
} }
} }
+49 -49
View File
@@ -1,49 +1,49 @@
# language: en # language: en
Feature: Place an order Feature: Place an order
Background: Background:
Given the system has the following customers for order: Given the system has the following customers for order:
| prenom | nom | numeroTelephone | pointsFidelite | | prenom | nom | numeroTelephone | pointsFidelite |
| Marie | Dupont | 0612345678 | 100 | | Marie | Dupont | 0612345678 | 100 |
| Jean | Martin | 0687654321 | 50 | | Jean | Martin | 0687654321 | 50 |
And the catalog has the following books for order: And the catalog has the following books for order:
| isbn | titre | auteur | editeur | datePublication | prix | stockInitial | categories | description | langue | | isbn | titre | auteur | editeur | datePublication | prix | stockInitial | categories | description | langue |
| 9782016289308 | Le Petit Prince | Antoine de Saint-Exupery | Gallimard | 1943-04-06 | 12.90 | 10 | Roman | Un classique | FR | | 9782016289308 | Le Petit Prince | Antoine de Saint-Exupery | Gallimard | 1943-04-06 | 12.90 | 10 | Roman | Un classique | FR |
| 9782070409189 | L Etranger | Albert Camus | Gallimard | 1942-05-19 | 9.50 | 5 | Roman | Philosophique| FR | | 9782070409189 | L Etranger | Albert Camus | Gallimard | 1942-05-19 | 9.50 | 5 | Roman | Philosophique| FR |
Scenario: Place an order with CB payment Scenario: Place an order with CB payment
When I place an order for customer "0612345678" with: When I place an order for customer "0612345678" with:
| livreIsbn | quantite | rue | ville | codePostal | pays | modePaiement | | livreIsbn | quantite | rue | ville | codePostal | pays | modePaiement |
| 9782016289308 | 2 | 1 rue de Paris | Paris | 75001 | France | CB | | 9782016289308 | 2 | 1 rue de Paris | Paris | 75001 | France | CB |
Then a new order is created Then a new order is created
And the order total is 25.80 And the order total is 25.80
And the customer "0612345678" now has 125 loyalty points And the customer "0612345678" now has 125 loyalty points
Scenario: Place an order with PAYPAL payment Scenario: Place an order with PAYPAL payment
When I place an order for customer "0687654321" with: When I place an order for customer "0687654321" with:
| livreIsbn | quantite | rue | ville | codePostal | pays | modePaiement | | livreIsbn | quantite | rue | ville | codePostal | pays | modePaiement |
| 9782070409189 | 1 | 5 rue de Lyon | Lyon | 69001 | France | PAYPAL | | 9782070409189 | 1 | 5 rue de Lyon | Lyon | 69001 | France | PAYPAL |
Then a new order is created Then a new order is created
And the order total is 9.50 And the order total is 9.50
And the customer "0687654321" now has 59 loyalty points And the customer "0687654321" now has 59 loyalty points
Scenario: Attempt to place an order with no items Scenario: Attempt to place an order with no items
When I try to place an order for customer "0612345678" with no items: When I try to place an order for customer "0612345678" with no items:
| rue | ville | codePostal | pays | modePaiement | | rue | ville | codePostal | pays | modePaiement |
| 1 rue de Paris | Paris | 75001 | France | CB | | 1 rue de Paris | Paris | 75001 | France | CB |
Then the order placement fails Then the order placement fails
And I receive a validation order error containing "Order must have at least one item" And I receive a validation order error containing "Order must have at least one item"
Scenario: Attempt to place an order with invalid quantity Scenario: Attempt to place an order with invalid quantity
When I try to place an order for customer "0612345678" with invalid quantity: When I try to place an order for customer "0612345678" with invalid quantity:
| livreIsbn | quantite | rue | ville | codePostal | pays | modePaiement | | livreIsbn | quantite | rue | ville | codePostal | pays | modePaiement |
| 9782016289308 | 0 | 1 rue de Paris | Paris | 75001 | France | CB | | 9782016289308 | 0 | 1 rue de Paris | Paris | 75001 | France | CB |
Then the order placement fails Then the order placement fails
And I receive a validation order error containing "Quantity must be positive" And I receive a validation order error containing "Quantity must be positive"
Scenario: Attempt to place an order for unknown customer Scenario: Attempt to place an order for unknown customer
When I try to place an order for an unknown customer with: When I try to place an order for an unknown customer with:
| livreIsbn | quantite | rue | ville | codePostal | pays | modePaiement | | livreIsbn | quantite | rue | ville | codePostal | pays | modePaiement |
| 9782016289308 | 1 | 1 rue de Paris | Paris | 75001 | France | CB | | 9782016289308 | 1 | 1 rue de Paris | Paris | 75001 | France | CB |
Then the order placement fails with customer not found Then the order placement fails with customer not found