Skip to content

Commit

Permalink
implement order logic
Browse files Browse the repository at this point in the history
  • Loading branch information
don-bigdad committed Nov 27, 2023
1 parent 0bf7d31 commit 8d60122
Show file tree
Hide file tree
Showing 22 changed files with 558 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.example.springbootbookshop.controller;

import com.example.springbootbookshop.dto.cart.CartDto;
import com.example.springbootbookshop.dto.order.OrderDto;
import com.example.springbootbookshop.dto.order.OrderItemDto;
import com.example.springbootbookshop.dto.order.RequestOrderDto;
import com.example.springbootbookshop.dto.order.UpdateRequestOrderStatus;
import com.example.springbootbookshop.entity.User;
import com.example.springbootbookshop.service.OrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.Positive;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
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;

@RequiredArgsConstructor
@Tag(name = "Order management",description = "Endpoints make orders")
@RestController
@RequestMapping("/orders")
public class OrderController {
private final OrderService orderService;

@PostMapping
@Operation(summary = "Make order")
@PreAuthorize("hasRole('USER')")
public CartDto makeOrder(Authentication authentication,
@RequestBody RequestOrderDto requestOrderDto) {
return orderService.save(getUserId(authentication), requestOrderDto);
}

@PatchMapping("/{orderId}")
@Operation(summary = "Update order status (for admin only)")
@PreAuthorize("hasRole('ADMIN')")
public void updateStatus(@Positive @PathVariable Long orderId,
@RequestBody UpdateRequestOrderStatus updateStatus) {
orderService.updateOrderStatus(orderId, updateStatus);
}

@GetMapping
@Operation(summary = "Get order history")
@PreAuthorize("hasRole('USER')")
public Set<OrderDto> showOrderHistory(Authentication authentication) {
return orderService.showAllOrders(getUserId(authentication));
}

@GetMapping("/{orderId}/items/{itemId}")
@Operation(summary = "Get special item from order history")
@PreAuthorize("hasRole('USER')")
public OrderItemDto showOrderItem(Authentication authentication,
@PathVariable @Positive Long orderId,
@PathVariable @Positive Long itemId) {
return orderService.getOrderItem(getUserId(authentication),
orderId, itemId);
}

@GetMapping("/{orderId}/items")
@Operation(summary = "Get special order from user history")
@PreAuthorize("hasRole('USER')")
public Set<OrderItemDto> showOrder(Authentication authentication,
@PathVariable Long orderId) {
return orderService.getOrder(getUserId(authentication), orderId);
}

private Long getUserId(Authentication authentication) {
User user = (User) authentication.getPrincipal();
return user.getId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.springbootbookshop.dto.order;

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

public record OrderDto(Long id,
Long userId,
String status,
Set<OrderItemDto> orderItems,
BigDecimal total,
LocalDateTime orderDate,
String shippingAddress) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.example.springbootbookshop.dto.order;

public record OrderItemDto(Long id,
Long bookId,
Integer quantity){
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.example.springbootbookshop.dto.order;

import jakarta.validation.constraints.NotBlank;

public record RequestOrderDto(@NotBlank String shippingAddress) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example.springbootbookshop.dto.order;

import com.example.springbootbookshop.entity.Status;
import jakarta.validation.constraints.NotBlank;

public record UpdateRequestOrderStatus(@NotBlank Status status) {
}
2 changes: 2 additions & 0 deletions src/main/java/com/example/springbootbookshop/entity/Book.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,7 @@ public class Book {
private Set<Category> categories = new HashSet<>();

@OneToMany(mappedBy = "book",orphanRemoval = true, cascade = CascadeType.REMOVE)
@ToString.Exclude
@EqualsAndHashCode.Exclude
private List<CartItem> cartItems = new ArrayList<>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ public class CartItem {

@Column(nullable = false)
@NotNull
private int quantity;
private Integer quantity;
}
60 changes: 60 additions & 0 deletions src/main/java/com/example/springbootbookshop/entity/Order.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.example.springbootbookshop.entity;

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.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.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;

@Entity
@Data
@Table(name = "orders")
@SQLDelete(sql = "UPDATE orders SET is_deleted = TRUE WHERE id = ?")
@Where(clause = "is_deleted = false")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@ToString.Exclude
@EqualsAndHashCode.Exclude
private User user;

@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Status status;

@Column(nullable = false)
private BigDecimal total;

@Column(nullable = false)
private LocalDateTime orderDate;

@Column(nullable = false)
private String shippingAddress;

@OneToMany(mappedBy = "order", orphanRemoval = true,
cascade = CascadeType.REMOVE)
@Column(nullable = false)
private Set<OrderItem> orderItems = new HashSet<>();

@Column(nullable = false)
private boolean isDeleted = false;
}
49 changes: 49 additions & 0 deletions src/main/java/com/example/springbootbookshop/entity/OrderItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.example.springbootbookshop.entity;

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.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;

@Entity
@Data
@Table(name = "order_items")
@SQLDelete(sql = "UPDATE orders_items SET is_deleted = TRUE WHERE id = ?")
@Where(clause = "is_deleted = false")
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@ToString.Exclude
@EqualsAndHashCode.Exclude
@JoinColumn(name = "order_id")
private Order order;

@ToString.Exclude
@EqualsAndHashCode.Exclude
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "book_id", nullable = false)
private Book book;

@Column(nullable = false)
private Integer quantity;

@Column(nullable = false)
private BigDecimal price;

@Column(nullable = false)
private boolean isDeleted = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.example.springbootbookshop.entity;

public enum Status {
PENDING,
PROCESSING,
COMPLETED,
CANCELLED,
DELIVERED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.springbootbookshop.mapper;

import com.example.springbootbookshop.dto.order.OrderItemDto;
import com.example.springbootbookshop.entity.OrderItem;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.NullValueCheckStrategy;

@Mapper(componentModel = "spring",
injectionStrategy = InjectionStrategy.CONSTRUCTOR,
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
implementationPackage = "<PACKAGE_NAME>.impl")
public interface OrderItemMapper {

@Mapping(source = "book.id", target = "bookId")
OrderItemDto toDto(OrderItem orderItem);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.example.springbootbookshop.mapper;

import com.example.springbootbookshop.dto.order.OrderDto;
import com.example.springbootbookshop.entity.Order;
import org.mapstruct.InjectionStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.NullValueCheckStrategy;

@Mapper(componentModel = "spring",
injectionStrategy = InjectionStrategy.CONSTRUCTOR,
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
implementationPackage = "<PACKAGE_NAME>.impl",
uses = OrderItemMapper.class)
public interface OrderMapper {
@Mapping(source = "user.id", target = "userId")
OrderDto toDto(Order order);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.example.springbootbookshop.entity.Cart;
import com.example.springbootbookshop.entity.CartItem;
import java.util.Optional;
import java.util.Set;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
Expand All @@ -14,4 +15,6 @@ public interface CartItemsRepository extends JpaRepository<CartItem, Long> {
Optional<CartItem> findByCartAndBook(Cart cart, Book book);

Optional<CartItem> getCartItemsByIdAndCartId(Long itemId,Long cartId);

Set<CartItem> findByCart(Cart cart);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.example.springbootbookshop.repository;

import com.example.springbootbookshop.dto.order.OrderItemDto;
import com.example.springbootbookshop.entity.Order;
import com.example.springbootbookshop.entity.OrderItem;
import java.util.Optional;
import java.util.Set;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface OrderItemsRepository extends JpaRepository<OrderItem, Long> {
Optional<OrderItemDto> findByOrderAndId(Order order, Long id);

Set<OrderItemDto> findByOrder(Order order);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.example.springbootbookshop.repository;

import com.example.springbootbookshop.entity.Order;
import java.util.Set;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {

@EntityGraph(attributePaths = {"user", "orderItems"})
Set<Order> findAllByUserId(Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example.springbootbookshop.service;

import com.example.springbootbookshop.dto.cart.CartDto;
import com.example.springbootbookshop.dto.order.OrderDto;
import com.example.springbootbookshop.dto.order.OrderItemDto;
import com.example.springbootbookshop.dto.order.RequestOrderDto;
import com.example.springbootbookshop.dto.order.UpdateRequestOrderStatus;
import java.util.Set;

public interface OrderService {
CartDto save(Long userId, RequestOrderDto requestOrderDto);

OrderItemDto getOrderItem(Long userId, Long orderId, Long itemId);

Set<OrderItemDto> getOrder(Long userId, Long orderId);

Set<OrderDto> showAllOrders(Long userId);

void updateOrderStatus(Long orderId, UpdateRequestOrderStatus status);
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ public CartItemDto addItemToCart(Long userId, RequestCartItemDto requestCartItem
+ "doesn`t exist"));
int quantityToAdd = requestCartItemDto.quantity();
CartItem cartItem = cartItemsRepository.findByCartAndBook(cart, book)
.orElseGet(() -> {
CartItem newCartItem = cartItemMapper.toEntity(requestCartItemDto);
newCartItem.setBook(book);
newCartItem.setCart(cart);
return newCartItem;
});
cartItem.setQuantity(quantityToAdd + cartItem.getQuantity());
.orElse(null);
if (cartItem == null) {
cartItem = cartItemMapper.toEntity(requestCartItemDto);
cartItem.setBook(book);
cartItem.setCart(cart);
} else {
cartItem.setQuantity(cartItem.getQuantity() + quantityToAdd);
}
return cartItemMapper.toDto(cartItemsRepository.save(cartItem));
}

Expand Down
Loading

0 comments on commit 8d60122

Please sign in to comment.