Skip to content

Commit

Permalink
Resolved issues:
Browse files Browse the repository at this point in the history
 - Refactored order saving method in OrderServiceImpl.
 - Fixed issues with lazy initialization.
 - Added authorized user in getOrderItem method in controller so that any user cannot get another user's data.
 - Added equals & hashcode, and toString in OrderItem entity.
  • Loading branch information
nklimovych committed May 24, 2024
1 parent bb8ead1 commit ee46947
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 69 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ build/
!**/src/test/**/build/

### VS Code ###
.vscode/
.vscode/

### Docker ###
/.env
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ public List<OrderItemResponseDto> getAllOrderItems(
description = "Retrieves a specific item from an order identified by its id")
public OrderItemResponseDto getOrderItem(
@PathVariable Long orderId,
@PathVariable Long itemId) {
return orderService.getOrderItem(orderId, itemId);
@PathVariable Long itemId,
@AuthenticationPrincipal User user) {
return orderService.getOrderItem(orderId, itemId, user);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ public class Order {
@Column(nullable = false)
private String shippingAddress;

@OneToMany(mappedBy = "order", cascade = CascadeType.REMOVE)
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private Set<OrderItem> orderItems = new HashSet<>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.math.BigDecimal;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import mate.academy.bookstore.model.Book;
import org.hibernate.annotations.SoftDelete;

@Getter
@Setter
@ToString
@EqualsAndHashCode(of = {"id", "order", "book", "price"})
@SoftDelete
@Entity
@Table(name = "order_items")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@

public interface ShoppingCartRepository extends JpaRepository<ShoppingCart, Long> {

Optional<ShoppingCart> findByUser_Id(Long userId);
Optional<ShoppingCart> findByUserId(Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

import java.util.List;
import java.util.Optional;
import mate.academy.bookstore.model.order.Order;
import mate.academy.bookstore.model.order.OrderItem;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderItemRepository extends JpaRepository<OrderItem, Long> {

List<OrderItem> findByOrderId(Long orderId);

Optional<OrderItem> findByIdAndOrder(Long itemId, Order order);
Optional<OrderItem> findByIdAndOrderId(Long itemId, Long orderId);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mate.academy.bookstore.repository.order;

import java.util.List;
import java.util.Optional;
import mate.academy.bookstore.model.order.Order;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
Expand All @@ -9,4 +10,8 @@ public interface OrderRepository extends JpaRepository<Order, Long> {

@EntityGraph(attributePaths = {"orderItems"})
List<Order> findByUserId(Long userId);

@Override
@EntityGraph(attributePaths = {"user"})
Optional<Order> findById(Long orderId);
}
10 changes: 1 addition & 9 deletions src/main/java/mate/academy/bookstore/service/OrderService.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
package mate.academy.bookstore.service;

import java.util.List;
import java.util.Map;
import java.util.Set;
import mate.academy.bookstore.dto.order.OrderItemResponseDto;
import mate.academy.bookstore.dto.order.OrderRequestDto;
import mate.academy.bookstore.dto.order.OrderResponseDto;
import mate.academy.bookstore.dto.order.OrderStatusDto;
import mate.academy.bookstore.model.Book;
import mate.academy.bookstore.model.User;
import mate.academy.bookstore.model.order.Order;
import mate.academy.bookstore.model.order.OrderItem;

public interface OrderService {
void createOrder(OrderRequestDto order, User user);
Expand All @@ -19,10 +14,7 @@ public interface OrderService {

void updateStatus(OrderStatusDto statusDto, Long orderId, Long userId);

Set<OrderItem> saveOrderItem(Order order, Map<Book, Integer> book);

List<OrderItemResponseDto> getAllOrderItems(Long orderId);

OrderItemResponseDto getOrderItem(Long orderId, Long itemId);
OrderItemResponseDto getOrderItem(Long orderId, Long itemId, User user);
}

Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ public interface ShoppingCartService {
CartItemResponseDto updateQuantity(Long itemId, QuantityRequestDto quantity);

void deleteCartItem(Long cartItemId);

ShoppingCart getShoppingCart(User user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
Expand All @@ -15,23 +14,23 @@
import mate.academy.bookstore.exception.EntityNotFoundException;
import mate.academy.bookstore.mapper.OrderItemMapper;
import mate.academy.bookstore.mapper.OrderMapper;
import mate.academy.bookstore.model.Book;
import mate.academy.bookstore.model.CartItem;
import mate.academy.bookstore.model.ShoppingCart;
import mate.academy.bookstore.model.User;
import mate.academy.bookstore.model.order.Order;
import mate.academy.bookstore.model.order.OrderItem;
import mate.academy.bookstore.model.order.Status;
import mate.academy.bookstore.repository.cart.ShoppingCartRepository;
import mate.academy.bookstore.repository.order.OrderItemRepository;
import mate.academy.bookstore.repository.order.OrderRepository;
import mate.academy.bookstore.service.OrderService;
import mate.academy.bookstore.service.ShoppingCartService;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {
private final ShoppingCartRepository cartRepository;
private final ShoppingCartService shoppingCartService;
private final OrderRepository orderRepository;
private final OrderItemRepository itemRepository;
private final OrderItemMapper itemMapper;
Expand All @@ -40,12 +39,13 @@ public class OrderServiceImpl implements OrderService {
@Transactional
@Override
public void createOrder(OrderRequestDto orderDto, User user) {
ShoppingCart cart = getCart(user);
Map<Book, Integer> books = getBooks(cart);
ShoppingCart cart = shoppingCartService.getShoppingCart(user);
Set<CartItem> cartItems = cart.getCartItems();

Order order = orderRepository.save(createNewOrder(orderDto, user, cart));
Set<OrderItem> orderItems = saveOrderItem(order, books);
Order order = createNewOrder(orderDto, user, cart);
Set<OrderItem> orderItems = createOrderItems(order, cartItems);
order.setOrderItems(orderItems);

orderRepository.save(order);
}

Expand All @@ -67,21 +67,6 @@ public void updateStatus(OrderStatusDto statusDto, Long orderId, Long userId) {
orderRepository.save(order);
}

@Override
public Set<OrderItem> saveOrderItem(Order order, Map<Book, Integer> book) {
return book.entrySet().stream()
.map(e -> {
OrderItem item = new OrderItem();
item.setBook(e.getKey());
item.setQuantity(e.getValue());
item.setOrder(order);
item.setPrice(e.getKey().getPrice());
return item;
})
.map(itemRepository::save)
.collect(Collectors.toSet());
}

@Override
public List<OrderItemResponseDto> getAllOrderItems(Long orderId) {
List<OrderItem> items = itemRepository.findByOrderId(orderId);
Expand All @@ -96,43 +81,50 @@ public List<OrderItemResponseDto> getAllOrderItems(Long orderId) {
}

@Override
public OrderItemResponseDto getOrderItem(Long orderId, Long itemId) {
public OrderItemResponseDto getOrderItem(Long orderId, Long itemId, User user) {
Order order = orderRepository.findById(orderId).orElseThrow(() ->
new EntityNotFoundException(
"Unable to proceed: Order not found with id: " + orderId));

return itemRepository.findByIdAndOrder(itemId, order)
if (!order.getUser().equals(user)) {
throw new AccessDeniedException(
"User doesn't have permission to view order with id: " + orderId);
}
return itemRepository.findByIdAndOrderId(itemId, orderId)
.map(itemMapper::toDto)
.orElseThrow(() -> new EntityNotFoundException(
"Unable to proceed: Order item not found with id: " + itemId));
}

private Order createNewOrder(OrderRequestDto orderDto, User user, ShoppingCart cart) {
Order newOrder = new Order();
newOrder.setUser(user);
newOrder.setStatus(Status.PENDING);
newOrder.setTotal(getTotalPrice(cart));
newOrder.setOrderDate(LocalDateTime.now());
newOrder.setShippingAddress(orderDto.getShippingAddress());

return newOrder;
private Set<OrderItem> createOrderItems(Order order, Set<CartItem> cartItems) {
return cartItems.stream()
.map(cartItem -> {
OrderItem item = new OrderItem();
item.setBook(cartItem.getBook());
item.setQuantity(cartItem.getQuantity());
item.setOrder(order);
item.setPrice(cartItem.getBook().getPrice());
return itemRepository.save(item);
})
.collect(Collectors.toSet());
}

private BigDecimal getTotalPrice(ShoppingCart cart) {
return cart.getCartItems().stream()
.map(i -> i.getBook()
.getPrice()
.multiply(BigDecimal.valueOf(i.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}

private ShoppingCart getCart(User user) {
return cartRepository.findByUser_Id(user.getId())
.orElseGet(() -> cartRepository.save(new ShoppingCart(user)));
private Order createNewOrder(OrderRequestDto orderDto, User user, ShoppingCart cart) {
Order order = new Order();
order.setUser(user);
order.setStatus(Status.PENDING);
order.setTotal(getTotalPrice(cart));
order.setOrderDate(LocalDateTime.now());
order.setShippingAddress(orderDto.getShippingAddress());

return orderRepository.save(order);
}

private Map<Book, Integer> getBooks(ShoppingCart cart) {
private BigDecimal getTotalPrice(ShoppingCart cart) {
return cart.getCartItems().stream()
.collect(Collectors.toMap(CartItem::getBook, CartItem::getQuantity));
.map(i -> i.getBook()
.getPrice()
.multiply(BigDecimal.valueOf(i.getQuantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ public ShoppingCart create(User user) {
@Override
@Transactional
public ShoppingCartDto getByUser(User user) {
ShoppingCart cart = getCart(user);
ShoppingCart cart = getShoppingCart(user);
return cartMapper.toDto(cart);
}

@Override
@Transactional
public CartItemResponseDto addCartItem(User user, CartItemRequestDto requestItemDto) {
ShoppingCart cart = getCart(user);
ShoppingCart cart = getShoppingCart(user);
Book book = getBook(requestItemDto.getBookId());

CartItem cartItem = itemRepository.findByShoppingCartAndBook(cart, book)
Expand Down Expand Up @@ -77,8 +77,10 @@ public void deleteCartItem(Long itemId) {
itemRepository.delete(cartItem);
}

private ShoppingCart getCart(User user) {
return cartRepository.findByUser_Id(user.getId())
@Override
@Transactional
public ShoppingCart getShoppingCart(User user) {
return cartRepository.findByUserId(user.getId())
.orElseGet(() -> cartRepository.save(new ShoppingCart(user)));

}
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/db/changelog/db.changelog-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ databaseChangeLog:
- include:
file: db/changelog/changes/12-create-orders-table.yaml
- include:
file: db/changelog/changes/13-create-order-items-table.yaml
file: db/changelog/changes/13-create-order-items-table.yaml

0 comments on commit ee46947

Please sign in to comment.