From 0afc62f0745f6b3877487680987ddaa793e29563 Mon Sep 17 00:00:00 2001 From: Murilo Kakazu Date: Sun, 19 May 2024 22:27:09 -0300 Subject: [PATCH] refactor: move order invariants to the entity --- ...ntSubmitOrderWithoutProductsException.java | 16 ----------- .../CompositeDomainValidationException.java | 18 ++++++++++++ .../order/AddProductToOrderUseCase.java | 5 ---- .../order/RemoveProductFromOrderUseCase.java | 5 ---- .../usecases/order/SubmitOrderUseCase.java | 5 ---- .../persistence/jpa/entities/OrderEntity.java | 28 +++++++++++++++++-- 6 files changed, 44 insertions(+), 33 deletions(-) delete mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CantSubmitOrderWithoutProductsException.java create mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CompositeDomainValidationException.java diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CantSubmitOrderWithoutProductsException.java b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CantSubmitOrderWithoutProductsException.java deleted file mode 100644 index 7b18055..0000000 --- a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CantSubmitOrderWithoutProductsException.java +++ /dev/null @@ -1,16 +0,0 @@ -package br.com.fiap.grupo30.fastfood.application.services.exceptions; - -import java.io.Serial; - -public class CantSubmitOrderWithoutProductsException extends DomainValidationException { - @Serial private static final long serialVersionUID = 1L; - private static final String MESSAGE = "Can not submit order without products"; - - public CantSubmitOrderWithoutProductsException() { - super(MESSAGE); - } - - public CantSubmitOrderWithoutProductsException(Throwable exception) { - super(MESSAGE, exception); - } -} diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CompositeDomainValidationException.java b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CompositeDomainValidationException.java new file mode 100644 index 0000000..163eeaf --- /dev/null +++ b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CompositeDomainValidationException.java @@ -0,0 +1,18 @@ +package br.com.fiap.grupo30.fastfood.application.services.exceptions; + +import java.io.Serial; +import java.util.Collection; + +public class CompositeDomainValidationException extends ResourceBadRequestException { + + @Serial private static final long serialVersionUID = 1L; + + public CompositeDomainValidationException(Collection domainErrors) { + super(String.join(", ", domainErrors)); + } + + public CompositeDomainValidationException( + Collection domainErrors, Throwable exception) { + super(String.join(", ", domainErrors), exception); + } +} diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/AddProductToOrderUseCase.java b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/AddProductToOrderUseCase.java index a196524..02ca32f 100644 --- a/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/AddProductToOrderUseCase.java +++ b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/AddProductToOrderUseCase.java @@ -1,7 +1,6 @@ package br.com.fiap.grupo30.fastfood.domain.usecases.order; import br.com.fiap.grupo30.fastfood.application.dto.OrderDTO; -import br.com.fiap.grupo30.fastfood.application.services.exceptions.CantChangeOrderProductsAfterSubmitException; import br.com.fiap.grupo30.fastfood.application.services.exceptions.ResourceNotFoundException; import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.OrderEntity; import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.ProductEntity; @@ -31,10 +30,6 @@ public OrderDTO execute(Long orderId, Long productId, Long productQuantity) { .findById(orderId) .orElseThrow(() -> new ResourceNotFoundException("Order not found")); - if (!order.isDraft()) { - throw new CantChangeOrderProductsAfterSubmitException(); - } - ProductEntity product = this.productRepository .findById(productId) diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/RemoveProductFromOrderUseCase.java b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/RemoveProductFromOrderUseCase.java index 019a0f0..6d5a618 100644 --- a/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/RemoveProductFromOrderUseCase.java +++ b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/RemoveProductFromOrderUseCase.java @@ -1,7 +1,6 @@ package br.com.fiap.grupo30.fastfood.domain.usecases.order; import br.com.fiap.grupo30.fastfood.application.dto.OrderDTO; -import br.com.fiap.grupo30.fastfood.application.services.exceptions.CantChangeOrderProductsAfterSubmitException; import br.com.fiap.grupo30.fastfood.application.services.exceptions.ResourceNotFoundException; import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.OrderEntity; import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.ProductEntity; @@ -29,10 +28,6 @@ public OrderDTO execute(Long orderId, Long productId) { .findById(orderId) .orElseThrow(() -> new ResourceNotFoundException("Order not found")); - if (!order.isDraft()) { - throw new CantChangeOrderProductsAfterSubmitException(); - } - ProductEntity product = this.productRepository .findById(productId) diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/SubmitOrderUseCase.java b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/SubmitOrderUseCase.java index 252e65e..fa548dd 100644 --- a/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/SubmitOrderUseCase.java +++ b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/SubmitOrderUseCase.java @@ -1,7 +1,6 @@ package br.com.fiap.grupo30.fastfood.domain.usecases.order; import br.com.fiap.grupo30.fastfood.application.dto.OrderDTO; -import br.com.fiap.grupo30.fastfood.application.services.exceptions.CantSubmitOrderWithoutProductsException; import br.com.fiap.grupo30.fastfood.application.services.exceptions.ResourceNotFoundException; import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.OrderEntity; import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.OrderStatus; @@ -25,10 +24,6 @@ public OrderDTO execute(Long orderId) { .findById(orderId) .orElseThrow(() -> new ResourceNotFoundException("Order not found")); - if (!order.hasProducts()) { - throw new CantSubmitOrderWithoutProductsException(); - } - order.setStatus(OrderStatus.SUBMITTED); return this.orderRepository.save(order).toDTO(); } diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/infrastructure/out/persistence/jpa/entities/OrderEntity.java b/src/main/java/br/com/fiap/grupo30/fastfood/infrastructure/out/persistence/jpa/entities/OrderEntity.java index d18f785..8a774ff 100644 --- a/src/main/java/br/com/fiap/grupo30/fastfood/infrastructure/out/persistence/jpa/entities/OrderEntity.java +++ b/src/main/java/br/com/fiap/grupo30/fastfood/infrastructure/out/persistence/jpa/entities/OrderEntity.java @@ -2,6 +2,8 @@ import br.com.fiap.grupo30.fastfood.application.dto.OrderDTO; import br.com.fiap.grupo30.fastfood.application.dto.OrderItemDTO; +import br.com.fiap.grupo30.fastfood.application.services.exceptions.CantChangeOrderProductsAfterSubmitException; +import br.com.fiap.grupo30.fastfood.application.services.exceptions.CompositeDomainValidationException; import jakarta.persistence.*; import java.time.Instant; import java.util.Collection; @@ -42,6 +44,10 @@ public class OrderEntity { private Instant deletedAt; public void addProduct(ProductEntity product, Long quantity) { + if (!this.isDraft()) { + throw new CantChangeOrderProductsAfterSubmitException(); + } + this.items.stream() .filter(orderItem -> orderItem.getProduct().equals(product)) .findFirst() @@ -54,6 +60,10 @@ public void addProduct(ProductEntity product, Long quantity) { } public void removeProduct(ProductEntity product) { + if (!this.isDraft()) { + throw new CantChangeOrderProductsAfterSubmitException(); + } + this.items.removeIf(orderItem -> orderItem.getProduct().equals(product)); this.recalculateTotalPrice(); @@ -67,11 +77,11 @@ private void recalculateTotalPrice() { this.totalPrice = this.items.stream().mapToDouble(item -> item.getTotalPrice()).sum(); } - public Boolean isDraft() { + private Boolean isDraft() { return OrderStatus.DRAFT.equals(this.status); } - public Boolean hasProducts() { + private Boolean hasProducts() { return !this.items.isEmpty(); } @@ -79,6 +89,18 @@ public void setStatus(OrderStatus status) { this.status = status; } + public void validate() { + var errors = new LinkedList(); + + if (this.status == OrderStatus.SUBMITTED && !this.hasProducts()) { + errors.add("Can not submit order without products"); + } + + if (!errors.isEmpty()) { + throw new CompositeDomainValidationException(errors); + } + } + @PostLoad protected void postLoad() { recalculateTotalPrice(); @@ -87,11 +109,13 @@ protected void postLoad() { @PrePersist protected void prePersist() { createdAt = Instant.now(); + this.validate(); } @PreUpdate protected void preUpdate() { updatedAt = Instant.now(); + this.validate(); } @PreRemove