Skip to content
This repository has been archived by the owner on Dec 4, 2024. It is now read-only.

Commit

Permalink
Merge pull request #24 from 7SOATSquad30/feature/order-endpoints
Browse files Browse the repository at this point in the history
feat: feature/order endpoints
  • Loading branch information
jonasmzsouza authored May 28, 2024
2 parents da0fc89 + a1d09a4 commit ee26fb7
Show file tree
Hide file tree
Showing 18 changed files with 372 additions and 59 deletions.
22 changes: 22 additions & 0 deletions init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,25 @@ INSERT INTO tb_customer (name, cpf, email, created_at) VALUES ('John', '20195054
INSERT INTO tb_customer (name, cpf, email, created_at) VALUES ('Mary', '81018255095', '[email protected]', NOW());
INSERT INTO tb_customer (name, cpf, email, created_at) VALUES ('Jack', '50260304085', '[email protected]', NOW());
INSERT INTO tb_customer (name, cpf, email, created_at) VALUES ('Lysa', '38877348070', '[email protected]', NOW());
INSERT INTO tb_order (status, customer_id, created_at) VALUES ('DRAFT', 1, NOW());
INSERT INTO tb_order (status, customer_id, created_at) VALUES ('SUBMITTED', 2, NOW());
INSERT INTO tb_order (status, customer_id, created_at) VALUES ('DRAFT', 3, NOW());
INSERT INTO tb_order (status, customer_id, created_at) VALUES ('PREPARING', 4, NOW());
INSERT INTO tb_order (status, customer_id, created_at) VALUES ('READY', 1, NOW());
INSERT INTO tb_order (status, customer_id, created_at) VALUES ('SUBMITTED', 3, NOW());
INSERT INTO tb_order (status, customer_id, created_at) VALUES ('DELIVERED', 2, NOW());
INSERT INTO tb_order (status, customer_id, created_at) VALUES ('PREPARING', 2, NOW());
INSERT INTO tb_order (status, customer_id, created_at) VALUES ('READY', 4, NOW());
INSERT INTO tb_order (status, customer_id, created_at) VALUES ('DELIVERED', 4, NOW());
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (2, 1, 1, 14.9);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (4, 3, 2, 29.8);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (5, 17, 2, 11.8);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (5, 6, 1, 9.9);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (6, 17, 3, 17.7);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (7, 5, 1, 12.9);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (7, 2, 1, 12.9);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (7, 8, 2, 23.8);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (8, 20, 1, 7.9);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (9, 22, 2, 17.8);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (10, 12, 1, 8.9);
INSERT INTO tb_order_item (order_id, product_id, quantity, total_price) VALUES (10, 15, 1, 13.9);
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package br.com.fiap.grupo30.fastfood.adapters.in.rest;

import br.com.fiap.grupo30.fastfood.application.dto.AddCustomerCpfRequest;
import br.com.fiap.grupo30.fastfood.application.dto.AddOrderProductRequest;
import br.com.fiap.grupo30.fastfood.application.dto.CustomerDTO;
import br.com.fiap.grupo30.fastfood.application.dto.OrderDTO;
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.ListOrdersUseCase;
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 br.com.fiap.grupo30.fastfood.domain.usecases.customer.FindCustomerByCpfUseCase;
import br.com.fiap.grupo30.fastfood.domain.usecases.order.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.net.URI;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand All @@ -27,6 +26,10 @@ public class OrderResource {
private final GetOrderUseCase getOrderUseCase;
private final SubmitOrderUseCase submitOrderUseCase;
private final ListOrdersUseCase listAllOrdersUseCase;
private final StartPreparingOrderUseCase startPreparingOrderUseCase;
private final FinishPreparingOrderUseCase finishPreparingOrderUseCase;
private final DeliverOrderUseCase deliverOrderUseCase;
private final FindCustomerByCpfUseCase findCustomerByCpfUseCase;

@Autowired
public OrderResource(
Expand All @@ -35,20 +38,33 @@ public OrderResource(
RemoveProductFromOrderUseCase removeProductFromOrderUseCase,
GetOrderUseCase getOrderUseCase,
SubmitOrderUseCase submitOrderUseCase,
ListOrdersUseCase listAllOrdersUseCase) {
ListOrdersUseCase listAllOrdersUseCase,
StartPreparingOrderUseCase startPreparingOrderUseCase,
FinishPreparingOrderUseCase finishPreparingOrderUseCase,
DeliverOrderUseCase deliverOrderUseCase,
FindCustomerByCpfUseCase findCustomerByCpfUseCase) {
this.startNewOrderUseCase = startNewOrderUseCase;
this.addProductToOrderUseCase = addProductToOrderUseCase;
this.removeProductFromOrderUseCase = removeProductFromOrderUseCase;
this.getOrderUseCase = getOrderUseCase;
this.submitOrderUseCase = submitOrderUseCase;
this.listAllOrdersUseCase = listAllOrdersUseCase;
this.startPreparingOrderUseCase = startPreparingOrderUseCase;
this.finishPreparingOrderUseCase = finishPreparingOrderUseCase;
this.deliverOrderUseCase = deliverOrderUseCase;
this.findCustomerByCpfUseCase = findCustomerByCpfUseCase;
}

@GetMapping(value = "/")
@Operation(summary = "List all orders", description = "Return all orders")
public ResponseEntity<OrderDTO[]> listAllOrders() {
OrderDTO[] orders = this.listAllOrdersUseCase.execute();
return ResponseEntity.ok().body(orders);
@GetMapping
@Operation(
summary = "Get all orders",
description =
"Get a list of all registered orders sorted by date and status or by status"
+ " sorted by date via RequestParam. i.e., ?status=")
public ResponseEntity<List<OrderDTO>> findOrdersByStatus(
@RequestParam(value = "status", required = false) String status) {
List<OrderDTO> list = listAllOrdersUseCase.execute(status);
return ResponseEntity.ok().body(list);
}

@GetMapping(value = "/{orderId}")
Expand All @@ -64,8 +80,13 @@ public ResponseEntity<OrderDTO> findById(@PathVariable Long orderId) {
@Operation(
summary = "Create a new order",
description = "Create a new order and return the new order's data")
public ResponseEntity<OrderDTO> startNewOrder() {
OrderDTO order = this.startNewOrderUseCase.execute();
public ResponseEntity<OrderDTO> startNewOrder(
@RequestBody(required = false) AddCustomerCpfRequest request) {
CustomerDTO customerDTO = null;
if (request != null && request.getCpf() != null && !request.getCpf().isEmpty()) {
customerDTO = findCustomerByCpfUseCase.execute(request.getCpf());
}
OrderDTO order = this.startNewOrderUseCase.execute(customerDTO);
URI uri =
ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{orderId}")
Expand Down Expand Up @@ -102,4 +123,31 @@ public ResponseEntity<OrderDTO> submitOrder(@PathVariable Long orderId) {
OrderDTO order = this.submitOrderUseCase.execute(orderId);
return ResponseEntity.ok().body(order);
}

@PostMapping(value = "/{orderId}/prepare")
@Operation(
summary = "Start preparing an order",
description = "Start preparing an order and return the order's data")
public ResponseEntity<OrderDTO> startPreparingOrder(@PathVariable Long orderId) {
OrderDTO order = this.startPreparingOrderUseCase.execute(orderId);
return ResponseEntity.ok().body(order);
}

@PostMapping(value = "/{orderId}/ready")
@Operation(
summary = "Finish preparing an order",
description = "Finish preparing an order and return the order's data")
public ResponseEntity<OrderDTO> finishPreparingOrder(@PathVariable Long orderId) {
OrderDTO order = this.finishPreparingOrderUseCase.execute(orderId);
return ResponseEntity.ok().body(order);
}

@PostMapping(value = "/{orderId}/deliver")
@Operation(
summary = "Deliver an order",
description = "Deliver an order and return the order's data")
public ResponseEntity<OrderDTO> deliverOrder(@PathVariable Long orderId) {
OrderDTO order = this.deliverOrderUseCase.execute(orderId);
return ResponseEntity.ok().body(order);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package br.com.fiap.grupo30.fastfood.application.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class AddCustomerCpfRequest {
private String cpf;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ public class OrderDTO {
private OrderStatus status;
private OrderItemDTO[] items;
private Double totalPrice;
private CustomerDTO customer;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package br.com.fiap.grupo30.fastfood.application.exceptions;

import java.io.Serial;

public class CantChangeOrderStatusDeliveredOtherThanReadyException
extends DomainValidationException {

@Serial private static final long serialVersionUID = 1L;
private static final String MESSAGE =
"Can not to finish the delivery an order that does not have the ready status";

public CantChangeOrderStatusDeliveredOtherThanReadyException() {
super(MESSAGE);
}

public CantChangeOrderStatusDeliveredOtherThanReadyException(Throwable exception) {
super(MESSAGE, exception);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package br.com.fiap.grupo30.fastfood.application.exceptions;

import java.io.Serial;

public class CantChangeOrderStatusPreparingOtherThanSubmittedException
extends DomainValidationException {

@Serial private static final long serialVersionUID = 1L;
private static final String MESSAGE =
"Can not to prepare an order that does not have the submitted status";

public CantChangeOrderStatusPreparingOtherThanSubmittedException() {
super(MESSAGE);
}

public CantChangeOrderStatusPreparingOtherThanSubmittedException(Throwable exception) {
super(MESSAGE, exception);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package br.com.fiap.grupo30.fastfood.application.exceptions;

import java.io.Serial;

public class CantChangeOrderStatusReadyOtherThanPreparingException
extends DomainValidationException {

@Serial private static final long serialVersionUID = 1L;
private static final String MESSAGE =
"Can not to finish the prepare an order that does not have the preparing status";

public CantChangeOrderStatusReadyOtherThanPreparingException() {
super(MESSAGE);
}

public CantChangeOrderStatusReadyOtherThanPreparingException(Throwable exception) {
super(MESSAGE, exception);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package br.com.fiap.grupo30.fastfood.application.exceptions;

import java.io.Serial;

public class InvalidOrderStatusException extends RuntimeException {

@Serial private static final long serialVersionUID = 1L;

private static final String MESSAGE_TEMPLATE = "Invalid order status: %s";

public InvalidOrderStatusException(String status) {
super(String.format(MESSAGE_TEMPLATE, status));
}

public InvalidOrderStatusException(String status, Throwable exception) {
super(String.format(MESSAGE_TEMPLATE, status), exception);
}
}
Original file line number Diff line number Diff line change
@@ -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.exceptions.CantChangeOrderStatusDeliveredOtherThanReadyException;
import br.com.fiap.grupo30.fastfood.application.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 DeliverOrderUseCase {

private final OrderRepository orderRepository;

@Autowired
public DeliverOrderUseCase(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}

public OrderDTO execute(Long orderId) {
OrderEntity order =
this.orderRepository
.findById(orderId)
.orElseThrow(() -> new ResourceNotFoundException("Order not found"));

if (order.getStatus() != OrderStatus.READY) {
throw new CantChangeOrderStatusDeliveredOtherThanReadyException();
}

order.setStatus(OrderStatus.DELIVERED);
return this.orderRepository.save(order).toDTO();
}
}
Original file line number Diff line number Diff line change
@@ -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.exceptions.CantChangeOrderStatusReadyOtherThanPreparingException;
import br.com.fiap.grupo30.fastfood.application.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 FinishPreparingOrderUseCase {

private final OrderRepository orderRepository;

@Autowired
public FinishPreparingOrderUseCase(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}

public OrderDTO execute(Long orderId) {
OrderEntity order =
this.orderRepository
.findById(orderId)
.orElseThrow(() -> new ResourceNotFoundException("Order not found"));

if (order.getStatus() != OrderStatus.PREPARING) {
throw new CantChangeOrderStatusReadyOtherThanPreparingException();
}

order.setStatus(OrderStatus.READY);
return this.orderRepository.save(order).toDTO();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
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.exceptions.InvalidOrderStatusException;
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 java.util.Comparator;
import java.util.List;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

Expand All @@ -17,9 +21,18 @@ public ListOrdersUseCase(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}

public OrderDTO[] execute() {
List<OrderEntity> allOrders = this.orderRepository.findAll();

return allOrders.stream().map(order -> order.toDTO()).toArray(OrderDTO[]::new);
public List<OrderDTO> execute(String status) {
OrderStatus orderStatus = null;
if (status != null && !status.isEmpty()) {
try {
orderStatus = OrderStatus.valueOf(status.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException e) {
throw new InvalidOrderStatusException(status, e);
}
}
return orderRepository.findOrdersByStatus(orderStatus).stream()
.sorted(Comparator.comparing(OrderEntity::getCreatedAt))
.map(OrderEntity::toDTO)
.toList();
}
}
Loading

0 comments on commit ee26fb7

Please sign in to comment.