done ?
This commit is contained in:
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
7
.idea/encodings.xml
generated
Normal file
7
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
10
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
10
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
12
.idea/misc.xml
generated
Normal file
12
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="corretto-21" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,24 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.book;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class BookDTO {
|
||||
private final String isbn;
|
||||
private final String title;
|
||||
private final String author;
|
||||
private final String publisher;
|
||||
private final LocalDate publicationDate;
|
||||
private final double price;
|
||||
private final int stock;
|
||||
private final List<Category> categories;
|
||||
private final String description;
|
||||
private final String language;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.book;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public record BookInfo(
|
||||
String isbn,
|
||||
String title,
|
||||
String author,
|
||||
String publisher,
|
||||
LocalDate publicationDate,
|
||||
double price,
|
||||
int stock,
|
||||
List<Category> categories,
|
||||
String description,
|
||||
String language
|
||||
) {}
|
||||
@@ -0,0 +1,24 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.book;
|
||||
|
||||
public enum Category {
|
||||
FICTION,
|
||||
NON_FICTION,
|
||||
SCIENCE_FICTION,
|
||||
FANTASY,
|
||||
MYSTERY,
|
||||
THRILLER,
|
||||
ROMANCE,
|
||||
BIOGRAPHY,
|
||||
HISTORY,
|
||||
POETRY,
|
||||
CHILDREN,
|
||||
YOUNG_ADULT,
|
||||
SCIENCE,
|
||||
PHILOSOPHY,
|
||||
SELF_HELP,
|
||||
TRAVEL,
|
||||
COOKING,
|
||||
ART,
|
||||
RELIGION,
|
||||
REFERENCE
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
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.BookInfo;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book;
|
||||
|
||||
public final class BookConverter {
|
||||
|
||||
private BookConverter() {}
|
||||
|
||||
public static Book toDomain(BookInfo info) {
|
||||
return Book.builder()
|
||||
.isbn(info.isbn())
|
||||
.title(info.title())
|
||||
.author(info.author())
|
||||
.publisher(info.publisher())
|
||||
.publicationDate(info.publicationDate())
|
||||
.price(info.price())
|
||||
.stock(info.stock())
|
||||
.categories(info.categories())
|
||||
.description(info.description())
|
||||
.language(info.language())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static BookDTO toDTO(Book book) {
|
||||
return BookDTO.builder()
|
||||
.isbn(book.getIsbn())
|
||||
.title(book.getTitle())
|
||||
.author(book.getAuthor())
|
||||
.publisher(book.getPublisher())
|
||||
.publicationDate(book.getPublicationDate())
|
||||
.price(book.getPrice())
|
||||
.stock(book.getStock())
|
||||
.categories(book.getCategories())
|
||||
.description(book.getDescription())
|
||||
.language(book.getLanguage())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.book.entity;
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.book.Category;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class Book {
|
||||
private String isbn;
|
||||
private String title;
|
||||
private String author;
|
||||
private String publisher;
|
||||
private LocalDate publicationDate;
|
||||
private double price;
|
||||
private int stock;
|
||||
private List<Category> categories;
|
||||
private String description;
|
||||
private String language;
|
||||
|
||||
public void addStock(int quantityToAdd) {
|
||||
this.stock += quantityToAdd;
|
||||
}
|
||||
|
||||
public void removeStock(int quantityToRemove) {
|
||||
if (quantityToRemove > this.stock) {
|
||||
throw new IllegalArgumentException("Pas assez de stock pour retirer : " + quantityToRemove);
|
||||
}
|
||||
this.stock -= quantityToRemove;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
|
||||
|
||||
public class BookNotFoundException extends RuntimeException {
|
||||
public static final String THE_BOOK_WITH_ISBN_DOES_NOT_EXIST_MESSAGE = "The book with isbn %s does not exist";
|
||||
|
||||
public BookNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public static BookNotFoundException forIsbn(String isbn) {
|
||||
return new BookNotFoundException(String.format(THE_BOOK_WITH_ISBN_DOES_NOT_EXIST_MESSAGE, isbn));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.book.exception;
|
||||
|
||||
public class NotValidBookException extends RuntimeException {
|
||||
public NotValidBookException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
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.Category;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
public final class BookRepository {
|
||||
private final List<Book> books = new ArrayList<>();
|
||||
|
||||
public List<Book> findAll() {
|
||||
return books;
|
||||
}
|
||||
|
||||
public void deleteAll() {
|
||||
books.clear();
|
||||
}
|
||||
|
||||
public Book save(Book newBook) {
|
||||
Optional<Book> optionalBookWithSameIsbn = this.findByIsbn(newBook.getIsbn());
|
||||
optionalBookWithSameIsbn.ifPresent(books::remove);
|
||||
books.add(newBook);
|
||||
return newBook;
|
||||
}
|
||||
|
||||
public Optional<Book> findByIsbn(String isbn) {
|
||||
return books.stream()
|
||||
.filter(book -> Objects.equals(book.getIsbn(), isbn))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public boolean existsByIsbn(String isbn) {
|
||||
return books.stream()
|
||||
.anyMatch(book -> Objects.equals(book.getIsbn(), isbn));
|
||||
}
|
||||
|
||||
public void delete(Book book) {
|
||||
books.remove(book);
|
||||
}
|
||||
|
||||
public List<Book> findByTitleContaining(String titlePart) {
|
||||
return books.stream()
|
||||
.filter(book -> book.getTitle() != null && book.getTitle().toLowerCase().contains(titlePart.toLowerCase()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Book> findByAuthor(String author) {
|
||||
return books.stream()
|
||||
.filter(book -> book.getAuthor() != null && book.getAuthor().equalsIgnoreCase(author))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Book> findByPublisher(String publisher) {
|
||||
return books.stream()
|
||||
.filter(book -> book.getPublisher() != null && book.getPublisher().equalsIgnoreCase(publisher))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Book> findByCategory(Category category) {
|
||||
return books.stream()
|
||||
.filter(book -> book.getCategories() != null && book.getCategories().contains(category))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Book> findPublishedAfter(java.time.LocalDate date) {
|
||||
return books.stream()
|
||||
.filter(book -> book.getPublicationDate() != null && book.getPublicationDate().isAfter(date))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Book> findByPriceRange(double min, double max) {
|
||||
return books.stream()
|
||||
.filter(book -> book.getPrice() >= min && book.getPrice() <= max)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
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.BookInfo;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.book.Category;
|
||||
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.exception.BookNotFoundException;
|
||||
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.validator.BookValidator;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class BookUseCase {
|
||||
|
||||
private final BookRepository bookRepository;
|
||||
|
||||
public BookUseCase(BookRepository bookRepository) {
|
||||
this.bookRepository = bookRepository;
|
||||
}
|
||||
|
||||
public String registerBook(BookInfo newBook) throws NotValidBookException {
|
||||
BookValidator.validate(newBook);
|
||||
|
||||
if (bookRepository.existsByIsbn(newBook.isbn())) {
|
||||
throw new NotValidBookException("Un livre avec cet ISBN existe déjà");
|
||||
}
|
||||
|
||||
Book bookToRegister = BookConverter.toDomain(newBook);
|
||||
Book registeredBook = bookRepository.save(bookToRegister);
|
||||
return registeredBook.getIsbn();
|
||||
}
|
||||
|
||||
public BookDTO findBookByIsbn(String isbn) throws BookNotFoundException {
|
||||
return bookRepository.findByIsbn(isbn)
|
||||
.map(BookConverter::toDTO)
|
||||
.orElseThrow(() -> new BookNotFoundException(isbn));
|
||||
}
|
||||
|
||||
public BookDTO updateBook(String isbn, BookInfo bookInfo)
|
||||
throws BookNotFoundException, NotValidBookException {
|
||||
BookValidator.validate(bookInfo);
|
||||
getBookIfDoesNotExistThrowBookNotFoundException(isbn);
|
||||
Book updated = Book.builder()
|
||||
.isbn(isbn)
|
||||
.title(bookInfo.title())
|
||||
.author(bookInfo.author())
|
||||
.publisher(bookInfo.publisher())
|
||||
.publicationDate(bookInfo.publicationDate())
|
||||
.price(bookInfo.price())
|
||||
.stock(bookInfo.stock())
|
||||
.categories(bookInfo.categories())
|
||||
.description(bookInfo.description())
|
||||
.language(bookInfo.language())
|
||||
.build();
|
||||
Book saved = bookRepository.save(updated);
|
||||
return BookConverter.toDTO(saved);
|
||||
}
|
||||
|
||||
public void deleteBook(String isbn) throws BookNotFoundException {
|
||||
Book bookToDelete = getBookIfDoesNotExistThrowBookNotFoundException(isbn);
|
||||
this.bookRepository.delete(bookToDelete);
|
||||
}
|
||||
|
||||
public int addStock(String isbn, int quantity) throws BookNotFoundException {
|
||||
Book book = getBookIfDoesNotExistThrowBookNotFoundException(isbn);
|
||||
book.addStock(quantity);
|
||||
bookRepository.save(book);
|
||||
return book.getStock();
|
||||
}
|
||||
|
||||
public int removeStock(String isbn, int quantity) throws BookNotFoundException {
|
||||
Book book = getBookIfDoesNotExistThrowBookNotFoundException(isbn);
|
||||
book.removeStock(quantity);
|
||||
bookRepository.save(book);
|
||||
return book.getStock();
|
||||
}
|
||||
|
||||
public Map<String, Object> findBooksPageSorted(int page, int size, String sortBy) {
|
||||
List<Book> allBooks = bookRepository.findAll();
|
||||
|
||||
allBooks.sort(Comparator.comparing(
|
||||
book -> {
|
||||
switch (sortBy.toLowerCase()) {
|
||||
case "titre":
|
||||
case "title":
|
||||
return book.getTitle() == null ? "" : book.getTitle().toLowerCase();
|
||||
case "auteur":
|
||||
case "author":
|
||||
return book.getAuthor() == null ? "" : book.getAuthor().toLowerCase();
|
||||
case "editeur":
|
||||
case "publisher":
|
||||
return book.getPublisher() == null ? "" : book.getPublisher().toLowerCase();
|
||||
default:
|
||||
return book.getTitle() == null ? "" : book.getTitle().toLowerCase();
|
||||
}
|
||||
},
|
||||
Comparator.naturalOrder()
|
||||
));
|
||||
|
||||
int totalElements = allBooks.size();
|
||||
int totalPages = (int) Math.ceil((double) totalElements / size);
|
||||
int fromIndex = Math.min(page * size, totalElements);
|
||||
int toIndex = Math.min(fromIndex + size, totalElements);
|
||||
|
||||
List<BookDTO> content = allBooks.subList(fromIndex, toIndex)
|
||||
.stream()
|
||||
.map(BookConverter::toDTO)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("content", content);
|
||||
result.put("totalElements", totalElements);
|
||||
result.put("totalPages", totalPages);
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<BookDTO> findBooksByTitleContaining(String title) {
|
||||
List<Book> books = bookRepository.findByTitleContaining(title);
|
||||
return books.stream().map(BookConverter::toDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<BookDTO> findBooksByAuthor(String author) {
|
||||
List<Book> books = bookRepository.findByAuthor(author);
|
||||
return books.stream().map(BookConverter::toDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<BookDTO> findBooksByPublisher(String publisher) {
|
||||
List<Book> books = bookRepository.findByPublisher(publisher);
|
||||
return books.stream().map(BookConverter::toDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<BookDTO> findBooksByCategory(Category category) {
|
||||
List<Book> books = bookRepository.findByCategory(category);
|
||||
return books.stream().map(BookConverter::toDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<BookDTO> findBooksPublishedAfter(LocalDate date) {
|
||||
List<Book> books = bookRepository.findPublishedAfter(date);
|
||||
return books.stream().map(BookConverter::toDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<BookDTO> findBooksByPriceRange(double min, double max) {
|
||||
List<Book> books = bookRepository.findByPriceRange(min, max);
|
||||
return books.stream().map(BookConverter::toDTO).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Book getBookIfDoesNotExistThrowBookNotFoundException(String isbn) {
|
||||
return bookRepository.findByIsbn(isbn)
|
||||
.orElseThrow(() -> new BookNotFoundException(isbn));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
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.exception.NotValidBookException;
|
||||
|
||||
public final class BookValidator {
|
||||
|
||||
public static final String ISBN_CANNOT_BE_NULL = "L'ISBN ne peut pas être nul";
|
||||
public static final String TITLE_CANNOT_BE_BLANK = "Le titre ne peut pas être vide";
|
||||
public static final String AUTHOR_CANNOT_BE_BLANK = "L'auteur ne peut pas être vide";
|
||||
public static final String PRICE_MUST_BE_POSITIVE = "Le prix doit être positif";
|
||||
public static final String STOCK_CANNOT_BE_NEGATIVE = "Le stock ne peut pas être négatif";
|
||||
public static final String ISBN_IS_NOT_VALID = "L'ISBN n'est pas valide";
|
||||
public static final String PUBLISHER_CANNOT_BE_BLANK = "L'éditeur ne peut pas être vide";
|
||||
public static final String PUBLICATION_DATE_CANNOT_BE_NULL = "La date de publication ne peut pas être nulle";
|
||||
public static final String CATEGORIES_CANNOT_BE_EMPTY = "La liste des catégories ne peut pas être vide";
|
||||
public static final String DESCRIPTION_CANNOT_BE_BLANK = "La description ne peut pas être vide";
|
||||
public static final String LANGUAGE_CANNOT_BE_BLANK = "La langue ne peut pas être vide";
|
||||
|
||||
private BookValidator() {}
|
||||
|
||||
public static void validate(BookInfo bookInfo) throws NotValidBookException {
|
||||
validateIsbn(bookInfo);
|
||||
validateTitle(bookInfo);
|
||||
validateAuthor(bookInfo);
|
||||
validatePrice(bookInfo);
|
||||
validateStock(bookInfo);
|
||||
}
|
||||
|
||||
private static void validateIsbn(BookInfo bookInfo) throws NotValidBookException {
|
||||
if (bookInfo.isbn() == null) {
|
||||
throw new NotValidBookException(ISBN_CANNOT_BE_NULL);
|
||||
}
|
||||
if (!bookInfo.isbn().matches("\\d{13}")) {
|
||||
throw new NotValidBookException(ISBN_IS_NOT_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateTitle(BookInfo bookInfo) throws NotValidBookException {
|
||||
if (bookInfo.title() == null || bookInfo.title().isBlank()) {
|
||||
throw new NotValidBookException(TITLE_CANNOT_BE_BLANK);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateAuthor(BookInfo bookInfo) throws NotValidBookException {
|
||||
if (bookInfo.author() == null || bookInfo.author().isBlank()) {
|
||||
throw new NotValidBookException(AUTHOR_CANNOT_BE_BLANK);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validatePrice(BookInfo bookInfo) throws NotValidBookException {
|
||||
if (bookInfo.price() < 0) {
|
||||
throw new NotValidBookException(PRICE_MUST_BE_POSITIVE);
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateStock(BookInfo bookInfo) throws NotValidBookException {
|
||||
if (bookInfo.stock() < 0) {
|
||||
throw new NotValidBookException(STOCK_CANNOT_BE_NEGATIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,16 @@ package fr.iut_fbleau.but3.dev62.mylibrary.customer.converter;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.customer.CustomerDTO;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.customer.CustomerInfo;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class CustomerConverter {
|
||||
private CustomerConverter() {
|
||||
|
||||
// util class
|
||||
}
|
||||
|
||||
public static Customer toDomain(CustomerInfo newCustomer) {
|
||||
return Customer.builder()
|
||||
.id(UUID.randomUUID()) // ← génération automatique
|
||||
.firstName(newCustomer.firstName())
|
||||
.lastName(newCustomer.lastName())
|
||||
.phoneNumber(newCustomer.phoneNumber())
|
||||
|
||||
@@ -20,26 +20,34 @@ public final class CustomerRepository {
|
||||
}
|
||||
|
||||
public Customer save(Customer newCustomer) {
|
||||
Optional<Customer> optionalCustomerWithSameId = this.findById(newCustomer.getId());
|
||||
optionalCustomerWithSameId.ifPresentOrElse(customers::remove, newCustomer::setRandomUUID);
|
||||
|
||||
if (newCustomer.getId() == null) {
|
||||
newCustomer.setRandomUUID();
|
||||
}
|
||||
|
||||
this.findById(newCustomer.getId()).ifPresent(customers::remove);
|
||||
|
||||
this.customers.add(newCustomer);
|
||||
return newCustomer;
|
||||
}
|
||||
|
||||
public Optional<Customer> findById(UUID uuid) {
|
||||
if (uuid == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return this.customers.stream()
|
||||
.filter(customer -> customer.getId().equals(uuid))
|
||||
.filter(c -> uuid.equals(c.getId()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public boolean existsById(UUID uuid) {
|
||||
return this.customers.stream()
|
||||
.anyMatch(customer -> customer.getId().equals(uuid));
|
||||
return uuid != null && this.customers.stream()
|
||||
.anyMatch(c -> uuid.equals(c.getId()));
|
||||
}
|
||||
|
||||
public Optional<Customer> findByPhoneNumber(String phoneNumber) {
|
||||
return this.customers.stream()
|
||||
.filter(customer -> customer.getPhoneNumber().equals(phoneNumber))
|
||||
.filter(c -> c.getPhoneNumber().equals(phoneNumber))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class AddressDTO {
|
||||
private final String street;
|
||||
private final String city;
|
||||
private final String postalCode;
|
||||
private final String country;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class OrderDTO {
|
||||
private final UUID id;
|
||||
private final UUID customerId;
|
||||
private final String paymentMethod;
|
||||
private final List<OrderLineDTO> orderLines;
|
||||
private final AddressDTO shippingAddress;
|
||||
private final double totalPrice;
|
||||
private final double totalPriceToPay;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
public class OrderInfo {
|
||||
private String customerId;
|
||||
private String paymentMethod;
|
||||
private List<OrderLineDTO> orderLines;
|
||||
private AddressDTO address;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class OrderLineDTO {
|
||||
private final String bookId;
|
||||
private final int quantity;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order;
|
||||
|
||||
public enum PaymentMethod {
|
||||
CREDIT_CARD,
|
||||
LOYALTY_POINTS;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.converter;
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.*;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Address;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.OrderLine;
|
||||
import java.util.UUID;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class OrderConverter {
|
||||
|
||||
private OrderConverter() {
|
||||
throw new AssertionError("Cette classe utilitaire ne doit pas être instanciée");
|
||||
}
|
||||
|
||||
public static Order toDomain(OrderInfo info) {
|
||||
if (info == null) return null;
|
||||
|
||||
return Order.builder()
|
||||
.customerId(Optional.ofNullable(info.getCustomerId())
|
||||
.map(UUID::fromString)
|
||||
.orElse(null))
|
||||
.paymentMethod(Optional.ofNullable(info.getPaymentMethod())
|
||||
.map(PaymentMethod::valueOf)
|
||||
.orElse(null))
|
||||
.orderLines(convertOrderLines(info.getOrderLines()))
|
||||
.shippingAddress(convertAddress(info.getAddress()))
|
||||
.totalPrice(0.0)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static OrderDTO toDTO(Order order) {
|
||||
if (order == null) return null;
|
||||
|
||||
return OrderDTO.builder()
|
||||
.id(order.getId())
|
||||
.customerId(order.getCustomerId())
|
||||
.paymentMethod(Optional.ofNullable(order.getPaymentMethod())
|
||||
.map(PaymentMethod::name)
|
||||
.orElse(null))
|
||||
.orderLines(convertOrderLinesToDTO(order.getOrderLines()))
|
||||
.shippingAddress(convertAddressToDTO(order.getShippingAddress()))
|
||||
.totalPrice(order.getTotalPrice())
|
||||
.totalPriceToPay(order.getTotalPriceToPay())
|
||||
.build();
|
||||
}
|
||||
|
||||
private static List<OrderLine> convertOrderLines(List<OrderLineDTO> orderLines) {
|
||||
return Optional.ofNullable(orderLines)
|
||||
.map(lines -> lines.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(line -> OrderLine.builder()
|
||||
.bookId(line.getBookId())
|
||||
.quantity(line.getQuantity())
|
||||
.build())
|
||||
.toList())
|
||||
.orElse(new ArrayList<>());
|
||||
}
|
||||
|
||||
private static List<OrderLineDTO> convertOrderLinesToDTO(List<OrderLine> orderLines) {
|
||||
return Optional.ofNullable(orderLines)
|
||||
.map(lines -> lines.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(line -> OrderLineDTO.builder()
|
||||
.bookId(line.getBookId())
|
||||
.quantity(line.getQuantity())
|
||||
.build())
|
||||
.toList())
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static Address convertAddress(AddressDTO addressDTO) {
|
||||
return Optional.ofNullable(addressDTO)
|
||||
.map(addr -> Address.builder()
|
||||
.street(addr.getStreet())
|
||||
.city(addr.getCity())
|
||||
.postalCode(addr.getPostalCode())
|
||||
.country(addr.getCountry())
|
||||
.build())
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static AddressDTO convertAddressToDTO(Address address) {
|
||||
return Optional.ofNullable(address)
|
||||
.map(addr -> AddressDTO.builder()
|
||||
.street(addr.getStreet())
|
||||
.city(addr.getCity())
|
||||
.postalCode(addr.getPostalCode())
|
||||
.country(addr.getCountry())
|
||||
.build())
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.entity;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class Address {
|
||||
private final String street;
|
||||
private final String city;
|
||||
private final String postalCode;
|
||||
private final String country;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.entity;
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.PaymentMethod;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
public class Order {
|
||||
private final UUID id;
|
||||
private final UUID customerId;
|
||||
private final PaymentMethod paymentMethod;
|
||||
private final List<OrderLine> orderLines;
|
||||
private final Address shippingAddress;
|
||||
private final double totalPrice;
|
||||
private final double totalPriceToPay;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.entity;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
@Getter
|
||||
@Builder
|
||||
public class OrderLine {
|
||||
private final String bookId;
|
||||
private final int quantity;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
|
||||
|
||||
public class IllegalOrderPointException extends RuntimeException {
|
||||
public IllegalOrderPointException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
|
||||
|
||||
public class InvalidPaymentMethodException extends RuntimeException {
|
||||
public InvalidPaymentMethodException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
|
||||
|
||||
public class NotValidOrderException extends RuntimeException {
|
||||
public NotValidOrderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
|
||||
|
||||
public class OrderNotFoundException extends RuntimeException {
|
||||
public OrderNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
|
||||
|
||||
public class OrderQuantityException extends RuntimeException {
|
||||
public OrderQuantityException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.exception;
|
||||
|
||||
public class WrongAddressException extends RuntimeException {
|
||||
public WrongAddressException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.repository;
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
|
||||
import java.util.*;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
public final class OrderRepository {
|
||||
private final List<Order> orders = new ArrayList<>();
|
||||
|
||||
public Order save(Order newOrder) {
|
||||
if (newOrder.getId() == null) {
|
||||
Order orderWithId = Order.builder()
|
||||
.id(UUID.randomUUID())
|
||||
.customerId(newOrder.getCustomerId())
|
||||
.paymentMethod(newOrder.getPaymentMethod())
|
||||
.orderLines(newOrder.getOrderLines())
|
||||
.shippingAddress(newOrder.getShippingAddress())
|
||||
.totalPrice(newOrder.getTotalPrice())
|
||||
.totalPriceToPay(newOrder.getTotalPriceToPay())
|
||||
.build();
|
||||
this.orders.add(orderWithId);
|
||||
return orderWithId;
|
||||
}
|
||||
|
||||
Optional<Order> optionalOrderWithSameId = this.findById(newOrder.getId());
|
||||
optionalOrderWithSameId.ifPresent(orders::remove);
|
||||
this.orders.add(newOrder);
|
||||
return newOrder;
|
||||
}
|
||||
|
||||
public Optional<Order> findById(UUID id) {
|
||||
return this.orders.stream()
|
||||
.filter(order -> Objects.equals(order.getId(), id))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public boolean existsById(UUID id) {
|
||||
return this.orders.stream()
|
||||
.anyMatch(order -> Objects.equals(order.getId(), id));
|
||||
}
|
||||
|
||||
public List<Order> findByCustomerId(UUID customerId) {
|
||||
return this.orders.stream()
|
||||
.filter(order -> Objects.equals(order.getCustomerId(), customerId))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public List<Order> findAll() {
|
||||
return orders;
|
||||
}
|
||||
|
||||
public void deleteAll() {
|
||||
orders.clear();
|
||||
}
|
||||
|
||||
public void delete(Order order) {
|
||||
this.orders.remove(order);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.usecase;
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.BookNotFoundException;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.IllegalCustomerPointException;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.PaymentMethod;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.converter.OrderConverter;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.*;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class OrderUseCase {
|
||||
private final OrderRepository orderRepository;
|
||||
private final CustomerRepository customerRepository;
|
||||
private final BookRepository bookRepository;
|
||||
|
||||
public OrderUseCase(OrderRepository orderRepository, CustomerRepository customerRepository, BookRepository bookRepository) {
|
||||
this.orderRepository = orderRepository;
|
||||
this.customerRepository = customerRepository;
|
||||
this.bookRepository = bookRepository;
|
||||
}
|
||||
|
||||
public UUID createOrder(OrderInfo orderInfo) throws CustomerNotFoundException, IllegalCustomerPointException, NotValidOrderException {
|
||||
validateOrderInfo(orderInfo);
|
||||
|
||||
PaymentMethod paymentMethod = parsePaymentMethod(orderInfo.getPaymentMethod());
|
||||
UUID customerId = parseCustomerId(orderInfo.getCustomerId());
|
||||
Customer customer = customerRepository.findById(customerId)
|
||||
.orElseThrow(() -> new CustomerNotFoundException(customerId));
|
||||
|
||||
// Pré-chargement des livres pour éviter les appels multiples
|
||||
Map<String, fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book> books = orderInfo.getOrderLines().stream()
|
||||
.map(line -> bookRepository.findByIsbn(line.getBookId())
|
||||
.orElseThrow(() -> new BookNotFoundException("Le livre avec l'ISBN " + line.getBookId() + " n'a pas été trouvé")))
|
||||
.collect(Collectors.toMap(fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book::getIsbn, b -> b));
|
||||
|
||||
validateOrderLines(orderInfo, books);
|
||||
|
||||
double totalPrice = calculateTotalPrice(orderInfo, books);
|
||||
double totalPriceToPay = calculateTotalPriceToPay(orderInfo, books);
|
||||
|
||||
Order domainOrder = OrderConverter.toDomain(orderInfo);
|
||||
Order order = Order.builder()
|
||||
.customerId(customerId)
|
||||
.paymentMethod(paymentMethod)
|
||||
.orderLines(domainOrder.getOrderLines())
|
||||
.shippingAddress(domainOrder.getShippingAddress())
|
||||
.totalPrice(totalPrice)
|
||||
.totalPriceToPay(totalPriceToPay)
|
||||
.build();
|
||||
|
||||
if (paymentMethod == PaymentMethod.LOYALTY_POINTS) {
|
||||
handleLoyaltyPointsPayment(customer, totalPrice);
|
||||
}
|
||||
|
||||
return orderRepository.save(order).getId();
|
||||
}
|
||||
|
||||
private void validateOrderInfo(OrderInfo orderInfo) throws NotValidOrderException {
|
||||
if (orderInfo == null) {
|
||||
throw new NotValidOrderException("La commande ne peut pas être nulle");
|
||||
}
|
||||
if (orderInfo.getOrderLines() == null || orderInfo.getOrderLines().isEmpty()) {
|
||||
throw new OrderQuantityException("La commande doit contenir au moins un livre");
|
||||
}
|
||||
if (orderInfo.getAddress() == null) {
|
||||
throw new NotValidOrderException("L'adresse de livraison est obligatoire");
|
||||
}
|
||||
}
|
||||
|
||||
private PaymentMethod parsePaymentMethod(String paymentMethod) {
|
||||
try {
|
||||
return PaymentMethod.valueOf(paymentMethod);
|
||||
} catch (IllegalArgumentException | NullPointerException e) {
|
||||
throw new InvalidPaymentMethodException("Le mode de paiement " + paymentMethod + " n'est pas valide");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateOrderLines(OrderInfo orderInfo, Map<String, fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book> books) {
|
||||
orderInfo.getOrderLines().forEach(line -> {
|
||||
if (line.getQuantity() <= 0) {
|
||||
throw new OrderQuantityException("La quantité doit être supérieure à 0 pour le livre " + line.getBookId());
|
||||
}
|
||||
var book = books.get(line.getBookId());
|
||||
if (book.getStock() < line.getQuantity()) {
|
||||
throw new OrderQuantityException("Stock insuffisant pour le livre " + line.getBookId());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private double calculateTotalPrice(OrderInfo orderInfo, Map<String, fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book> books) {
|
||||
return orderInfo.getOrderLines().stream()
|
||||
.mapToDouble(line -> books.get(line.getBookId()).getPrice() * line.getQuantity())
|
||||
.sum();
|
||||
}
|
||||
|
||||
private double calculateTotalPriceToPay(OrderInfo orderInfo, Map<String, fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book> books) {
|
||||
// Appliquer ici les éventuelles remises
|
||||
return calculateTotalPrice(orderInfo, books);
|
||||
}
|
||||
|
||||
private UUID parseOrderId(String orderId) {
|
||||
try {
|
||||
return UUID.fromString(orderId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new OrderNotFoundException("La commande avec l'ID " + orderId + " n'a pas été trouvée");
|
||||
}
|
||||
}
|
||||
|
||||
public OrderDTO findOrderById(String orderId) {
|
||||
UUID uuid = parseOrderId(orderId);
|
||||
return orderRepository.findById(uuid)
|
||||
.map(OrderConverter::toDTO)
|
||||
.orElseThrow(() -> new OrderNotFoundException("La commande n'a pas été trouvée"));
|
||||
}
|
||||
|
||||
public List<OrderDTO> findOrdersByCustomerId(String customerId) throws CustomerNotFoundException {
|
||||
UUID uuid = parseCustomerId(customerId);
|
||||
customerRepository.findById(uuid)
|
||||
.orElseThrow(() -> new CustomerNotFoundException(uuid));
|
||||
return orderRepository.findByCustomerId(uuid)
|
||||
.stream()
|
||||
.map(OrderConverter::toDTO)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private UUID parseCustomerId(String customerId) throws CustomerNotFoundException {
|
||||
if (customerId == null || customerId.trim().isEmpty()) {
|
||||
throw new CustomerNotFoundException(null);
|
||||
}
|
||||
try {
|
||||
return UUID.fromString(customerId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new CustomerNotFoundException(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLoyaltyPointsPayment(Customer customer, double totalPrice) throws IllegalCustomerPointException {
|
||||
int requiredPoints = (int) (totalPrice * 100);
|
||||
if (customer.getLoyaltyPoints() < requiredPoints) {
|
||||
throw new IllegalOrderPointException("Points de fidélité insuffisants pour payer la commande");
|
||||
}
|
||||
customer.removeLoyaltyPoints(requiredPoints);
|
||||
customerRepository.save(customer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.order.validator;
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Address;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException;
|
||||
|
||||
public class OrderValidator {
|
||||
|
||||
public static void validate(Order order) {
|
||||
if (order == null) {
|
||||
throw new NotValidOrderException("La commande ne peut pas être nulle");
|
||||
}
|
||||
validateAddress(order);
|
||||
validateOrderLines(order);
|
||||
validatePrices(order);
|
||||
validatePaymentMethod(order);
|
||||
}
|
||||
|
||||
private static void validateAddress(Order order) {
|
||||
Address address = order.getShippingAddress();
|
||||
if (address == null) {
|
||||
throw new NotValidOrderException("L'adresse de livraison est obligatoire");
|
||||
}
|
||||
|
||||
if (isNullOrBlank(address.getStreet()) ||
|
||||
isNullOrBlank(address.getCity()) ||
|
||||
isNullOrBlank(address.getPostalCode()) ||
|
||||
isNullOrBlank(address.getCountry())) {
|
||||
throw new NotValidOrderException("Tous les champs de l'adresse sont obligatoires");
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateOrderLines(Order order) {
|
||||
if (order.getOrderLines() == null || order.getOrderLines().isEmpty()) {
|
||||
throw new NotValidOrderException("La commande doit contenir au moins une ligne");
|
||||
}
|
||||
|
||||
order.getOrderLines().forEach(line -> {
|
||||
if (line.getQuantity() <= 0) {
|
||||
throw new NotValidOrderException("La quantité doit être positive");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void validatePrices(Order order) {
|
||||
if (order.getTotalPrice() <= 0) {
|
||||
throw new NotValidOrderException("Le prix total doit être positif");
|
||||
}
|
||||
if (order.getTotalPriceToPay() <= 0) {
|
||||
throw new NotValidOrderException("Le prix total à payer doit être positif");
|
||||
}
|
||||
if (order.getTotalPriceToPay() > order.getTotalPrice()) {
|
||||
throw new NotValidOrderException("Le prix à payer ne peut pas être supérieur au prix total");
|
||||
}
|
||||
}
|
||||
|
||||
private static void validatePaymentMethod(Order order) {
|
||||
if (order.getPaymentMethod() == null) {
|
||||
throw new NotValidOrderException("Le mode de paiement ne peut pas être nul");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isNullOrBlank(String value) {
|
||||
return value == null || value.trim().isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.review;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class ReviewDto {
|
||||
private final UUID reviewId;
|
||||
private final long bookId;
|
||||
private final String customerName;
|
||||
private final String comment;
|
||||
private final int rating;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.review;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class ReviewInfo {
|
||||
private final String customerId;
|
||||
private final long isbn;
|
||||
private final int rating;
|
||||
private final String comment;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.review.converter;
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.ReviewDto;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.ReviewInfo;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.entity.Review;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ReviewConverter {
|
||||
public static ReviewDto toDto(Review review, UUID reviewId, String customerName) {
|
||||
return ReviewDto.builder()
|
||||
.reviewId(reviewId)
|
||||
.bookId(review.getIsbn())
|
||||
.customerName(customerName)
|
||||
.comment(review.getComment())
|
||||
.rating(review.getRating())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Review toDomain(ReviewInfo info) {
|
||||
return Review.builder()
|
||||
.customerId(UUID.fromString(info.getCustomerId()))
|
||||
.isbn(info.getIsbn())
|
||||
.rating(info.getRating())
|
||||
.comment(info.getComment())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.review.entity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Review {
|
||||
private UUID customerId;
|
||||
private long isbn;
|
||||
private int rating;
|
||||
private String comment;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.review.exception;
|
||||
|
||||
public class InvalidReviewRatingException extends RuntimeException {
|
||||
public InvalidReviewRatingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.review.exception;
|
||||
|
||||
public class ReviewAlreadyExistsException extends RuntimeException {
|
||||
public ReviewAlreadyExistsException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.review.exception;
|
||||
|
||||
public class ReviewNotFoundException extends RuntimeException {
|
||||
public ReviewNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.review.repository;
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.entity.Review;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ReviewRepository {
|
||||
private final List<Review> reviews = new ArrayList<>();
|
||||
|
||||
public void save(Review review) {
|
||||
reviews.add(review);
|
||||
}
|
||||
|
||||
public List<Review> findAll() {
|
||||
return new ArrayList<>(reviews);
|
||||
}
|
||||
|
||||
public List<Review> findByIsbn(long isbn) {
|
||||
return reviews.stream().filter(r -> r.getIsbn() == isbn).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<Review> findByCustomerId(UUID customerId) {
|
||||
return reviews.stream().filter(r -> r.getCustomerId().equals(customerId)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public boolean existsByCustomerIdAndIsbn(UUID customerId, long isbn) {
|
||||
return reviews.stream().anyMatch(r -> r.getCustomerId().equals(customerId) && r.getIsbn() == isbn);
|
||||
}
|
||||
|
||||
public void deleteByCustomerIdAndIsbn(UUID customerId, long isbn) {
|
||||
reviews.removeIf(r -> r.getCustomerId().equals(customerId) && r.getIsbn() == isbn);
|
||||
}
|
||||
|
||||
public void update(Review review) {
|
||||
deleteByCustomerIdAndIsbn(review.getCustomerId(), review.getIsbn());
|
||||
save(review);
|
||||
}
|
||||
|
||||
public void deleteAll() {
|
||||
reviews.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.review.usecase;
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.entity.Review;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.exception.InvalidReviewRatingException;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.exception.ReviewAlreadyExistsException;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.exception.ReviewNotFoundException;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.BookNotFoundException;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.repository.ReviewRepository;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.validator.ReviewValidator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ReviewUseCase {
|
||||
private final ReviewRepository reviewRepository;
|
||||
private final BookRepository bookRepository;
|
||||
private final CustomerRepository customerRepository;
|
||||
|
||||
public ReviewUseCase(ReviewRepository reviewRepository, BookRepository bookRepository, CustomerRepository customerRepository) {
|
||||
this.reviewRepository = reviewRepository;
|
||||
this.bookRepository = bookRepository;
|
||||
this.customerRepository = customerRepository;
|
||||
}
|
||||
|
||||
public void submitReview(Review review) throws CustomerNotFoundException {
|
||||
ReviewValidator.validate(review);
|
||||
|
||||
if (!bookRepository.existsByIsbn(String.valueOf(review.getIsbn()))) {
|
||||
throw new BookNotFoundException("Book not found: " + review.getIsbn());
|
||||
}
|
||||
|
||||
if (!customerRepository.existsById(review.getCustomerId())) {
|
||||
throw new CustomerNotFoundException(review.getCustomerId());
|
||||
}
|
||||
|
||||
if (reviewRepository.existsByCustomerIdAndIsbn(review.getCustomerId(), review.getIsbn())) {
|
||||
throw new ReviewAlreadyExistsException("Review already exists for this customer and book.");
|
||||
}
|
||||
|
||||
reviewRepository.save(review);
|
||||
}
|
||||
|
||||
public List<Review> getReviewsByBook(long isbn) {
|
||||
return reviewRepository.findByIsbn(isbn);
|
||||
}
|
||||
|
||||
public List<Review> getReviewsByCustomer(UUID customerId) {
|
||||
return reviewRepository.findByCustomerId(customerId);
|
||||
}
|
||||
|
||||
public void updateReview(Review review) {
|
||||
ReviewValidator.validate(review);
|
||||
if (!reviewRepository.existsByCustomerIdAndIsbn(review.getCustomerId(), review.getIsbn())) {
|
||||
throw new ReviewNotFoundException("Review not found for this customer and book.");
|
||||
}
|
||||
reviewRepository.update(review);
|
||||
}
|
||||
|
||||
public void deleteReview(long isbn, UUID customerId) {
|
||||
if (!reviewRepository.existsByCustomerIdAndIsbn(customerId, isbn)) {
|
||||
throw new ReviewNotFoundException("Review not found for this customer and book.");
|
||||
}
|
||||
reviewRepository.deleteByCustomerIdAndIsbn(customerId, isbn);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.review.validator;
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.review.entity.Review;
|
||||
|
||||
public class ReviewValidator {
|
||||
public static void validate(Review review) {
|
||||
if (review == null) {
|
||||
throw new IllegalArgumentException("Review cannot be null");
|
||||
}
|
||||
if (review.getRating() < 1 || review.getRating() > 5) {
|
||||
throw new fr.iut_fbleau.but3.dev62.mylibrary.review.exception.InvalidReviewRatingException("Rating must be between 1 and 5");
|
||||
}
|
||||
if (review.getComment() == null || review.getComment().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Comment cannot be empty");
|
||||
}
|
||||
if (review.getCustomerId() == null) {
|
||||
throw new IllegalArgumentException("CustomerId cannot be null");
|
||||
}
|
||||
if (review.getIsbn() <= 0) {
|
||||
throw new IllegalArgumentException("ISBN must be positive");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.subscription;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import java.util.UUID;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class SubscriptionDTO {
|
||||
private final UUID id;
|
||||
private final UUID customerId;
|
||||
private final Integer duration;
|
||||
private final String paymentMethod;
|
||||
private final String debutDate;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.subscription;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record SubscriptionInfo(UUID customerId, Integer duration, String paymentMethod) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.converter;
|
||||
|
||||
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionDTO;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.SubscriptionInfo;
|
||||
import fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity.Subscription;
|
||||
|
||||
public final class SubscriptionConverter {
|
||||
private SubscriptionConverter() {
|
||||
|
||||
}
|
||||
|
||||
public static Subscription toDomain(SubscriptionInfo newSubscription) {
|
||||
return Subscription.builder()
|
||||
.customerId(newSubscription.customerId())
|
||||
.duration(newSubscription.duration())
|
||||
.paymentMethod(newSubscription.paymentMethod())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static SubscriptionDTO toDTO(Subscription subscription) {
|
||||
return SubscriptionDTO.builder()
|
||||
.id(subscription.getId())
|
||||
.customerId(subscription.getCustomerId())
|
||||
.duration(subscription.getDuration())
|
||||
.paymentMethod(subscription.getPaymentMethod())
|
||||
.debutDate(subscription.getDebutDate())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.entity;
|
||||
|
||||
import java.util.UUID;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class Subscription {
|
||||
private UUID id;
|
||||
private UUID customerId;
|
||||
private Integer duration;
|
||||
private String paymentMethod;
|
||||
private String debutDate;
|
||||
|
||||
public void setRandomUUID() {
|
||||
this.id = UUID.randomUUID();
|
||||
}
|
||||
|
||||
public void setDebutDate(String debutDate) {
|
||||
this.debutDate = LocalDate.now().toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package fr.iut_fbleau.but3.dev62.mylibrary.subscription.exception;
|
||||
|
||||
public class NotValidSubscriptionException extends Exception {
|
||||
|
||||
public NotValidSubscriptionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user