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 #9 from 7SOATSquad30/feat/order
Browse files Browse the repository at this point in the history
feat: order resource and some domain logic
  • Loading branch information
MuriloKakazu authored May 13, 2024
2 parents 9e5b28f + e6244ba commit 6ecfaa2
Show file tree
Hide file tree
Showing 18 changed files with 537 additions and 0 deletions.
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
test:
./gradlew test

build:
./gradlew build

run:
./gradlew bootRun

debug:
./gradlew bootRun --debug-jvm
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package br.com.fiap.grupo30.fastfood.adapters.in.rest;

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 io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.net.URI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

@RestController
@RequestMapping(value = "/orders")
@Tag(name = "Orders Resource", description = "RESTful API for managing orders.")
public class OrderResource {

private final OrderService orderService;

@Autowired
public OrderResource(OrderService orderService) {
this.orderService = orderService;
}

@GetMapping(value = "/{orderId}")
@Operation(
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);
return ResponseEntity.ok().body(order);
}

@PostMapping
@Operation(
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();
URI uri =
ServletUriComponentsBuilder.fromCurrentRequest()
.path("/{orderId}")
.buildAndExpand(order.getOrderId())
.toUri();
return ResponseEntity.created(uri).body(order);
}

@PostMapping(value = "/{orderId}/products")
@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);
return ResponseEntity.ok().body(order);
}

@DeleteMapping(value = "/{orderId}/products/{productId}")
@Operation(
summary = "Remove a product from an order",
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);
return ResponseEntity.ok().body(order);
}

@PostMapping(value = "/{orderId}/submit")
@Operation(
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);
return ResponseEntity.ok().body(order);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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;
Expand Down Expand Up @@ -64,4 +65,17 @@ 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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package br.com.fiap.grupo30.fastfood.application.dto;

import lombok.Data;

@Data
public class AddOrderProductRequest {
private final Long productId;
private final Long quantity;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package br.com.fiap.grupo30.fastfood.application.dto;

import br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities.OrderStatus;
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class OrderDTO {
private Long orderId;
private OrderStatus status;
private OrderItemDTO[] items;
private Double totalPrice;
}
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;

@Data
@AllArgsConstructor
public class OrderItemDTO {
private Long quantity;
private Double totalPrice;
private ProductDTO product;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
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();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package br.com.fiap.grupo30.fastfood.domain.commands;

import lombok.Data;

@Data
public class AddProductToOrderCommand {
private Long orderId;
private Long productId;
private Long productQuantity;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package br.com.fiap.grupo30.fastfood.domain.commands;

import lombok.Data;

@Data
public class RemoveProductFromOrderCommand {
private Long orderId;
private Long productId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package br.com.fiap.grupo30.fastfood.domain.commands;

import lombok.Data;

@Data
public class SubmitOrderCommand {
private Long orderId;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package br.com.fiap.grupo30.fastfood.infrastructure.out.persistence.jpa.entities;

import br.com.fiap.grupo30.fastfood.application.dto.CategoryDTO;
import jakarta.persistence.*;
import java.time.Instant;
import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -53,4 +54,9 @@ public void preUpdate() {
public void preRemove() {
deletedAt = Instant.now();
}

public CategoryDTO toDTO() {
CategoryDTO categoryDto = new CategoryDTO(this.id, this.name);
return categoryDto;
}
}
Loading

0 comments on commit 6ecfaa2

Please sign in to comment.