diff --git a/src/main/java/kitchenpos/products/tobe/application/ProductService.java b/src/main/java/kitchenpos/products/tobe/application/ProductService.java new file mode 100644 index 000000000..71cee48f6 --- /dev/null +++ b/src/main/java/kitchenpos/products/tobe/application/ProductService.java @@ -0,0 +1,81 @@ +package kitchenpos.products.tobe.application; + +import kitchenpos.menus.domain.Menu; +import kitchenpos.menus.domain.MenuProduct; +import kitchenpos.menus.domain.MenuRepository; +import kitchenpos.products.domain.Product; +import kitchenpos.products.domain.ProductRepository; +import kitchenpos.products.infra.PurgomalumClient; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.UUID; + +@Service +public class ProductService { + private final ProductRepository productRepository; + private final MenuRepository menuRepository; + private final PurgomalumClient purgomalumClient; + + public ProductService( + final ProductRepository productRepository, + final MenuRepository menuRepository, + final PurgomalumClient purgomalumClient + ) { + this.productRepository = productRepository; + this.menuRepository = menuRepository; + this.purgomalumClient = purgomalumClient; + } + + @Transactional + public Product create(final Product request) { + final BigDecimal price = request.getPrice(); + if (Objects.isNull(price) || price.compareTo(BigDecimal.ZERO) < 0) { + throw new IllegalArgumentException(); + } + final String name = request.getName(); + if (Objects.isNull(name) || purgomalumClient.containsProfanity(name)) { + throw new IllegalArgumentException(); + } + final Product product = new Product(); + product.setId(UUID.randomUUID()); + product.setName(name); + product.setPrice(price); + return productRepository.save(product); + } + + @Transactional + public Product changePrice(final UUID productId, final Product request) { + final BigDecimal price = request.getPrice(); + if (Objects.isNull(price) || price.compareTo(BigDecimal.ZERO) < 0) { + throw new IllegalArgumentException(); + } + final Product product = productRepository.findById(productId) + .orElseThrow(NoSuchElementException::new); + product.setPrice(price); + final List menus = menuRepository.findAllByProductId(productId); + for (final Menu menu : menus) { + BigDecimal sum = BigDecimal.ZERO; + for (final MenuProduct menuProduct : menu.getMenuProducts()) { + sum = sum.add( + menuProduct.getProduct() + .getPrice() + .multiply(BigDecimal.valueOf(menuProduct.getQuantity())) + ); + } + if (menu.getPrice().compareTo(sum) > 0) { + menu.setDisplayed(false); + } + } + return product; + } + + @Transactional(readOnly = true) + public List findAll() { + return productRepository.findAll(); + } +} diff --git a/src/main/java/kitchenpos/products/tobe/domain/Name.java b/src/main/java/kitchenpos/products/tobe/domain/Name.java new file mode 100644 index 000000000..a1251263f --- /dev/null +++ b/src/main/java/kitchenpos/products/tobe/domain/Name.java @@ -0,0 +1,26 @@ +package kitchenpos.products.tobe.domain; + +import java.util.Objects; + +import jakarta.persistence.Embeddable; +import kitchenpos.products.infra.PurgomalumClient; +@Embeddable +public class Name { + private final String name; + private final PurgomalumClient purgomalumClient; + + public Name(final String name, final PurgomalumClient purgomalumClient) { + this.purgomalumClient = Objects.requireNonNull(purgomalumClient, "purgomalumClient must not be null"); + validate(name); + this.name = name; + } + + private void validate(final String name) { + if (Objects.isNull(name) || name.isEmpty() || purgomalumClient.containsProfanity(name)) { + throw new IllegalArgumentException(); + } + } + public String getName() { + return name; + } +} diff --git a/src/main/java/kitchenpos/products/tobe/domain/Price.java b/src/main/java/kitchenpos/products/tobe/domain/Price.java new file mode 100644 index 000000000..230106100 --- /dev/null +++ b/src/main/java/kitchenpos/products/tobe/domain/Price.java @@ -0,0 +1,24 @@ +package kitchenpos.products.tobe.domain; + +import jakarta.persistence.Embeddable; + +import java.math.BigDecimal; +import java.util.Objects; +@Embeddable +public class Price { + private final BigDecimal price; + + public Price(BigDecimal price) { + validate(price); + this.price = price; + } + + private void validate(final BigDecimal price) { + if (Objects.isNull(price) || price.compareTo(BigDecimal.ZERO) < 0) { + throw new IllegalArgumentException(); + } + } + public BigDecimal getPrice() { + return price; + } +} diff --git a/src/main/java/kitchenpos/products/tobe/domain/Product.java b/src/main/java/kitchenpos/products/tobe/domain/Product.java new file mode 100644 index 000000000..b6ee0d43f --- /dev/null +++ b/src/main/java/kitchenpos/products/tobe/domain/Product.java @@ -0,0 +1,34 @@ +package kitchenpos.products.tobe.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Id; +import kitchenpos.products.tobe.persistence.ProductEntity; + +import java.util.UUID; + +public class Product { + private final UUID id; + + private final Name name; + + private final Price price; + + public Product(UUID id, Name name, Price price) { + this.id = id; + this.name = name; + this.price = price; + } + + public UUID getId() { + return id; + } + + public Name getName() { + return name; + } + + public Price getPrice() { + return price; + } +} diff --git a/src/main/java/kitchenpos/products/tobe/domain/ProductRepository.java b/src/main/java/kitchenpos/products/tobe/domain/ProductRepository.java new file mode 100644 index 000000000..8be1bb392 --- /dev/null +++ b/src/main/java/kitchenpos/products/tobe/domain/ProductRepository.java @@ -0,0 +1,15 @@ +package kitchenpos.products.tobe.domain; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +public interface ProductRepository { + Product save(Product product); + + Optional findById(UUID id); + + List findAll(); + + List findAllByIdIn(List ids); +} diff --git a/src/main/java/kitchenpos/products/tobe/persistence/JpaProductRepository.java b/src/main/java/kitchenpos/products/tobe/persistence/JpaProductRepository.java new file mode 100644 index 000000000..c9d79c774 --- /dev/null +++ b/src/main/java/kitchenpos/products/tobe/persistence/JpaProductRepository.java @@ -0,0 +1,9 @@ +package kitchenpos.products.tobe.persistence; + +import kitchenpos.products.tobe.persistence.ProductEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.UUID; + +public interface JpaProductRepository extends JpaRepository { +} diff --git a/src/main/java/kitchenpos/products/tobe/persistence/JpaProductRepositoryImpl.java b/src/main/java/kitchenpos/products/tobe/persistence/JpaProductRepositoryImpl.java new file mode 100644 index 000000000..9cdf7766f --- /dev/null +++ b/src/main/java/kitchenpos/products/tobe/persistence/JpaProductRepositoryImpl.java @@ -0,0 +1,48 @@ +package kitchenpos.products.tobe.persistence; + +import kitchenpos.products.tobe.domain.Product; +import kitchenpos.products.tobe.domain.ProductRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +@Repository +public class JpaProductRepositoryImpl implements ProductRepository { + + private final JpaProductRepository jpaProductRepository; + + public JpaProductRepositoryImpl(JpaProductRepository jpaProductRepository) { + this.jpaProductRepository = jpaProductRepository; + } + + @Override + public Product save(Product product) { + ProductEntity productEntity = new ProductEntity(product); + return jpaProductRepository.save(productEntity).toDomain(); + } + + @Override + public Optional findById(UUID id) { + Optional productEntity = jpaProductRepository.findById(id); + return productEntity.map(ProductEntity::toDomain); + } + + @Override + public List findAll() { + return jpaProductRepository.findAll() + .stream() + .map(ProductEntity::toDomain) + .collect(Collectors.toList()); + } + + @Override + public List findAllByIdIn(List ids) { + return jpaProductRepository.findAllById(ids) + .stream() + .map(ProductEntity::toDomain) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/kitchenpos/products/tobe/persistence/ProductEntity.java b/src/main/java/kitchenpos/products/tobe/persistence/ProductEntity.java new file mode 100644 index 000000000..2c39e408e --- /dev/null +++ b/src/main/java/kitchenpos/products/tobe/persistence/ProductEntity.java @@ -0,0 +1,47 @@ +package kitchenpos.products.tobe.persistence; + +import jakarta.persistence.*; +import kitchenpos.products.tobe.domain.Name; +import kitchenpos.products.tobe.domain.Price; +import kitchenpos.products.tobe.domain.Product; +import java.util.UUID; + +@Entity +@Table(name = "product") +public class ProductEntity { + + @Id + @Column(name = "id", columnDefinition = "binary(16)") + private UUID id; + + @Embedded + private Name name; + + @Embedded + private Price price; + + protected ProductEntity() { + } + + public ProductEntity(Product product) { + this.id = product.getId(); + this.name = product.getName(); + this.price = product.getPrice(); + } + + public Product toDomain() { + return new Product(id, name, price); + } + + public UUID getId() { + return id; + } + + public Name getName() { + return name; + } + + public Price getPrice() { + return price; + } +}