Skip to content

Commit

Permalink
Merge pull request #12 from TarasYashchuk/dev
Browse files Browse the repository at this point in the history
implemented order model
  • Loading branch information
TarasYashchuk authored Jul 27, 2024
2 parents c83941c + fb65d91 commit e294193
Show file tree
Hide file tree
Showing 19 changed files with 611 additions and 12 deletions.
122 changes: 122 additions & 0 deletions src/main/java/mate/academy/controller/OrderController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package mate.academy.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
import mate.academy.dto.order.OrderDto;
import mate.academy.dto.order.OrderItemDto;
import mate.academy.dto.order.PlaceOrderRequestDto;
import mate.academy.dto.order.UpdateOrderStatusRequestDto;
import mate.academy.model.User;
import mate.academy.service.OrderService;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/orders")
@RequiredArgsConstructor
@Tag(name = "Order Controller", description = "Operations pertaining to orders in Online Book App")
public class OrderController {
private final OrderService orderService;

@PreAuthorize("hasRole('USER')")
@PostMapping
@Operation(summary = "Place an order",
description = "Allows a user to place an order with the items in their shopping cart.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Order placed successfully"),
@ApiResponse(responseCode = "400", description = "Invalid input data"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "User not found")
})
public OrderDto placeOrder(
@AuthenticationPrincipal User userDetails,
@RequestBody @Parameter(description = "Details for placing an order", required = true)
PlaceOrderRequestDto requestDto) {
return orderService.createOrder(userDetails.getId(), requestDto.shippingAddress());
}

@PreAuthorize("hasRole('USER')")
@GetMapping
@Operation(summary = "Get order history",
description = "Allows a user to view their order history.")
@ApiResponses({
@ApiResponse(responseCode = "200",
description = "Order history retrieved successfully"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "User not found")
})
public List<OrderDto> getOrderHistory(
@AuthenticationPrincipal User userDetails,
@ParameterObject @PageableDefault Pageable pageable) {
return orderService.getOrderHistory(userDetails.getId(), pageable);
}

@PreAuthorize("hasRole('USER')")
@GetMapping("/{orderId}/items")
@Operation(summary = "Get order items",
description = "Allows a user to view all items in a specific order.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Order items retrieved successfully"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Order not found")
})
public List<OrderItemDto> getOrderItems(
@PathVariable
@Parameter(description = "ID of the order to retrieve items from", required = true)
Long orderId,
@ParameterObject @PageableDefault Pageable pageable) {
return orderService.getOrderItems(orderId, pageable);
}

@PreAuthorize("hasRole('USER')")
@GetMapping("/{orderId}/items/{itemId}")
@Operation(summary = "Get specific order item",
description = "Allows a user to view a specific item in an order.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Order item retrieved successfully"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Order or item not found")
})
public OrderItemDto getOrderItem(
@PathVariable
@Parameter(description = "ID of the order to retrieve the item from", required = true)
Long orderId,
@PathVariable @Parameter(description = "ID of the item to retrieve", required = true)
Long itemId) {
return orderService.getOrderItem(orderId, itemId);
}

@PreAuthorize("hasRole('ADMIN')")
@PatchMapping("/{orderId}")
@Operation(summary = "Update order status",
description = "Allows an admin to update the status of an order.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Order status updated successfully"),
@ApiResponse(responseCode = "400", description = "Invalid status"),
@ApiResponse(responseCode = "401", description = "Unauthorized"),
@ApiResponse(responseCode = "404", description = "Order not found")
})
public OrderDto updateOrderStatus(
@PathVariable
@Parameter(description = "ID of the order to update", required = true) Long orderId,
@RequestBody
@Parameter(description = "Details for updating the order status", required = true)
UpdateOrderStatusRequestDto requestDto) {
return orderService.updateOrderStatus(orderId, requestDto.status().name());
}
}
16 changes: 16 additions & 0 deletions src/main/java/mate/academy/dto/order/OrderDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package mate.academy.dto.order;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Set;

public record OrderDto(
Long id,
Long userId,
String status,
BigDecimal total,
LocalDateTime orderDate,
String shippingAddress,
Set<OrderItemDto> orderItems
) {
}
11 changes: 11 additions & 0 deletions src/main/java/mate/academy/dto/order/OrderItemDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package mate.academy.dto.order;

import java.math.BigDecimal;

public record OrderItemDto(
Long id,
Long orderId,
Long bookId,
int quantity,
BigDecimal price) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package mate.academy.dto.order;

import jakarta.validation.constraints.NotBlank;

public record PlaceOrderRequestDto(
@NotBlank String shippingAddress
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package mate.academy.dto.order;

import jakarta.validation.constraints.NotNull;
import mate.academy.model.Order;

public record UpdateOrderStatusRequestDto(
@NotNull Order.Status status
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package mate.academy.exception;

public class OrderProcessingException extends RuntimeException {
public OrderProcessingException(String message) {
super(message);
}
}
18 changes: 18 additions & 0 deletions src/main/java/mate/academy/mapper/OrderItemMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package mate.academy.mapper;

import mate.academy.config.MapperConfig;
import mate.academy.dto.order.OrderItemDto;
import mate.academy.model.OrderItem;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper(config = MapperConfig.class)
public interface OrderItemMapper {
@Mapping(source = "order.id", target = "orderId")
@Mapping(source = "book.id", target = "bookId")
OrderItemDto toDto(OrderItem orderItem);

@Mapping(source = "orderId", target = "order.id")
@Mapping(source = "bookId", target = "book.id")
OrderItem toModel(OrderItemDto orderItemDto);
}
16 changes: 16 additions & 0 deletions src/main/java/mate/academy/mapper/OrderMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package mate.academy.mapper;

import mate.academy.config.MapperConfig;
import mate.academy.dto.order.OrderDto;
import mate.academy.model.Order;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper(config = MapperConfig.class, uses = OrderItemMapper.class)
public interface OrderMapper {
@Mapping(source = "user.id", target = "userId")
OrderDto toDto(Order order);

@Mapping(source = "userId", target = "user.id")
Order toModel(OrderDto orderDto);
}
61 changes: 61 additions & 0 deletions src/main/java/mate/academy/model/Order.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package mate.academy.model;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLRestriction;

@Entity
@Getter
@Setter
@SQLDelete(sql = "UPDATE orders set is_deleted = true WHERE id=?")
@SQLRestriction("is_deleted=false")
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Status status = Status.PENDING;
@Column(nullable = false)
private BigDecimal total;
@Column(nullable = false)
private LocalDateTime orderDate = LocalDateTime.now();
@Column(nullable = false)
private String shippingAddress;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
@ToString.Exclude
@EqualsAndHashCode.Exclude
private Set<OrderItem> orderItems = new HashSet<>();
@Column(nullable = false, name = "is_deleted", columnDefinition = "BIT")
private boolean isDeleted = false;

public enum Status {
COMPLETED,
PENDING,
DELIVERED
}
}
42 changes: 42 additions & 0 deletions src/main/java/mate/academy/model/OrderItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package mate.academy.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLRestriction;

@Entity
@Getter
@Setter
@SQLDelete(sql = "UPDATE order_items set is_deleted = true WHERE id=?")
@SQLRestriction("is_deleted=false")
@Table(name = "order_items")
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "order_id", nullable = false)
private Order order;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "book_id", nullable = false)
private Book book;
@Column(nullable = false)
private int quantity;
@Column(nullable = false)
private BigDecimal price;
@Column(nullable = false, name = "is_deleted", columnDefinition = "BIT")
private boolean isDeleted = false;
}
10 changes: 10 additions & 0 deletions src/main/java/mate/academy/repository/order/OrderRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package mate.academy.repository.order;

import java.util.List;
import mate.academy.model.Order;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByUserId(Long userId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package mate.academy.repository.orderitem;

import java.util.List;
import java.util.Optional;
import mate.academy.model.OrderItem;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderItemRepository extends JpaRepository<OrderItem, Long> {
List<OrderItem> findByOrderId(Long orderId, Pageable pageable);

Optional<OrderItem> findByOrderIdAndId(Long orderId, Long id);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package mate.academy.repository.shoppingcart;

import java.util.Optional;
import mate.academy.model.ShoppingCart;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -8,5 +9,5 @@
@Repository
public interface ShoppingCartRepository extends JpaRepository<ShoppingCart, Long> {
@EntityGraph(attributePaths = {"cartItems", "cartItems.book"})
ShoppingCart findByUserId(Long userId);
Optional<ShoppingCart> findByUserId(Long userId);
}
18 changes: 18 additions & 0 deletions src/main/java/mate/academy/service/OrderService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package mate.academy.service;

import java.util.List;
import mate.academy.dto.order.OrderDto;
import mate.academy.dto.order.OrderItemDto;
import org.springframework.data.domain.Pageable;

public interface OrderService {
OrderDto createOrder(Long userId, String shippingAddress);

List<OrderDto> getOrderHistory(Long userId, Pageable pageable);

List<OrderItemDto> getOrderItems(Long orderId, Pageable pageable);

OrderItemDto getOrderItem(Long orderId, Long itemId);

OrderDto updateOrderStatus(Long orderId, String status);
}
Loading

0 comments on commit e294193

Please sign in to comment.