From 150e910a69031691fc2e6d8856916a9a30b6f8cd Mon Sep 17 00:00:00 2001
From: Murilo Kakazu <yuri.kakazu@gmail.com>
Date: Sun, 19 May 2024 21:54:16 -0300
Subject: [PATCH] refactor: implement order actions as use cases

---
 Makefile                                      |   7 +-
 .../adapters/in/rest/OrderResource.java       |  52 +++++----
 .../exceptions/ResourceExceptionHandler.java  |  14 ---
 .../application/services/OrderService.java    |  19 ----
 ...angeOrderProductsAfterSubmitException.java |  17 +++
 ...ntSubmitOrderWithoutProductsException.java |  16 +++
 .../exceptions/DomainValidationException.java |  15 +++
 .../exceptions/InvalidCpfException.java       |  16 +++
 .../ResourceBadRequestException.java          |   6 +-
 ...erCantChangeOrderAfterSubmitException.java |  16 ---
 .../services/impl/CustomerServiceImpl.java    |   4 +-
 .../services/impl/OrderServiceImpl.java       | 106 ------------------
 .../commands/AddProductToOrderCommand.java    |  10 --
 .../RemoveProductFromOrderCommand.java        |   9 --
 .../domain/commands/SubmitOrderCommand.java   |   8 --
 .../order/AddProductToOrderUseCase.java       |  47 ++++++++
 .../usecases/order/GetOrderUseCase.java       |  28 +++++
 .../order/RemoveProductFromOrderUseCase.java  |  44 ++++++++
 .../usecases/order/StartNewOrderUseCase.java  |  26 +++++
 .../usecases/order/SubmitOrderUseCase.java    |  35 ++++++
 .../persistence/jpa/entities/OrderEntity.java |   4 +
 21 files changed, 289 insertions(+), 210 deletions(-)
 delete mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/application/services/OrderService.java
 create mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CantChangeOrderProductsAfterSubmitException.java
 create 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/DomainValidationException.java
 create mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/InvalidCpfException.java
 delete mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/UserCantChangeOrderAfterSubmitException.java
 delete mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/application/services/impl/OrderServiceImpl.java
 delete mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/AddProductToOrderCommand.java
 delete mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/RemoveProductFromOrderCommand.java
 delete mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/SubmitOrderCommand.java
 create mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/AddProductToOrderUseCase.java
 create mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/GetOrderUseCase.java
 create mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/RemoveProductFromOrderUseCase.java
 create mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/StartNewOrderUseCase.java
 create mode 100644 src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/SubmitOrderUseCase.java

diff --git a/Makefile b/Makefile
index d36ba89..d256ab1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,5 @@
+.PHONY: test build run debug lint/fix
+
 test:
 	./gradlew test
 
@@ -8,4 +10,7 @@ run:
 	./gradlew bootRun
 
 debug:
-	./gradlew bootRun --debug-jvm
\ No newline at end of file
+	./gradlew bootRun --debug-jvm
+
+lint/fix:
+	./gradlew spotlessApply
\ No newline at end of file
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/adapters/in/rest/OrderResource.java b/src/main/java/br/com/fiap/grupo30/fastfood/adapters/in/rest/OrderResource.java
index 24f3632..9a1147b 100644
--- a/src/main/java/br/com/fiap/grupo30/fastfood/adapters/in/rest/OrderResource.java
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/adapters/in/rest/OrderResource.java
@@ -2,10 +2,11 @@
 
 import br.com.fiap.grupo30.fastfood.application.dto.AddOrderProductRequest;
 import br.com.fiap.grupo30.fastfood.application.dto.OrderDTO;
-import br.com.fiap.grupo30.fastfood.application.services.OrderService;
-import br.com.fiap.grupo30.fastfood.domain.commands.AddProductToOrderCommand;
-import br.com.fiap.grupo30.fastfood.domain.commands.RemoveProductFromOrderCommand;
-import br.com.fiap.grupo30.fastfood.domain.commands.SubmitOrderCommand;
+import br.com.fiap.grupo30.fastfood.domain.usecases.order.AddProductToOrderUseCase;
+import br.com.fiap.grupo30.fastfood.domain.usecases.order.GetOrderUseCase;
+import br.com.fiap.grupo30.fastfood.domain.usecases.order.RemoveProductFromOrderUseCase;
+import br.com.fiap.grupo30.fastfood.domain.usecases.order.StartNewOrderUseCase;
+import br.com.fiap.grupo30.fastfood.domain.usecases.order.SubmitOrderUseCase;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import java.net.URI;
@@ -19,11 +20,24 @@
 @Tag(name = "Orders Resource", description = "RESTful API for managing orders.")
 public class OrderResource {
 
-    private final OrderService orderService;
+    private final StartNewOrderUseCase startNewOrderUseCase;
+    private final AddProductToOrderUseCase addProductToOrderUseCase;
+    private final RemoveProductFromOrderUseCase removeProductFromOrderUseCase;
+    private final GetOrderUseCase getOrderUseCase;
+    private final SubmitOrderUseCase submitOrderUseCase;
 
     @Autowired
-    public OrderResource(OrderService orderService) {
-        this.orderService = orderService;
+    public OrderResource(
+            StartNewOrderUseCase startNewOrderUseCase,
+            AddProductToOrderUseCase addProductToOrderUseCase,
+            RemoveProductFromOrderUseCase removeProductFromOrderUseCase,
+            GetOrderUseCase getOrderUseCase,
+            SubmitOrderUseCase submitOrderUseCase) {
+        this.startNewOrderUseCase = startNewOrderUseCase;
+        this.addProductToOrderUseCase = addProductToOrderUseCase;
+        this.removeProductFromOrderUseCase = removeProductFromOrderUseCase;
+        this.getOrderUseCase = getOrderUseCase;
+        this.submitOrderUseCase = submitOrderUseCase;
     }
 
     @GetMapping(value = "/{orderId}")
@@ -31,7 +45,7 @@ public OrderResource(OrderService orderService) {
             summary = "Get an order by ID",
             description = "Retrieve a specific order based on its ID")
     public ResponseEntity<OrderDTO> findById(@PathVariable Long orderId) {
-        OrderDTO order = orderService.getOrder(orderId);
+        OrderDTO order = this.getOrderUseCase.execute(orderId);
         return ResponseEntity.ok().body(order);
     }
 
@@ -40,7 +54,7 @@ public ResponseEntity<OrderDTO> findById(@PathVariable Long orderId) {
             summary = "Create a new order",
             description = "Create a new order and return the new order's data")
     public ResponseEntity<OrderDTO> startNewOrder() {
-        OrderDTO order = orderService.startNewOrder();
+        OrderDTO order = this.startNewOrderUseCase.execute();
         URI uri =
                 ServletUriComponentsBuilder.fromCurrentRequest()
                         .path("/{orderId}")
@@ -53,12 +67,9 @@ public ResponseEntity<OrderDTO> startNewOrder() {
     @Operation(summary = "Add a product to an order", description = "Adds a product to an order")
     public ResponseEntity<OrderDTO> addProduct(
             @PathVariable Long orderId, @RequestBody AddOrderProductRequest request) {
-        var command = new AddProductToOrderCommand();
-        command.setOrderId(orderId);
-        command.setProductId(request.getProductId());
-        command.setProductQuantity(request.getQuantity());
-
-        OrderDTO order = orderService.addProductToOrder(command);
+        OrderDTO order =
+                this.addProductToOrderUseCase.execute(
+                        orderId, request.getProductId(), request.getQuantity());
         return ResponseEntity.ok().body(order);
     }
 
@@ -68,11 +79,7 @@ public ResponseEntity<OrderDTO> addProduct(
             description = "Removes a product from an order")
     public ResponseEntity<OrderDTO> removeProduct(
             @PathVariable Long orderId, @PathVariable Long productId) {
-        var command = new RemoveProductFromOrderCommand();
-        command.setOrderId(orderId);
-        command.setProductId(productId);
-
-        OrderDTO order = orderService.removeProductFromOrder(command);
+        OrderDTO order = this.removeProductFromOrderUseCase.execute(orderId, productId);
         return ResponseEntity.ok().body(order);
     }
 
@@ -81,10 +88,7 @@ public ResponseEntity<OrderDTO> removeProduct(
             summary = "Submit an order for preparation",
             description = "Submits an order for preparation and return the order's data")
     public ResponseEntity<OrderDTO> submitOrder(@PathVariable Long orderId) {
-        var command = new SubmitOrderCommand();
-        command.setOrderId(orderId);
-
-        OrderDTO order = orderService.submitOrder(command);
+        OrderDTO order = this.submitOrderUseCase.execute(orderId);
         return ResponseEntity.ok().body(order);
     }
 }
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/adapters/in/rest/exceptions/ResourceExceptionHandler.java b/src/main/java/br/com/fiap/grupo30/fastfood/adapters/in/rest/exceptions/ResourceExceptionHandler.java
index 19eae55..14fd3ce 100644
--- a/src/main/java/br/com/fiap/grupo30/fastfood/adapters/in/rest/exceptions/ResourceExceptionHandler.java
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/adapters/in/rest/exceptions/ResourceExceptionHandler.java
@@ -4,7 +4,6 @@
 import br.com.fiap.grupo30.fastfood.application.services.exceptions.ResourceBadRequestException;
 import br.com.fiap.grupo30.fastfood.application.services.exceptions.ResourceConflictException;
 import br.com.fiap.grupo30.fastfood.application.services.exceptions.ResourceNotFoundException;
-import br.com.fiap.grupo30.fastfood.application.services.exceptions.UserCantChangeOrderAfterSubmitException;
 import jakarta.servlet.http.HttpServletRequest;
 import java.time.Instant;
 import org.springframework.http.HttpStatus;
@@ -65,17 +64,4 @@ public ResponseEntity<StandardError> database(DatabaseException e, HttpServletRe
         err.setPath(request.getRequestURI());
         return ResponseEntity.status(status).body(err);
     }
-
-    @ExceptionHandler(UserCantChangeOrderAfterSubmitException.class)
-    public ResponseEntity<StandardError> userCantChangeOrderAfterSubmit(
-            UserCantChangeOrderAfterSubmitException e, HttpServletRequest request) {
-        HttpStatus status = HttpStatus.BAD_REQUEST;
-        StandardError err = new StandardError();
-        err.setTimestamp(Instant.now());
-        err.setStatus(status.value());
-        err.setError("UserCantChangeOrderAfterSubmit exception");
-        err.setMessage(e.getMessage());
-        err.setPath(request.getRequestURI());
-        return ResponseEntity.status(status).body(err);
-    }
 }
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/OrderService.java b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/OrderService.java
deleted file mode 100644
index d037495..0000000
--- a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/OrderService.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package br.com.fiap.grupo30.fastfood.application.services;
-
-import br.com.fiap.grupo30.fastfood.application.dto.OrderDTO;
-import br.com.fiap.grupo30.fastfood.domain.commands.AddProductToOrderCommand;
-import br.com.fiap.grupo30.fastfood.domain.commands.RemoveProductFromOrderCommand;
-import br.com.fiap.grupo30.fastfood.domain.commands.SubmitOrderCommand;
-
-public interface OrderService {
-
-    public OrderDTO startNewOrder();
-
-    public OrderDTO addProductToOrder(AddProductToOrderCommand command);
-
-    public OrderDTO removeProductFromOrder(RemoveProductFromOrderCommand command);
-
-    public OrderDTO submitOrder(SubmitOrderCommand command);
-
-    public OrderDTO getOrder(Long orderId);
-}
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CantChangeOrderProductsAfterSubmitException.java b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CantChangeOrderProductsAfterSubmitException.java
new file mode 100644
index 0000000..1d4434f
--- /dev/null
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CantChangeOrderProductsAfterSubmitException.java
@@ -0,0 +1,17 @@
+package br.com.fiap.grupo30.fastfood.application.services.exceptions;
+
+import java.io.Serial;
+
+public class CantChangeOrderProductsAfterSubmitException extends DomainValidationException {
+
+    @Serial private static final long serialVersionUID = 1L;
+    private static final String MESSAGE = "Can not change products of a submitted order";
+
+    public CantChangeOrderProductsAfterSubmitException() {
+        super(MESSAGE);
+    }
+
+    public CantChangeOrderProductsAfterSubmitException(Throwable exception) {
+        super(MESSAGE, exception);
+    }
+}
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
new file mode 100644
index 0000000..7b18055
--- /dev/null
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/CantSubmitOrderWithoutProductsException.java
@@ -0,0 +1,16 @@
+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/DomainValidationException.java b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/DomainValidationException.java
new file mode 100644
index 0000000..81ea5ef
--- /dev/null
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/DomainValidationException.java
@@ -0,0 +1,15 @@
+package br.com.fiap.grupo30.fastfood.application.services.exceptions;
+
+import java.io.Serial;
+
+public abstract class DomainValidationException extends ResourceBadRequestException {
+    @Serial private static final long serialVersionUID = 1L;
+
+    public DomainValidationException(String msg) {
+        super(msg);
+    }
+
+    public DomainValidationException(String msg, Throwable exception) {
+        super(msg, exception);
+    }
+}
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/InvalidCpfException.java b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/InvalidCpfException.java
new file mode 100644
index 0000000..1c54b2b
--- /dev/null
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/InvalidCpfException.java
@@ -0,0 +1,16 @@
+package br.com.fiap.grupo30.fastfood.application.services.exceptions;
+
+import java.io.Serial;
+
+public class InvalidCpfException extends DomainValidationException {
+    @Serial private static final long serialVersionUID = 1L;
+    private static final String MESSAGE_TEMPLATE = "Invalid CPF: %s";
+
+    public InvalidCpfException(String cpf) {
+        super(String.format(MESSAGE_TEMPLATE, cpf));
+    }
+
+    public InvalidCpfException(String cpf, Throwable exception) {
+        super(String.format(MESSAGE_TEMPLATE, cpf), exception);
+    }
+}
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/ResourceBadRequestException.java b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/ResourceBadRequestException.java
index 780999f..1117b05 100644
--- a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/ResourceBadRequestException.java
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/ResourceBadRequestException.java
@@ -2,10 +2,14 @@
 
 import java.io.Serial;
 
-public class ResourceBadRequestException extends RuntimeException {
+public abstract class ResourceBadRequestException extends RuntimeException {
     @Serial private static final long serialVersionUID = 1L;
 
     public ResourceBadRequestException(String msg) {
         super(msg);
     }
+
+    public ResourceBadRequestException(String msg, Throwable exception) {
+        super(msg, exception);
+    }
 }
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/UserCantChangeOrderAfterSubmitException.java b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/UserCantChangeOrderAfterSubmitException.java
deleted file mode 100644
index 9d874f4..0000000
--- a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/exceptions/UserCantChangeOrderAfterSubmitException.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package br.com.fiap.grupo30.fastfood.application.services.exceptions;
-
-import java.io.Serial;
-
-public class UserCantChangeOrderAfterSubmitException extends RuntimeException {
-
-    @Serial private static final long serialVersionUID = 1L;
-
-    public UserCantChangeOrderAfterSubmitException(String msg) {
-        super(msg);
-    }
-
-    public UserCantChangeOrderAfterSubmitException(String msg, Throwable exception) {
-        super(msg, exception);
-    }
-}
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/impl/CustomerServiceImpl.java b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/impl/CustomerServiceImpl.java
index 3f7035a..fe37d8f 100644
--- a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/impl/CustomerServiceImpl.java
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/impl/CustomerServiceImpl.java
@@ -4,7 +4,7 @@
 import br.com.fiap.grupo30.fastfood.application.mapper.impl.CustomerDTOMapper;
 import br.com.fiap.grupo30.fastfood.application.mapper.impl.CustomerMapper;
 import br.com.fiap.grupo30.fastfood.application.services.CustomerService;
-import br.com.fiap.grupo30.fastfood.application.services.exceptions.ResourceBadRequestException;
+import br.com.fiap.grupo30.fastfood.application.services.exceptions.InvalidCpfException;
 import br.com.fiap.grupo30.fastfood.application.services.exceptions.ResourceConflictException;
 import br.com.fiap.grupo30.fastfood.application.services.exceptions.ResourceNotFoundException;
 import br.com.fiap.grupo30.fastfood.domain.vo.CPF;
@@ -45,7 +45,7 @@ public CustomerDTO findCustomerByCpf(String cpf) {
     public CustomerDTO insert(CustomerDTO dto) {
         String cpfDTO = dto.getCpf();
         if (!CPF.isValid(cpfDTO)) {
-            throw new ResourceBadRequestException("Invalid CPF: " + cpfDTO);
+            throw new InvalidCpfException(cpfDTO);
         }
         try {
             dto.setCpf(CPF.removeNonDigits(cpfDTO));
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/impl/OrderServiceImpl.java b/src/main/java/br/com/fiap/grupo30/fastfood/application/services/impl/OrderServiceImpl.java
deleted file mode 100644
index ced289b..0000000
--- a/src/main/java/br/com/fiap/grupo30/fastfood/application/services/impl/OrderServiceImpl.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package br.com.fiap.grupo30.fastfood.application.services.impl;
-
-import br.com.fiap.grupo30.fastfood.application.dto.OrderDTO;
-import br.com.fiap.grupo30.fastfood.application.services.OrderService;
-import br.com.fiap.grupo30.fastfood.application.services.exceptions.ResourceNotFoundException;
-import br.com.fiap.grupo30.fastfood.application.services.exceptions.UserCantChangeOrderAfterSubmitException;
-import br.com.fiap.grupo30.fastfood.domain.commands.AddProductToOrderCommand;
-import br.com.fiap.grupo30.fastfood.domain.commands.RemoveProductFromOrderCommand;
-import br.com.fiap.grupo30.fastfood.domain.commands.SubmitOrderCommand;
-import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.OrderEntity;
-import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.OrderStatus;
-import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.ProductEntity;
-import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.repositories.OrderRepository;
-import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.repositories.ProductRepository;
-import jakarta.transaction.Transactional;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-@Service
-public class OrderServiceImpl implements OrderService {
-
-    private final String ORDER_NOT_FOUND_MESSAGE = "Order not found";
-
-    private final OrderRepository orderRepository;
-    private final ProductRepository productRepository;
-
-    @Autowired
-    public OrderServiceImpl(OrderRepository orderRepository, ProductRepository productRepository) {
-        this.orderRepository = orderRepository;
-        this.productRepository = productRepository;
-    }
-
-    @Override
-    @Transactional
-    public OrderDTO startNewOrder() {
-        OrderEntity newOrder = OrderEntity.create();
-        newOrder = this.orderRepository.save(newOrder);
-        return newOrder.toDTO();
-    }
-
-    @Override
-    @Transactional
-    public OrderDTO addProductToOrder(AddProductToOrderCommand command) {
-        OrderEntity order =
-                this.orderRepository
-                        .findById(command.getOrderId())
-                        .orElseThrow(() -> new ResourceNotFoundException(ORDER_NOT_FOUND_MESSAGE));
-
-        if (!order.isDraft()) {
-            throw new UserCantChangeOrderAfterSubmitException(
-                    "Can only add products to an order in draft");
-        }
-
-        ProductEntity product =
-                this.productRepository
-                        .findById(command.getProductId())
-                        .orElseThrow(() -> new ResourceNotFoundException("Product not found"));
-
-        order.addProduct(product, command.getProductQuantity());
-        return this.orderRepository.save(order).toDTO();
-    }
-
-    @Override
-    @Transactional
-    public OrderDTO removeProductFromOrder(RemoveProductFromOrderCommand command) {
-        OrderEntity order =
-                this.orderRepository
-                        .findById(command.getOrderId())
-                        .orElseThrow(() -> new ResourceNotFoundException(ORDER_NOT_FOUND_MESSAGE));
-
-        if (!order.isDraft()) {
-            throw new UserCantChangeOrderAfterSubmitException(
-                    "Can only remove products from an order in draft");
-        }
-
-        ProductEntity product =
-                this.productRepository
-                        .findById(command.getProductId())
-                        .orElseThrow(() -> new ResourceNotFoundException("Product not found"));
-
-        order.removeProduct(product);
-        return this.orderRepository.save(order).toDTO();
-    }
-
-    @Override
-    @Transactional
-    public OrderDTO submitOrder(SubmitOrderCommand command) {
-        OrderEntity order =
-                this.orderRepository
-                        .findById(command.getOrderId())
-                        .orElseThrow(() -> new ResourceNotFoundException(ORDER_NOT_FOUND_MESSAGE));
-
-        order.setStatus(OrderStatus.SUBMITTED);
-        return this.orderRepository.save(order).toDTO();
-    }
-
-    @Override
-    public OrderDTO getOrder(Long orderId) {
-        OrderEntity order =
-                this.orderRepository
-                        .findById(orderId)
-                        .orElseThrow(() -> new ResourceNotFoundException(ORDER_NOT_FOUND_MESSAGE));
-
-        return order.toDTO();
-    }
-}
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/AddProductToOrderCommand.java b/src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/AddProductToOrderCommand.java
deleted file mode 100644
index 0288bb3..0000000
--- a/src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/AddProductToOrderCommand.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package br.com.fiap.grupo30.fastfood.domain.commands;
-
-import lombok.Data;
-
-@Data
-public class AddProductToOrderCommand {
-    private Long orderId;
-    private Long productId;
-    private Long productQuantity;
-}
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/RemoveProductFromOrderCommand.java b/src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/RemoveProductFromOrderCommand.java
deleted file mode 100644
index a3ff108..0000000
--- a/src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/RemoveProductFromOrderCommand.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package br.com.fiap.grupo30.fastfood.domain.commands;
-
-import lombok.Data;
-
-@Data
-public class RemoveProductFromOrderCommand {
-    private Long orderId;
-    private Long productId;
-}
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/SubmitOrderCommand.java b/src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/SubmitOrderCommand.java
deleted file mode 100644
index c1a3765..0000000
--- a/src/main/java/br/com/fiap/grupo30/fastfood/domain/commands/SubmitOrderCommand.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package br.com.fiap.grupo30.fastfood.domain.commands;
-
-import lombok.Data;
-
-@Data
-public class SubmitOrderCommand {
-    private Long orderId;
-}
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
new file mode 100644
index 0000000..a196524
--- /dev/null
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/AddProductToOrderUseCase.java
@@ -0,0 +1,47 @@
+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;
+import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.repositories.OrderRepository;
+import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.repositories.ProductRepository;
+import jakarta.transaction.Transactional;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AddProductToOrderUseCase {
+
+    private final OrderRepository orderRepository;
+    private final ProductRepository productRepository;
+
+    @Autowired
+    public AddProductToOrderUseCase(
+            OrderRepository orderRepository, ProductRepository productRepository) {
+        this.orderRepository = orderRepository;
+        this.productRepository = productRepository;
+    }
+
+    @Transactional
+    public OrderDTO execute(Long orderId, Long productId, Long productQuantity) {
+        OrderEntity order =
+                this.orderRepository
+                        .findById(orderId)
+                        .orElseThrow(() -> new ResourceNotFoundException("Order not found"));
+
+        if (!order.isDraft()) {
+            throw new CantChangeOrderProductsAfterSubmitException();
+        }
+
+        ProductEntity product =
+                this.productRepository
+                        .findById(productId)
+                        .orElseThrow(() -> new ResourceNotFoundException("Product not found"));
+
+        order.addProduct(product, productQuantity);
+
+        return this.orderRepository.save(order).toDTO();
+    }
+}
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/GetOrderUseCase.java b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/GetOrderUseCase.java
new file mode 100644
index 0000000..025b1ef
--- /dev/null
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/GetOrderUseCase.java
@@ -0,0 +1,28 @@
+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.ResourceNotFoundException;
+import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.OrderEntity;
+import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.repositories.OrderRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class GetOrderUseCase {
+
+    private final OrderRepository orderRepository;
+
+    @Autowired
+    public GetOrderUseCase(OrderRepository orderRepository) {
+        this.orderRepository = orderRepository;
+    }
+
+    public OrderDTO execute(Long orderId) {
+        OrderEntity order =
+                this.orderRepository
+                        .findById(orderId)
+                        .orElseThrow(() -> new ResourceNotFoundException("Order not found"));
+
+        return order.toDTO();
+    }
+}
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
new file mode 100644
index 0000000..019a0f0
--- /dev/null
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/RemoveProductFromOrderUseCase.java
@@ -0,0 +1,44 @@
+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;
+import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.repositories.OrderRepository;
+import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.repositories.ProductRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RemoveProductFromOrderUseCase {
+
+    private final OrderRepository orderRepository;
+    private final ProductRepository productRepository;
+
+    @Autowired
+    public RemoveProductFromOrderUseCase(
+            OrderRepository orderRepository, ProductRepository productRepository) {
+        this.orderRepository = orderRepository;
+        this.productRepository = productRepository;
+    }
+
+    public OrderDTO execute(Long orderId, Long productId) {
+        OrderEntity order =
+                this.orderRepository
+                        .findById(orderId)
+                        .orElseThrow(() -> new ResourceNotFoundException("Order not found"));
+
+        if (!order.isDraft()) {
+            throw new CantChangeOrderProductsAfterSubmitException();
+        }
+
+        ProductEntity product =
+                this.productRepository
+                        .findById(productId)
+                        .orElseThrow(() -> new ResourceNotFoundException("Product not found"));
+
+        order.removeProduct(product);
+        return this.orderRepository.save(order).toDTO();
+    }
+}
diff --git a/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/StartNewOrderUseCase.java b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/StartNewOrderUseCase.java
new file mode 100644
index 0000000..9932874
--- /dev/null
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/StartNewOrderUseCase.java
@@ -0,0 +1,26 @@
+package br.com.fiap.grupo30.fastfood.domain.usecases.order;
+
+import br.com.fiap.grupo30.fastfood.application.dto.OrderDTO;
+import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.OrderEntity;
+import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.repositories.OrderRepository;
+import jakarta.transaction.Transactional;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class StartNewOrderUseCase {
+
+    private final OrderRepository orderRepository;
+
+    @Autowired
+    public StartNewOrderUseCase(OrderRepository orderRepository) {
+        this.orderRepository = orderRepository;
+    }
+
+    @Transactional
+    public OrderDTO execute() {
+        OrderEntity newOrder = OrderEntity.create();
+        newOrder = this.orderRepository.save(newOrder);
+        return newOrder.toDTO();
+    }
+}
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
new file mode 100644
index 0000000..252e65e
--- /dev/null
+++ b/src/main/java/br/com/fiap/grupo30/fastfood/domain/usecases/order/SubmitOrderUseCase.java
@@ -0,0 +1,35 @@
+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;
+import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.repositories.OrderRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SubmitOrderUseCase {
+
+    private final OrderRepository orderRepository;
+
+    @Autowired
+    public SubmitOrderUseCase(OrderRepository orderRepository) {
+        this.orderRepository = orderRepository;
+    }
+
+    public OrderDTO execute(Long orderId) {
+        OrderEntity order =
+                this.orderRepository
+                        .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 a66b4d7..d18f785 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
@@ -71,6 +71,10 @@ public Boolean isDraft() {
         return OrderStatus.DRAFT.equals(this.status);
     }
 
+    public Boolean hasProducts() {
+        return !this.items.isEmpty();
+    }
+
     public void setStatus(OrderStatus status) {
         this.status = status;
     }