From bd749e4d6edf0e27a1ba4bafeb369506df7cd272 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Tue, 16 Dec 2025 22:41:59 +0200 Subject: [PATCH 01/10] added Order entity and OrderItem entity --- .../java/com/springm/store/model/Order.java | 42 +++++++++++++++++++ .../com/springm/store/model/OrderItem.java | 33 +++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/main/java/com/springm/store/model/Order.java create mode 100644 src/main/java/com/springm/store/model/OrderItem.java diff --git a/src/main/java/com/springm/store/model/Order.java b/src/main/java/com/springm/store/model/Order.java new file mode 100644 index 0000000..0369ff6 --- /dev/null +++ b/src/main/java/com/springm/store/model/Order.java @@ -0,0 +1,42 @@ +package com.springm.store.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Set; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.SQLRestriction; + +@Entity +@Table(name = "orders") +@SQLDelete(sql = "UPDATE orders SET is_deleted = true WHERE id=?") +@SQLRestriction("is_deleted = false") +@Getter +@Setter +public class Order { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private User user; + + @Column(nullable = false) + private BigDecimal total; + + @Column(nullable = false) + private LocalDateTime orderDate; + + @Column(nullable = false) + private String shippingAddress; + + private Set orderItems; + +} diff --git a/src/main/java/com/springm/store/model/OrderItem.java b/src/main/java/com/springm/store/model/OrderItem.java new file mode 100644 index 0000000..194b59e --- /dev/null +++ b/src/main/java/com/springm/store/model/OrderItem.java @@ -0,0 +1,33 @@ +package com.springm.store.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.math.BigDecimal; +import lombok.Getter; +import lombok.Setter; + +@Entity +@Table(name = "orderItems") +@Getter +@Setter +public class OrderItem { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private Order order; + + @Column(nullable = false) + private Book book; + + @Column(nullable = false) + private int quantity; + + @Column(nullable = false) + private BigDecimal price; +} From fd1c1a3883ddf76287ea0c8e01b9894ce622e8c7 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Tue, 16 Dec 2025 22:51:20 +0200 Subject: [PATCH 02/10] added OrderItem dto and OrderResponseDto --- .../store/dto/order/OrderResponseDto.java | 20 +++++++++++++++++++ .../store/dto/order/item/OrderItemDto.java | 17 ++++++++++++++++ .../java/com/springm/store/model/Order.java | 10 ++++++++++ 3 files changed, 47 insertions(+) create mode 100644 src/main/java/com/springm/store/dto/order/OrderResponseDto.java create mode 100644 src/main/java/com/springm/store/dto/order/item/OrderItemDto.java diff --git a/src/main/java/com/springm/store/dto/order/OrderResponseDto.java b/src/main/java/com/springm/store/dto/order/OrderResponseDto.java new file mode 100644 index 0000000..4a02f92 --- /dev/null +++ b/src/main/java/com/springm/store/dto/order/OrderResponseDto.java @@ -0,0 +1,20 @@ +package com.springm.store.dto.order; + +import com.springm.store.dto.order.item.OrderItemDto; +import com.springm.store.model.Order; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class OrderResponseDto { + private Long id; + private Long userId; + private List orderItems; + private LocalDateTime orderDate; + private BigDecimal total; + private Order.Status orderStatus; +} diff --git a/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java b/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java new file mode 100644 index 0000000..f3261ea --- /dev/null +++ b/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java @@ -0,0 +1,17 @@ +package com.springm.store.dto.order.item; + +import com.springm.store.model.Book; +import com.springm.store.model.Order; +import java.math.BigDecimal; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class OrderItemDto { + private Long id; + private Order order; + private Book book; + private int quantity; + private BigDecimal price; +} diff --git a/src/main/java/com/springm/store/model/Order.java b/src/main/java/com/springm/store/model/Order.java index 0369ff6..7f110a8 100644 --- a/src/main/java/com/springm/store/model/Order.java +++ b/src/main/java/com/springm/store/model/Order.java @@ -28,6 +28,9 @@ public class Order { @Column(nullable = false) private User user; + @Column(nullable = false) + private Status status; + @Column(nullable = false) private BigDecimal total; @@ -39,4 +42,11 @@ public class Order { private Set orderItems; + + public enum Status { + ORDER_PLACED, + PENDING, + DELIVERED, + COMPLETED + } } From 54cbc424a7f018b8e1ccbefbf684594ce660ad57 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Fri, 19 Dec 2025 12:50:00 +0200 Subject: [PATCH 03/10] changed order's entities, added required repositories --- .../store/dto/order/item/OrderItemDto.java | 4 +-- .../springm/store/mapper/OrderItemMapper.java | 17 ++++++++++++ .../java/com/springm/store/model/Order.java | 10 ++++++- .../com/springm/store/model/OrderItem.java | 11 +++++--- .../repository/order/OrderRepository.java | 7 +++++ .../order/item/OrderItemRepository.java | 7 +++++ .../springm/store/service/OrderService.java | 14 ++++++++++ .../store/service/impl/OrderServiceImpl.java | 27 +++++++++++++++++++ 8 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/springm/store/mapper/OrderItemMapper.java create mode 100644 src/main/java/com/springm/store/repository/order/OrderRepository.java create mode 100644 src/main/java/com/springm/store/repository/order/item/OrderItemRepository.java create mode 100644 src/main/java/com/springm/store/service/OrderService.java create mode 100644 src/main/java/com/springm/store/service/impl/OrderServiceImpl.java diff --git a/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java b/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java index f3261ea..dd9c627 100644 --- a/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java +++ b/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java @@ -1,6 +1,5 @@ package com.springm.store.dto.order.item; -import com.springm.store.model.Book; import com.springm.store.model.Order; import java.math.BigDecimal; import lombok.Getter; @@ -11,7 +10,8 @@ public class OrderItemDto { private Long id; private Order order; - private Book book; + private Long bookId; + private String bookTitle; private int quantity; private BigDecimal price; } diff --git a/src/main/java/com/springm/store/mapper/OrderItemMapper.java b/src/main/java/com/springm/store/mapper/OrderItemMapper.java new file mode 100644 index 0000000..ca755e7 --- /dev/null +++ b/src/main/java/com/springm/store/mapper/OrderItemMapper.java @@ -0,0 +1,17 @@ +package com.springm.store.mapper; + +import com.springm.store.config.MapperConfig; +import com.springm.store.dto.cart.item.CartItemDto; +import com.springm.store.dto.order.item.OrderItemDto; +import java.math.BigDecimal; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = MapperConfig.class) +public interface OrderItemMapper { + + @Mapping(target = "id", ignore = true) + @Mapping(target = "order", ignore = true) + @Mapping(target = "price", source = "bookPrice") + OrderItemDto toOrderItemDto(CartItemDto cartItemDto, BigDecimal bookPrice); +} diff --git a/src/main/java/com/springm/store/model/Order.java b/src/main/java/com/springm/store/model/Order.java index 7f110a8..0618958 100644 --- a/src/main/java/com/springm/store/model/Order.java +++ b/src/main/java/com/springm/store/model/Order.java @@ -1,10 +1,16 @@ package com.springm.store.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.ManyToOne; +import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import java.math.BigDecimal; import java.time.LocalDateTime; @@ -25,10 +31,12 @@ public class Order { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @ManyToOne @Column(nullable = false) private User user; @Column(nullable = false) + @Enumerated(EnumType.STRING) private Status status; @Column(nullable = false) @@ -40,9 +48,9 @@ public class Order { @Column(nullable = false) private String shippingAddress; + @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true) private Set orderItems; - public enum Status { ORDER_PLACED, PENDING, diff --git a/src/main/java/com/springm/store/model/OrderItem.java b/src/main/java/com/springm/store/model/OrderItem.java index 194b59e..fe65cea 100644 --- a/src/main/java/com/springm/store/model/OrderItem.java +++ b/src/main/java/com/springm/store/model/OrderItem.java @@ -2,16 +2,19 @@ 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; @Entity -@Table(name = "orderItems") +@Table(name = "order_items") @Getter @Setter public class OrderItem { @@ -19,10 +22,12 @@ public class OrderItem { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false) + @ManyToOne(optional = false, fetch = FetchType.LAZY) + @JoinColumn(name = "order_id", nullable = false) private Order order; - @Column(nullable = false) + @ManyToOne(optional = false, fetch = FetchType.LAZY) + @JoinColumn(name = "book_id", nullable = false) private Book book; @Column(nullable = false) diff --git a/src/main/java/com/springm/store/repository/order/OrderRepository.java b/src/main/java/com/springm/store/repository/order/OrderRepository.java new file mode 100644 index 0000000..38a03ab --- /dev/null +++ b/src/main/java/com/springm/store/repository/order/OrderRepository.java @@ -0,0 +1,7 @@ +package com.springm.store.repository.order; + +import com.springm.store.model.Order; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface OrderRepository extends JpaRepository { +} diff --git a/src/main/java/com/springm/store/repository/order/item/OrderItemRepository.java b/src/main/java/com/springm/store/repository/order/item/OrderItemRepository.java new file mode 100644 index 0000000..d174624 --- /dev/null +++ b/src/main/java/com/springm/store/repository/order/item/OrderItemRepository.java @@ -0,0 +1,7 @@ +package com.springm.store.repository.order.item; + +import com.springm.store.model.OrderItem; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface OrderItemRepository extends JpaRepository { +} diff --git a/src/main/java/com/springm/store/service/OrderService.java b/src/main/java/com/springm/store/service/OrderService.java new file mode 100644 index 0000000..aa54f68 --- /dev/null +++ b/src/main/java/com/springm/store/service/OrderService.java @@ -0,0 +1,14 @@ +package com.springm.store.service; + +import com.springm.store.dto.order.OrderResponseDto; +import com.springm.store.model.Order; +import java.util.List; + +public interface OrderService { + boolean placeOrder(String shippingAddress); + + List receiveOrderHistory(); + + OrderResponseDto updateOrderStatus(Long orderId, Order.Status orderStatus); + +} diff --git a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java new file mode 100644 index 0000000..2ba011f --- /dev/null +++ b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java @@ -0,0 +1,27 @@ +package com.springm.store.service.impl; + +import com.springm.store.dto.order.OrderResponseDto; +import com.springm.store.model.Order; +import com.springm.store.service.OrderService; +import java.util.List; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class OrderServiceImpl implements OrderService { + @Override + public boolean placeOrder(String shippingAddress) { + return false; + } + + @Override + public List receiveOrderHistory() { + return List.of(); + } + + @Override + public OrderResponseDto updateOrderStatus(Long orderId, Order.Status orderStatus) { + return null; + } +} From 2da8bb3a1bcbb20ee9a6f3e855031bf02fc53f56 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Fri, 19 Dec 2025 13:24:25 +0200 Subject: [PATCH 04/10] added OrderMapper, new UserNotFoundException, implemented OrderService --- .../exception/UserNotFoundException.java | 7 +++ .../springm/store/mapper/OrderItemMapper.java | 7 ++- .../com/springm/store/mapper/OrderMapper.java | 15 +++++ .../com/springm/store/model/ShoppingCart.java | 4 ++ .../cart/ShoppingCartRepository.java | 2 + .../repository/order/OrderRepository.java | 5 ++ .../store/repository/user/UserRepository.java | 3 + .../store/service/impl/OrderServiceImpl.java | 63 ++++++++++++++++++- .../service/impl/UserDetailsServiceImpl.java | 9 +++ 9 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/springm/store/exception/UserNotFoundException.java create mode 100644 src/main/java/com/springm/store/mapper/OrderMapper.java diff --git a/src/main/java/com/springm/store/exception/UserNotFoundException.java b/src/main/java/com/springm/store/exception/UserNotFoundException.java new file mode 100644 index 0000000..2846b90 --- /dev/null +++ b/src/main/java/com/springm/store/exception/UserNotFoundException.java @@ -0,0 +1,7 @@ +package com.springm.store.exception; + +public class UserNotFoundException extends RuntimeException { + public UserNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/springm/store/mapper/OrderItemMapper.java b/src/main/java/com/springm/store/mapper/OrderItemMapper.java index ca755e7..820a371 100644 --- a/src/main/java/com/springm/store/mapper/OrderItemMapper.java +++ b/src/main/java/com/springm/store/mapper/OrderItemMapper.java @@ -3,7 +3,7 @@ import com.springm.store.config.MapperConfig; import com.springm.store.dto.cart.item.CartItemDto; import com.springm.store.dto.order.item.OrderItemDto; -import java.math.BigDecimal; +import com.springm.store.model.OrderItem; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -12,6 +12,7 @@ public interface OrderItemMapper { @Mapping(target = "id", ignore = true) @Mapping(target = "order", ignore = true) - @Mapping(target = "price", source = "bookPrice") - OrderItemDto toOrderItemDto(CartItemDto cartItemDto, BigDecimal bookPrice); + OrderItemDto toOrderItemDto(CartItemDto cartItemDto); + + OrderItem toOrderItemModel(OrderItemDto orderItemDto); } diff --git a/src/main/java/com/springm/store/mapper/OrderMapper.java b/src/main/java/com/springm/store/mapper/OrderMapper.java new file mode 100644 index 0000000..4945cbf --- /dev/null +++ b/src/main/java/com/springm/store/mapper/OrderMapper.java @@ -0,0 +1,15 @@ +package com.springm.store.mapper; + +import com.springm.store.config.MapperConfig; +import com.springm.store.dto.order.OrderResponseDto; +import com.springm.store.model.Order; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = MapperConfig.class, uses = OrderItemMapper.class) +public interface OrderMapper { + @Mapping(source = "id", target = "id") + @Mapping(source = "user.id", target = "userId") + @Mapping(source = "orderItems", target = "orderItems") + OrderResponseDto toResponseDto(Order order); +} diff --git a/src/main/java/com/springm/store/model/ShoppingCart.java b/src/main/java/com/springm/store/model/ShoppingCart.java index 0ca6339..75aa6cd 100644 --- a/src/main/java/com/springm/store/model/ShoppingCart.java +++ b/src/main/java/com/springm/store/model/ShoppingCart.java @@ -36,4 +36,8 @@ public class ShoppingCart { @Column(nullable = false) private boolean isDeleted = false; + + public void clear() { + cartItems.clear(); + } } diff --git a/src/main/java/com/springm/store/repository/cart/ShoppingCartRepository.java b/src/main/java/com/springm/store/repository/cart/ShoppingCartRepository.java index e905ad5..a0292af 100644 --- a/src/main/java/com/springm/store/repository/cart/ShoppingCartRepository.java +++ b/src/main/java/com/springm/store/repository/cart/ShoppingCartRepository.java @@ -1,10 +1,12 @@ package com.springm.store.repository.cart; import com.springm.store.model.ShoppingCart; +import com.springm.store.model.User; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface ShoppingCartRepository extends JpaRepository { Optional findByUserId(Long userId); + Optional findByUser(User user); } diff --git a/src/main/java/com/springm/store/repository/order/OrderRepository.java b/src/main/java/com/springm/store/repository/order/OrderRepository.java index 38a03ab..257f8c5 100644 --- a/src/main/java/com/springm/store/repository/order/OrderRepository.java +++ b/src/main/java/com/springm/store/repository/order/OrderRepository.java @@ -1,7 +1,12 @@ package com.springm.store.repository.order; import com.springm.store.model.Order; +import com.springm.store.model.User; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface OrderRepository extends JpaRepository { + Optional findByUser(User user); + + Optional findByOrderId(Long orderId); } diff --git a/src/main/java/com/springm/store/repository/user/UserRepository.java b/src/main/java/com/springm/store/repository/user/UserRepository.java index 6c57f34..923b920 100644 --- a/src/main/java/com/springm/store/repository/user/UserRepository.java +++ b/src/main/java/com/springm/store/repository/user/UserRepository.java @@ -9,5 +9,8 @@ public interface UserRepository extends JpaRepository { @EntityGraph(attributePaths = "roles") Optional findByEmail(String email); + @EntityGraph(attributePaths = "roles") + Optional findByUserId(Long id); + boolean existsByEmail(String email); } diff --git a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java index 2ba011f..91e4dc8 100644 --- a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java @@ -1,27 +1,84 @@ package com.springm.store.service.impl; import com.springm.store.dto.order.OrderResponseDto; +import com.springm.store.exception.EntityNotFoundException; +import com.springm.store.mapper.CartItemMapper; +import com.springm.store.mapper.OrderItemMapper; +import com.springm.store.mapper.OrderMapper; import com.springm.store.model.Order; +import com.springm.store.model.OrderItem; +import com.springm.store.model.ShoppingCart; +import com.springm.store.model.User; +import com.springm.store.repository.cart.ShoppingCartRepository; +import com.springm.store.repository.order.OrderRepository; +import com.springm.store.repository.user.UserRepository; import com.springm.store.service.OrderService; +import java.time.LocalDateTime; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @Transactional +@RequiredArgsConstructor public class OrderServiceImpl implements OrderService { + private final UserRepository userRepository; + private final OrderRepository orderRepository; + private final ShoppingCartRepository shoppingCartRepository; + private final OrderMapper orderMapper; + private final OrderItemMapper orderItemMapper; + private final CartItemMapper cartItemMapper; + private final UserDetailsServiceImpl userDetailsService; + @Override public boolean placeOrder(String shippingAddress) { - return false; + User user = userDetailsService.getCurrentUser(); + ShoppingCart cart = shoppingCartRepository.findByUser(user) + .orElseThrow(() -> new EntityNotFoundException(user.getUsername() + " cart not found!")); + + if (cart.getCartItems().isEmpty()) { + return false; + } + + Order order = new Order(); + order.setUser(user); + order.setShippingAddress(shippingAddress); + order.setOrderDate(LocalDateTime.now()); + order.setStatus(Order.Status.ORDER_PLACED); + + Set orderItems = cart.getCartItems().stream() + .map(cartItemMapper::toDto) + .map(orderItemMapper::toOrderItemDto) + .map(orderItemMapper::toOrderItemModel) + .collect(Collectors.toSet()); + + order.setOrderItems(orderItems); + orderRepository.save(order); + + cart.clear(); + shoppingCartRepository.save(cart); + + return true; } @Override public List receiveOrderHistory() { - return List.of(); + User user = userDetailsService.getCurrentUser(); + return orderRepository.findByUser(user).stream() + .map(orderMapper::toResponseDto) + .toList(); } @Override public OrderResponseDto updateOrderStatus(Long orderId, Order.Status orderStatus) { - return null; + Order order = orderRepository.findByOrderId(orderId) + .orElseThrow(() -> new EntityNotFoundException( + "Order with id " + orderId + " not found!" + )); + order.setStatus(orderStatus); + return orderMapper.toResponseDto(orderRepository.save(order)); } } diff --git a/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java b/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java index 9a0aa40..f6fedb3 100644 --- a/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java @@ -1,5 +1,6 @@ package com.springm.store.service.impl; +import com.springm.store.exception.UserNotFoundException; import com.springm.store.model.User; import com.springm.store.repository.user.UserRepository; import lombok.RequiredArgsConstructor; @@ -33,4 +34,12 @@ public Long getCurrentUserId() { return user.getId(); } + public User getCurrentUser() { + Long userId = getCurrentUserId(); + return userRepository.findByUserId(userId) + .orElseThrow(() -> new UserNotFoundException( + "User with id " + userId + " not found!" + )); + } + } From 81e7c1b6979ee18118155ef5f069d348dcc8a85f Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Sun, 21 Dec 2025 17:51:45 +0200 Subject: [PATCH 05/10] added Order Controller and yaml files that creates tables --- .../store/controller/OrderController.java | 67 +++++++++++++++++++ .../java/com/springm/store/model/Order.java | 19 ++++-- .../repository/order/OrderRepository.java | 2 - .../store/repository/user/UserRepository.java | 3 - .../springm/store/service/OrderService.java | 2 +- .../store/service/impl/OrderServiceImpl.java | 10 ++- .../service/impl/UserDetailsServiceImpl.java | 2 +- .../changes/10-create-orders-table.yaml | 49 ++++++++++++++ .../changes/11-create-order-items-table.yaml | 43 ++++++++++++ .../changes/12-create-orders-parts-table.yaml | 40 +++++++++++ .../db/changelog/db.changelog-master.yaml | 10 ++- 11 files changed, 228 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/springm/store/controller/OrderController.java create mode 100644 src/main/resources/db/changelog/changes/10-create-orders-table.yaml create mode 100644 src/main/resources/db/changelog/changes/11-create-order-items-table.yaml create mode 100644 src/main/resources/db/changelog/changes/12-create-orders-parts-table.yaml diff --git a/src/main/java/com/springm/store/controller/OrderController.java b/src/main/java/com/springm/store/controller/OrderController.java new file mode 100644 index 0000000..83e9028 --- /dev/null +++ b/src/main/java/com/springm/store/controller/OrderController.java @@ -0,0 +1,67 @@ +package com.springm.store.controller; + +import com.springm.store.dto.order.OrderResponseDto; +import com.springm.store.model.Order; +import com.springm.store.service.OrderService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +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; + +@Tag(name = "Order management", description = "Endpoints for managing orders") +@RestController +@RequiredArgsConstructor +@RequestMapping("/orders") +public class OrderController { + private final OrderService orderService; + + @PostMapping + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") + @Operation(summary = "Place an order", description = "Place an order") + public ResponseEntity placeOrder( + @RequestBody String shippingAddress + ) { + return new ResponseEntity( + orderService.placeOrder(shippingAddress), + HttpStatus.CREATED + ); + } + + @GetMapping + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") + @Operation(summary = "Receive orders history", description = "Receive orders history") + public ResponseEntity> getAll() { + return new ResponseEntity>( + orderService.receiveOrderHistory(), + HttpStatus.OK + ); + } + + @PatchMapping("/{id}") + @PreAuthorize("hasRole('ADMIN')") + @Operation( + summary = "Update order status", + description = "Updates order status with specified ID" + ) + public ResponseEntity updateStatus( + @PathVariable Long id, + @RequestBody Order.Status orderStatus + ) { + return new ResponseEntity( + orderService.updateOrderStatus(id, orderStatus), + HttpStatus.NO_CONTENT + ); + } + + +} diff --git a/src/main/java/com/springm/store/model/Order.java b/src/main/java/com/springm/store/model/Order.java index 0618958..31c2de8 100644 --- a/src/main/java/com/springm/store/model/Order.java +++ b/src/main/java/com/springm/store/model/Order.java @@ -5,18 +5,22 @@ 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.JoinTable; 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; @@ -32,7 +36,7 @@ public class Order { private Long id; @ManyToOne - @Column(nullable = false) + @JoinColumn(name = "user_id", nullable = false) private User user; @Column(nullable = false) @@ -48,8 +52,15 @@ public class Order { @Column(nullable = false) private String shippingAddress; - @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true) - private Set orderItems; + @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) + @ToString.Exclude + @EqualsAndHashCode.Exclude + @JoinTable( + name = "orders_parts", + joinColumns = @JoinColumn(name = "order_id"), + inverseJoinColumns = @JoinColumn(name = "order_item_id") + ) + private Set orderItems = new HashSet<>(); public enum Status { ORDER_PLACED, diff --git a/src/main/java/com/springm/store/repository/order/OrderRepository.java b/src/main/java/com/springm/store/repository/order/OrderRepository.java index 257f8c5..5c1c76e 100644 --- a/src/main/java/com/springm/store/repository/order/OrderRepository.java +++ b/src/main/java/com/springm/store/repository/order/OrderRepository.java @@ -7,6 +7,4 @@ public interface OrderRepository extends JpaRepository { Optional findByUser(User user); - - Optional findByOrderId(Long orderId); } diff --git a/src/main/java/com/springm/store/repository/user/UserRepository.java b/src/main/java/com/springm/store/repository/user/UserRepository.java index 923b920..6c57f34 100644 --- a/src/main/java/com/springm/store/repository/user/UserRepository.java +++ b/src/main/java/com/springm/store/repository/user/UserRepository.java @@ -9,8 +9,5 @@ public interface UserRepository extends JpaRepository { @EntityGraph(attributePaths = "roles") Optional findByEmail(String email); - @EntityGraph(attributePaths = "roles") - Optional findByUserId(Long id); - boolean existsByEmail(String email); } diff --git a/src/main/java/com/springm/store/service/OrderService.java b/src/main/java/com/springm/store/service/OrderService.java index aa54f68..7f48e73 100644 --- a/src/main/java/com/springm/store/service/OrderService.java +++ b/src/main/java/com/springm/store/service/OrderService.java @@ -5,7 +5,7 @@ import java.util.List; public interface OrderService { - boolean placeOrder(String shippingAddress); + OrderResponseDto placeOrder(String shippingAddress); List receiveOrderHistory(); diff --git a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java index 91e4dc8..2a0b3f7 100644 --- a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java @@ -11,7 +11,6 @@ import com.springm.store.model.User; import com.springm.store.repository.cart.ShoppingCartRepository; import com.springm.store.repository.order.OrderRepository; -import com.springm.store.repository.user.UserRepository; import com.springm.store.service.OrderService; import java.time.LocalDateTime; import java.util.List; @@ -25,7 +24,6 @@ @Transactional @RequiredArgsConstructor public class OrderServiceImpl implements OrderService { - private final UserRepository userRepository; private final OrderRepository orderRepository; private final ShoppingCartRepository shoppingCartRepository; private final OrderMapper orderMapper; @@ -34,13 +32,13 @@ public class OrderServiceImpl implements OrderService { private final UserDetailsServiceImpl userDetailsService; @Override - public boolean placeOrder(String shippingAddress) { + public OrderResponseDto placeOrder(String shippingAddress) { User user = userDetailsService.getCurrentUser(); ShoppingCart cart = shoppingCartRepository.findByUser(user) .orElseThrow(() -> new EntityNotFoundException(user.getUsername() + " cart not found!")); if (cart.getCartItems().isEmpty()) { - return false; + throw new IllegalArgumentException("Order can't be empty!"); } Order order = new Order(); @@ -61,7 +59,7 @@ public boolean placeOrder(String shippingAddress) { cart.clear(); shoppingCartRepository.save(cart); - return true; + return orderMapper.toResponseDto(order); } @Override @@ -74,7 +72,7 @@ public List receiveOrderHistory() { @Override public OrderResponseDto updateOrderStatus(Long orderId, Order.Status orderStatus) { - Order order = orderRepository.findByOrderId(orderId) + Order order = orderRepository.findById(orderId) .orElseThrow(() -> new EntityNotFoundException( "Order with id " + orderId + " not found!" )); diff --git a/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java b/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java index f6fedb3..adcd5fd 100644 --- a/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java @@ -36,7 +36,7 @@ public Long getCurrentUserId() { public User getCurrentUser() { Long userId = getCurrentUserId(); - return userRepository.findByUserId(userId) + return userRepository.findById(userId) .orElseThrow(() -> new UserNotFoundException( "User with id " + userId + " not found!" )); diff --git a/src/main/resources/db/changelog/changes/10-create-orders-table.yaml b/src/main/resources/db/changelog/changes/10-create-orders-table.yaml new file mode 100644 index 0000000..699b116 --- /dev/null +++ b/src/main/resources/db/changelog/changes/10-create-orders-table.yaml @@ -0,0 +1,49 @@ +databaseChangeLog: + - changeSet: + id: create-orders-table + author: jelors + changes: + - createTable: + tableName: orders + columns: + - column: + name: id + type: bigint + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: user_id + type: bigint + constraints: + nullable: false + foreignKeyName: fk_orders_user + references: users(id) + - column: + name: status + type: varchar(255) + constraints: + nullable: false + unique: true + - column: + name: total + type: decimal + constraints: + nullable: false + - column: + name: order_date + type: TIMESTAMP + constraints: + nullable: false + - column: + name: shipping_address + type: varchar(255) + constraints: + nullable: false + - column: + name: is_deleted + type: bit(1) + defaultValueBoolean: false + constraints: + nullable: false diff --git a/src/main/resources/db/changelog/changes/11-create-order-items-table.yaml b/src/main/resources/db/changelog/changes/11-create-order-items-table.yaml new file mode 100644 index 0000000..936b81e --- /dev/null +++ b/src/main/resources/db/changelog/changes/11-create-order-items-table.yaml @@ -0,0 +1,43 @@ +databaseChangeLog: + - changeSet: + id: create-cart-items-table + author: jelors + changes: + - createTable: + tableName: order_items + columns: + - column: + name: id + type: BIGINT + autoIncrement: true + constraints: + primaryKey: true + nullable: false + + - column: + name: order_id + type: BIGINT + constraints: + nullable: false + foreignKeyName: fk_order_items_order + references: orders(id) + + - column: + name: book_id + type: BIGINT + constraints: + nullable: false + foreignKeyName: fk_order_items_book + references: books(id) + + - column: + name: quantity + type: INT + constraints: + nullable: false + + - column: + name: price + type: decimal + constraints: + nullable: false diff --git a/src/main/resources/db/changelog/changes/12-create-orders-parts-table.yaml b/src/main/resources/db/changelog/changes/12-create-orders-parts-table.yaml new file mode 100644 index 0000000..4f975d1 --- /dev/null +++ b/src/main/resources/db/changelog/changes/12-create-orders-parts-table.yaml @@ -0,0 +1,40 @@ +databaseChangeLog: + - changeSet: + id: create-books-categories-table + author: jelors + changes: + - createTable: + tableName: orders_parts + columns: + - column: + name: order_id + type: BIGINT + constraints: + nullable: false + + - column: + name: order_item_id + type: BIGINT + constraints: + nullable: false + + - addForeignKeyConstraint: + baseTableName: orders_parts + baseColumnNames: order_id + referencedTableName: orders + referencedColumnNames: id + onDelete: CASCADE + constraintName: fk_orders_parts_order + + - addForeignKeyConstraint: + baseTableName: orders_parts + baseColumnNames: order_item_id + referencedTableName: order_items + referencedColumnNames: id + onDelete: CASCADE + constraintName: fk_orders_parts_order_item + + - addUniqueConstraint: + tableName: orders_parts + columnNames: order_id, order_item_id + constraintName: uk_orders_parts_unique diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index c409fc7..44c397a 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -14,6 +14,12 @@ databaseChangeLog: - include: file: db/changelog/changes/07-create-books-categories-table.yaml - include: - file: db/changelog/changes/08-create-shopping-carts-table.yaml + file: db/changelog/changes/08-create-shopping-carts-table.yaml - include: - file: db/changelog/changes/09-create-cart-items-table.yaml \ No newline at end of file + file: db/changelog/changes/09-create-cart-items-table.yaml + - include: + file: db/changelog/changes/10-create-orders-table.yaml + - include: + file: db/changelog/changes/11-create-order-items-table.yaml + - include: + file: db/changelog/changes/12-create-orders-parts-table.yaml \ No newline at end of file From 7ecfd3715f51799fe5a98af5697e8c48ebc223b3 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Mon, 22 Dec 2025 15:42:53 +0200 Subject: [PATCH 06/10] added Order Item service and other little fixes --- .../store/controller/OrderItemController.java | 42 +++++++++++++++++++ .../store/dto/cart/item/CartItemDto.java | 2 + .../springm/store/mapper/CartItemMapper.java | 1 - .../springm/store/mapper/OrderItemMapper.java | 8 +++- .../com/springm/store/model/CartItem.java | 3 ++ .../java/com/springm/store/model/Order.java | 2 + .../com/springm/store/model/OrderItem.java | 5 +++ .../order/item/OrderItemRepository.java | 6 +++ .../store/service/OrderItemService.java | 10 +++++ .../service/impl/OrderItemServiceImpl.java | 35 ++++++++++++++++ .../store/service/impl/OrderServiceImpl.java | 17 ++++++-- .../service/impl/ShoppingCartServiceImpl.java | 1 + .../changes/09-create-cart-items-table.yaml | 5 +++ 13 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/springm/store/controller/OrderItemController.java create mode 100644 src/main/java/com/springm/store/service/OrderItemService.java create mode 100644 src/main/java/com/springm/store/service/impl/OrderItemServiceImpl.java diff --git a/src/main/java/com/springm/store/controller/OrderItemController.java b/src/main/java/com/springm/store/controller/OrderItemController.java new file mode 100644 index 0000000..70f2fbf --- /dev/null +++ b/src/main/java/com/springm/store/controller/OrderItemController.java @@ -0,0 +1,42 @@ +package com.springm.store.controller; + +import com.springm.store.dto.order.item.OrderItemDto; +import com.springm.store.service.OrderItemService; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/orders/{orderId}/items") +@RequiredArgsConstructor +public class OrderItemController { + private final OrderItemService orderItemService; + + + @GetMapping + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") + public ResponseEntity> getOrderItems(@PathVariable Long orderId) { + return new ResponseEntity>( + orderItemService.getItemsByOrderId(orderId), + HttpStatus.OK + ); + } + + + @GetMapping("/{id}") + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") + public ResponseEntity getOrderItem(@PathVariable Long orderId, + @PathVariable Long id) { + return new ResponseEntity( + orderItemService.getItemByOrderIdAndItemId(orderId, id), + HttpStatus.OK + ); + } + +} diff --git a/src/main/java/com/springm/store/dto/cart/item/CartItemDto.java b/src/main/java/com/springm/store/dto/cart/item/CartItemDto.java index 7024619..08c983f 100644 --- a/src/main/java/com/springm/store/dto/cart/item/CartItemDto.java +++ b/src/main/java/com/springm/store/dto/cart/item/CartItemDto.java @@ -1,5 +1,6 @@ package com.springm.store.dto.cart.item; +import java.math.BigDecimal; import lombok.Getter; import lombok.Setter; @@ -10,4 +11,5 @@ public class CartItemDto { private Long bookId; private String bookTitle; private int quantity; + private BigDecimal price; } diff --git a/src/main/java/com/springm/store/mapper/CartItemMapper.java b/src/main/java/com/springm/store/mapper/CartItemMapper.java index 1a5accf..ed7b27e 100644 --- a/src/main/java/com/springm/store/mapper/CartItemMapper.java +++ b/src/main/java/com/springm/store/mapper/CartItemMapper.java @@ -10,7 +10,6 @@ public interface CartItemMapper { @Mapping(source = "book.id", target = "bookId") - @Mapping(source = "book.title", target = "bookTitle") CartItemDto toDto(CartItem cartItem); CartItem toModel(CartItemDto cartItemDto); diff --git a/src/main/java/com/springm/store/mapper/OrderItemMapper.java b/src/main/java/com/springm/store/mapper/OrderItemMapper.java index 820a371..6b01954 100644 --- a/src/main/java/com/springm/store/mapper/OrderItemMapper.java +++ b/src/main/java/com/springm/store/mapper/OrderItemMapper.java @@ -12,7 +12,11 @@ public interface OrderItemMapper { @Mapping(target = "id", ignore = true) @Mapping(target = "order", ignore = true) - OrderItemDto toOrderItemDto(CartItemDto cartItemDto); + OrderItemDto toDtoFromCart(CartItemDto cartItemDto); - OrderItem toOrderItemModel(OrderItemDto orderItemDto); + @Mapping(source = "price", target = "price") + @Mapping(source = "bookId", target = "book.id") + OrderItem toModel(OrderItemDto orderItemDto); + + OrderItemDto toDto(OrderItem orderItem); } diff --git a/src/main/java/com/springm/store/model/CartItem.java b/src/main/java/com/springm/store/model/CartItem.java index b759002..6c47362 100644 --- a/src/main/java/com/springm/store/model/CartItem.java +++ b/src/main/java/com/springm/store/model/CartItem.java @@ -9,6 +9,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; +import java.math.BigDecimal; import lombok.Getter; import lombok.Setter; @@ -32,4 +33,6 @@ public class CartItem { @Column(nullable = false) private int quantity; + @Column(nullable = false) + private BigDecimal price; } diff --git a/src/main/java/com/springm/store/model/Order.java b/src/main/java/com/springm/store/model/Order.java index 31c2de8..0f36f1b 100644 --- a/src/main/java/com/springm/store/model/Order.java +++ b/src/main/java/com/springm/store/model/Order.java @@ -1,5 +1,6 @@ package com.springm.store.model; +import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -55,6 +56,7 @@ public class Order { @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @ToString.Exclude @EqualsAndHashCode.Exclude + @JsonManagedReference @JoinTable( name = "orders_parts", joinColumns = @JoinColumn(name = "order_id"), diff --git a/src/main/java/com/springm/store/model/OrderItem.java b/src/main/java/com/springm/store/model/OrderItem.java index fe65cea..12286c9 100644 --- a/src/main/java/com/springm/store/model/OrderItem.java +++ b/src/main/java/com/springm/store/model/OrderItem.java @@ -1,5 +1,6 @@ package com.springm.store.model; +import com.fasterxml.jackson.annotation.JsonBackReference; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -24,6 +25,7 @@ public class OrderItem { @ManyToOne(optional = false, fetch = FetchType.LAZY) @JoinColumn(name = "order_id", nullable = false) + @JsonBackReference private Order order; @ManyToOne(optional = false, fetch = FetchType.LAZY) @@ -36,3 +38,6 @@ public class OrderItem { @Column(nullable = false) private BigDecimal price; } + +// TODO: дофіксить залупу book_title, якась помилка якщо знов ордер плейсить на рахунок статусів; +// TODO: непонятка з отриманням окремих ітемів в ордері і ордерс хісторі пустий якогось хуя. \ No newline at end of file diff --git a/src/main/java/com/springm/store/repository/order/item/OrderItemRepository.java b/src/main/java/com/springm/store/repository/order/item/OrderItemRepository.java index d174624..90b3cc0 100644 --- a/src/main/java/com/springm/store/repository/order/item/OrderItemRepository.java +++ b/src/main/java/com/springm/store/repository/order/item/OrderItemRepository.java @@ -1,7 +1,13 @@ package com.springm.store.repository.order.item; import com.springm.store.model.OrderItem; +import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; public interface OrderItemRepository extends JpaRepository { + List findByOrderId(Long orderId); + + Optional findByOrderIdAndId(Long orderId, Long id); + } diff --git a/src/main/java/com/springm/store/service/OrderItemService.java b/src/main/java/com/springm/store/service/OrderItemService.java new file mode 100644 index 0000000..3e2b188 --- /dev/null +++ b/src/main/java/com/springm/store/service/OrderItemService.java @@ -0,0 +1,10 @@ +package com.springm.store.service; + +import com.springm.store.dto.order.item.OrderItemDto; +import java.util.List; + +public interface OrderItemService { + List getItemsByOrderId(Long orderId); + + OrderItemDto getItemByOrderIdAndItemId(Long orderId, Long itemId); +} diff --git a/src/main/java/com/springm/store/service/impl/OrderItemServiceImpl.java b/src/main/java/com/springm/store/service/impl/OrderItemServiceImpl.java new file mode 100644 index 0000000..2cc2786 --- /dev/null +++ b/src/main/java/com/springm/store/service/impl/OrderItemServiceImpl.java @@ -0,0 +1,35 @@ +package com.springm.store.service.impl; + +import com.springm.store.dto.order.item.OrderItemDto; +import com.springm.store.exception.EntityNotFoundException; +import com.springm.store.mapper.OrderItemMapper; +import com.springm.store.repository.order.item.OrderItemRepository; +import com.springm.store.service.OrderItemService; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@RequiredArgsConstructor +public class OrderItemServiceImpl implements OrderItemService { + private final OrderItemRepository orderItemRepository; + private final OrderItemMapper orderItemMapper; + + @Override + public List getItemsByOrderId(Long orderId) { + return orderItemRepository.findByOrderId(orderId) + .stream() + .map(orderItemMapper::toDto) + .toList(); + } + + @Override + public OrderItemDto getItemByOrderIdAndItemId(Long orderId, Long itemId) { + return orderItemRepository.findByOrderIdAndId(orderId, itemId) + .map(orderItemMapper::toDto) + .orElseThrow(() -> new EntityNotFoundException("Item not found")); + } + +} diff --git a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java index 2a0b3f7..de2dd43 100644 --- a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java @@ -12,6 +12,7 @@ import com.springm.store.repository.cart.ShoppingCartRepository; import com.springm.store.repository.order.OrderRepository; import com.springm.store.service.OrderService; +import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; import java.util.Set; @@ -49,16 +50,24 @@ public OrderResponseDto placeOrder(String shippingAddress) { Set orderItems = cart.getCartItems().stream() .map(cartItemMapper::toDto) - .map(orderItemMapper::toOrderItemDto) - .map(orderItemMapper::toOrderItemModel) + .map(orderItemMapper::toDtoFromCart) + .map(orderItemMapper::toModel) + .peek(item -> item.setOrder(order)) .collect(Collectors.toSet()); - order.setOrderItems(orderItems); - orderRepository.save(order); cart.clear(); shoppingCartRepository.save(cart); + BigDecimal totalPrice = orderItems.stream() + .map(item -> { + BigDecimal price = item.getPrice() != null ? item.getPrice() : BigDecimal.ZERO; + return price.multiply(BigDecimal.valueOf(item.getQuantity())); + }) + .reduce(BigDecimal.ZERO, BigDecimal::add); + order.setTotal(totalPrice); + orderRepository.save(order); + return orderMapper.toResponseDto(order); } diff --git a/src/main/java/com/springm/store/service/impl/ShoppingCartServiceImpl.java b/src/main/java/com/springm/store/service/impl/ShoppingCartServiceImpl.java index e5371d9..7a8feac 100644 --- a/src/main/java/com/springm/store/service/impl/ShoppingCartServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/ShoppingCartServiceImpl.java @@ -56,6 +56,7 @@ public ShoppingCartResponseDto addItem(AddShoppingCartRequestDto requestDto) { } else { CartItem item = new CartItem(); item.setBook(book); + item.setPrice(book.getPrice()); item.setQuantity(requestDto.getQuantity()); item.setShoppingCart(cart); cart.getCartItems().add(item); diff --git a/src/main/resources/db/changelog/changes/09-create-cart-items-table.yaml b/src/main/resources/db/changelog/changes/09-create-cart-items-table.yaml index 84b124f..fc08705 100644 --- a/src/main/resources/db/changelog/changes/09-create-cart-items-table.yaml +++ b/src/main/resources/db/changelog/changes/09-create-cart-items-table.yaml @@ -35,3 +35,8 @@ databaseChangeLog: type: INT constraints: nullable: false + - column: + name: price + type: decimal + constraints: + nullable: false \ No newline at end of file From 5dea6595fc81d74dc2c3380d61bd8d57e42ba000 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Mon, 22 Dec 2025 16:30:22 +0200 Subject: [PATCH 07/10] added all required things --- .../springm/store/controller/OrderController.java | 9 ++++----- .../store/controller/OrderItemController.java | 2 -- .../springm/store/dto/order/OrderResponseDto.java | 2 +- .../store/dto/order/UpdateOrderStatusDto.java | 11 +++++++++++ .../springm/store/dto/order/item/OrderItemDto.java | 2 -- .../com/springm/store/mapper/CartItemMapper.java | 1 + .../com/springm/store/mapper/OrderItemMapper.java | 12 ++++++++++-- .../java/com/springm/store/mapper/OrderMapper.java | 2 ++ src/main/java/com/springm/store/model/OrderItem.java | 3 --- .../store/repository/order/OrderRepository.java | 4 ++-- .../java/com/springm/store/service/OrderService.java | 4 ++-- .../springm/store/service/impl/OrderServiceImpl.java | 9 ++++++--- .../db/changelog/changes/10-create-orders-table.yaml | 1 - 13 files changed, 39 insertions(+), 23 deletions(-) create mode 100644 src/main/java/com/springm/store/dto/order/UpdateOrderStatusDto.java diff --git a/src/main/java/com/springm/store/controller/OrderController.java b/src/main/java/com/springm/store/controller/OrderController.java index 83e9028..6aa3770 100644 --- a/src/main/java/com/springm/store/controller/OrderController.java +++ b/src/main/java/com/springm/store/controller/OrderController.java @@ -1,7 +1,7 @@ package com.springm.store.controller; import com.springm.store.dto.order.OrderResponseDto; -import com.springm.store.model.Order; +import com.springm.store.dto.order.UpdateOrderStatusDto; import com.springm.store.service.OrderService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -40,7 +40,7 @@ public ResponseEntity placeOrder( @GetMapping @PreAuthorize("hasAnyRole('USER', 'ADMIN')") @Operation(summary = "Receive orders history", description = "Receive orders history") - public ResponseEntity> getAll() { + public ResponseEntity> getOrderHistory() { return new ResponseEntity>( orderService.receiveOrderHistory(), HttpStatus.OK @@ -55,13 +55,12 @@ public ResponseEntity> getAll() { ) public ResponseEntity updateStatus( @PathVariable Long id, - @RequestBody Order.Status orderStatus + @RequestBody UpdateOrderStatusDto orderStatusDto ) { return new ResponseEntity( - orderService.updateOrderStatus(id, orderStatus), + orderService.updateOrderStatus(id, orderStatusDto), HttpStatus.NO_CONTENT ); } - } diff --git a/src/main/java/com/springm/store/controller/OrderItemController.java b/src/main/java/com/springm/store/controller/OrderItemController.java index 70f2fbf..fd931c3 100644 --- a/src/main/java/com/springm/store/controller/OrderItemController.java +++ b/src/main/java/com/springm/store/controller/OrderItemController.java @@ -18,7 +18,6 @@ public class OrderItemController { private final OrderItemService orderItemService; - @GetMapping @PreAuthorize("hasAnyRole('USER', 'ADMIN')") public ResponseEntity> getOrderItems(@PathVariable Long orderId) { @@ -28,7 +27,6 @@ public ResponseEntity> getOrderItems(@PathVariable Long order ); } - @GetMapping("/{id}") @PreAuthorize("hasAnyRole('USER', 'ADMIN')") public ResponseEntity getOrderItem(@PathVariable Long orderId, diff --git a/src/main/java/com/springm/store/dto/order/OrderResponseDto.java b/src/main/java/com/springm/store/dto/order/OrderResponseDto.java index 4a02f92..a6e7c4b 100644 --- a/src/main/java/com/springm/store/dto/order/OrderResponseDto.java +++ b/src/main/java/com/springm/store/dto/order/OrderResponseDto.java @@ -13,8 +13,8 @@ public class OrderResponseDto { private Long id; private Long userId; - private List orderItems; private LocalDateTime orderDate; private BigDecimal total; private Order.Status orderStatus; + private List orderItems; } diff --git a/src/main/java/com/springm/store/dto/order/UpdateOrderStatusDto.java b/src/main/java/com/springm/store/dto/order/UpdateOrderStatusDto.java new file mode 100644 index 0000000..5f3a3ed --- /dev/null +++ b/src/main/java/com/springm/store/dto/order/UpdateOrderStatusDto.java @@ -0,0 +1,11 @@ +package com.springm.store.dto.order; + +import com.springm.store.model.Order; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class UpdateOrderStatusDto { + private Order.Status status; +} diff --git a/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java b/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java index dd9c627..2d99042 100644 --- a/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java +++ b/src/main/java/com/springm/store/dto/order/item/OrderItemDto.java @@ -1,6 +1,5 @@ package com.springm.store.dto.order.item; -import com.springm.store.model.Order; import java.math.BigDecimal; import lombok.Getter; import lombok.Setter; @@ -9,7 +8,6 @@ @Setter public class OrderItemDto { private Long id; - private Order order; private Long bookId; private String bookTitle; private int quantity; diff --git a/src/main/java/com/springm/store/mapper/CartItemMapper.java b/src/main/java/com/springm/store/mapper/CartItemMapper.java index ed7b27e..1a5accf 100644 --- a/src/main/java/com/springm/store/mapper/CartItemMapper.java +++ b/src/main/java/com/springm/store/mapper/CartItemMapper.java @@ -10,6 +10,7 @@ public interface CartItemMapper { @Mapping(source = "book.id", target = "bookId") + @Mapping(source = "book.title", target = "bookTitle") CartItemDto toDto(CartItem cartItem); CartItem toModel(CartItemDto cartItemDto); diff --git a/src/main/java/com/springm/store/mapper/OrderItemMapper.java b/src/main/java/com/springm/store/mapper/OrderItemMapper.java index 6b01954..eb5fb01 100644 --- a/src/main/java/com/springm/store/mapper/OrderItemMapper.java +++ b/src/main/java/com/springm/store/mapper/OrderItemMapper.java @@ -11,12 +11,20 @@ public interface OrderItemMapper { @Mapping(target = "id", ignore = true) - @Mapping(target = "order", ignore = true) + @Mapping(source = "bookId", target = "bookId") + @Mapping(source = "bookTitle", target = "bookTitle") + @Mapping(source = "quantity", target = "quantity") + @Mapping(source = "price", target = "price") OrderItemDto toDtoFromCart(CartItemDto cartItemDto); - @Mapping(source = "price", target = "price") @Mapping(source = "bookId", target = "book.id") + @Mapping(source = "bookTitle", target = "book.title") + @Mapping(source = "price", target = "price") + @Mapping(source = "quantity", target = "quantity") OrderItem toModel(OrderItemDto orderItemDto); + @Mapping(source = "book.id", target = "bookId") + @Mapping(source = "book.title", target = "bookTitle") OrderItemDto toDto(OrderItem orderItem); + } diff --git a/src/main/java/com/springm/store/mapper/OrderMapper.java b/src/main/java/com/springm/store/mapper/OrderMapper.java index 4945cbf..ee4ccd8 100644 --- a/src/main/java/com/springm/store/mapper/OrderMapper.java +++ b/src/main/java/com/springm/store/mapper/OrderMapper.java @@ -10,6 +10,8 @@ public interface OrderMapper { @Mapping(source = "id", target = "id") @Mapping(source = "user.id", target = "userId") + @Mapping(source = "status", target = "orderStatus") @Mapping(source = "orderItems", target = "orderItems") OrderResponseDto toResponseDto(Order order); + } diff --git a/src/main/java/com/springm/store/model/OrderItem.java b/src/main/java/com/springm/store/model/OrderItem.java index 12286c9..dcb631f 100644 --- a/src/main/java/com/springm/store/model/OrderItem.java +++ b/src/main/java/com/springm/store/model/OrderItem.java @@ -38,6 +38,3 @@ public class OrderItem { @Column(nullable = false) private BigDecimal price; } - -// TODO: дофіксить залупу book_title, якась помилка якщо знов ордер плейсить на рахунок статусів; -// TODO: непонятка з отриманням окремих ітемів в ордері і ордерс хісторі пустий якогось хуя. \ No newline at end of file diff --git a/src/main/java/com/springm/store/repository/order/OrderRepository.java b/src/main/java/com/springm/store/repository/order/OrderRepository.java index 5c1c76e..528cdf3 100644 --- a/src/main/java/com/springm/store/repository/order/OrderRepository.java +++ b/src/main/java/com/springm/store/repository/order/OrderRepository.java @@ -2,9 +2,9 @@ import com.springm.store.model.Order; import com.springm.store.model.User; -import java.util.Optional; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; public interface OrderRepository extends JpaRepository { - Optional findByUser(User user); + List findByUser(User user); } diff --git a/src/main/java/com/springm/store/service/OrderService.java b/src/main/java/com/springm/store/service/OrderService.java index 7f48e73..ca410f0 100644 --- a/src/main/java/com/springm/store/service/OrderService.java +++ b/src/main/java/com/springm/store/service/OrderService.java @@ -1,7 +1,7 @@ package com.springm.store.service; import com.springm.store.dto.order.OrderResponseDto; -import com.springm.store.model.Order; +import com.springm.store.dto.order.UpdateOrderStatusDto; import java.util.List; public interface OrderService { @@ -9,6 +9,6 @@ public interface OrderService { List receiveOrderHistory(); - OrderResponseDto updateOrderStatus(Long orderId, Order.Status orderStatus); + OrderResponseDto updateOrderStatus(Long orderId, UpdateOrderStatusDto orderStatus); } diff --git a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java index de2dd43..f0e1853 100644 --- a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java @@ -1,6 +1,7 @@ package com.springm.store.service.impl; import com.springm.store.dto.order.OrderResponseDto; +import com.springm.store.dto.order.UpdateOrderStatusDto; import com.springm.store.exception.EntityNotFoundException; import com.springm.store.mapper.CartItemMapper; import com.springm.store.mapper.OrderItemMapper; @@ -36,7 +37,9 @@ public class OrderServiceImpl implements OrderService { public OrderResponseDto placeOrder(String shippingAddress) { User user = userDetailsService.getCurrentUser(); ShoppingCart cart = shoppingCartRepository.findByUser(user) - .orElseThrow(() -> new EntityNotFoundException(user.getUsername() + " cart not found!")); + .orElseThrow(() -> new EntityNotFoundException( + user.getUsername() + " cart not found!" + )); if (cart.getCartItems().isEmpty()) { throw new IllegalArgumentException("Order can't be empty!"); @@ -80,12 +83,12 @@ public List receiveOrderHistory() { } @Override - public OrderResponseDto updateOrderStatus(Long orderId, Order.Status orderStatus) { + public OrderResponseDto updateOrderStatus(Long orderId, UpdateOrderStatusDto orderStatus) { Order order = orderRepository.findById(orderId) .orElseThrow(() -> new EntityNotFoundException( "Order with id " + orderId + " not found!" )); - order.setStatus(orderStatus); + order.setStatus(orderStatus.getStatus()); return orderMapper.toResponseDto(orderRepository.save(order)); } } diff --git a/src/main/resources/db/changelog/changes/10-create-orders-table.yaml b/src/main/resources/db/changelog/changes/10-create-orders-table.yaml index 699b116..7d3029e 100644 --- a/src/main/resources/db/changelog/changes/10-create-orders-table.yaml +++ b/src/main/resources/db/changelog/changes/10-create-orders-table.yaml @@ -25,7 +25,6 @@ databaseChangeLog: type: varchar(255) constraints: nullable: false - unique: true - column: name: total type: decimal From 76c918da357fd824dc9efa245994cf2143d52a3d Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Wed, 24 Dec 2025 12:15:31 +0200 Subject: [PATCH 08/10] added validation for Status dto --- .../store/dto/order/UpdateOrderStatusDto.java | 2 ++ .../store/validation/order/Status.java | 22 ++++++++++++++++ .../validation/order/StatusValidator.java | 26 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 src/main/java/com/springm/store/validation/order/Status.java create mode 100644 src/main/java/com/springm/store/validation/order/StatusValidator.java diff --git a/src/main/java/com/springm/store/dto/order/UpdateOrderStatusDto.java b/src/main/java/com/springm/store/dto/order/UpdateOrderStatusDto.java index 5f3a3ed..cbd5187 100644 --- a/src/main/java/com/springm/store/dto/order/UpdateOrderStatusDto.java +++ b/src/main/java/com/springm/store/dto/order/UpdateOrderStatusDto.java @@ -1,11 +1,13 @@ package com.springm.store.dto.order; import com.springm.store.model.Order; +import com.springm.store.validation.order.Status; import lombok.Getter; import lombok.Setter; @Getter @Setter public class UpdateOrderStatusDto { + @Status(enumClass = Order.Status.class) private Order.Status status; } diff --git a/src/main/java/com/springm/store/validation/order/Status.java b/src/main/java/com/springm/store/validation/order/Status.java new file mode 100644 index 0000000..a24950a --- /dev/null +++ b/src/main/java/com/springm/store/validation/order/Status.java @@ -0,0 +1,22 @@ +package com.springm.store.validation.order; + +import com.springm.store.validation.user.EmailValidator; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Constraint(validatedBy = EmailValidator.class) +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Status { + Class> enumClass(); + + String message() default "Invalid order status!"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/src/main/java/com/springm/store/validation/order/StatusValidator.java b/src/main/java/com/springm/store/validation/order/StatusValidator.java new file mode 100644 index 0000000..b3d9fe1 --- /dev/null +++ b/src/main/java/com/springm/store/validation/order/StatusValidator.java @@ -0,0 +1,26 @@ +package com.springm.store.validation.order; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +public class StatusValidator implements ConstraintValidator { + private Set values; + + @Override + public void initialize(Status constraintAnnotation) { + values = Arrays.stream(constraintAnnotation.enumClass().getEnumConstants()) + .map(Enum::name) + .collect(Collectors.toSet()); + } + + @Override + public boolean isValid(String status, + ConstraintValidatorContext constraintValidatorContext + ) { + return status != null && values.contains(status); + } + +} From 90217e9ffa2c6c0c85fbbfe0f1e8dda1dc4a533e Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Wed, 24 Dec 2025 12:24:11 +0200 Subject: [PATCH 09/10] removed OrderItem controller and service, also removed yaml file for creating orders_parts --- .../store/controller/OrderController.java | 20 ++++++++++ .../store/controller/OrderItemController.java | 40 ------------------- .../exception/UserNotFoundException.java | 7 ---- .../springm/store/mapper/OrderItemMapper.java | 6 --- .../java/com/springm/store/model/Order.java | 9 +---- .../store/service/OrderItemService.java | 10 ----- .../springm/store/service/OrderService.java | 4 ++ .../service/impl/OrderItemServiceImpl.java | 35 ---------------- .../store/service/impl/OrderServiceImpl.java | 18 +++++++++ .../service/impl/UserDetailsServiceImpl.java | 4 +- .../changes/12-create-orders-parts-table.yaml | 40 ------------------- .../db/changelog/db.changelog-master.yaml | 2 - 12 files changed, 46 insertions(+), 149 deletions(-) delete mode 100644 src/main/java/com/springm/store/controller/OrderItemController.java delete mode 100644 src/main/java/com/springm/store/exception/UserNotFoundException.java delete mode 100644 src/main/java/com/springm/store/service/OrderItemService.java delete mode 100644 src/main/java/com/springm/store/service/impl/OrderItemServiceImpl.java delete mode 100644 src/main/resources/db/changelog/changes/12-create-orders-parts-table.yaml diff --git a/src/main/java/com/springm/store/controller/OrderController.java b/src/main/java/com/springm/store/controller/OrderController.java index 6aa3770..a377745 100644 --- a/src/main/java/com/springm/store/controller/OrderController.java +++ b/src/main/java/com/springm/store/controller/OrderController.java @@ -2,6 +2,7 @@ import com.springm.store.dto.order.OrderResponseDto; import com.springm.store.dto.order.UpdateOrderStatusDto; +import com.springm.store.dto.order.item.OrderItemDto; import com.springm.store.service.OrderService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -63,4 +64,23 @@ public ResponseEntity updateStatus( ); } + @GetMapping("/orders/{orderId}/items") + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") + public ResponseEntity> getOrderItems(@PathVariable Long orderId) { + return new ResponseEntity>( + orderService.getItemsByOrderId(orderId), + HttpStatus.OK + ); + } + + @GetMapping("/orders/{orderId}/items/{id}") + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") + public ResponseEntity getOrderItem(@PathVariable Long orderId, + @PathVariable Long id) { + return new ResponseEntity( + orderService.getItemByOrderIdAndItemId(orderId, id), + HttpStatus.OK + ); + } + } diff --git a/src/main/java/com/springm/store/controller/OrderItemController.java b/src/main/java/com/springm/store/controller/OrderItemController.java deleted file mode 100644 index fd931c3..0000000 --- a/src/main/java/com/springm/store/controller/OrderItemController.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.springm.store.controller; - -import com.springm.store.dto.order.item.OrderItemDto; -import com.springm.store.service.OrderItemService; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/orders/{orderId}/items") -@RequiredArgsConstructor -public class OrderItemController { - private final OrderItemService orderItemService; - - @GetMapping - @PreAuthorize("hasAnyRole('USER', 'ADMIN')") - public ResponseEntity> getOrderItems(@PathVariable Long orderId) { - return new ResponseEntity>( - orderItemService.getItemsByOrderId(orderId), - HttpStatus.OK - ); - } - - @GetMapping("/{id}") - @PreAuthorize("hasAnyRole('USER', 'ADMIN')") - public ResponseEntity getOrderItem(@PathVariable Long orderId, - @PathVariable Long id) { - return new ResponseEntity( - orderItemService.getItemByOrderIdAndItemId(orderId, id), - HttpStatus.OK - ); - } - -} diff --git a/src/main/java/com/springm/store/exception/UserNotFoundException.java b/src/main/java/com/springm/store/exception/UserNotFoundException.java deleted file mode 100644 index 2846b90..0000000 --- a/src/main/java/com/springm/store/exception/UserNotFoundException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.springm.store.exception; - -public class UserNotFoundException extends RuntimeException { - public UserNotFoundException(String message) { - super(message); - } -} diff --git a/src/main/java/com/springm/store/mapper/OrderItemMapper.java b/src/main/java/com/springm/store/mapper/OrderItemMapper.java index eb5fb01..2581d20 100644 --- a/src/main/java/com/springm/store/mapper/OrderItemMapper.java +++ b/src/main/java/com/springm/store/mapper/OrderItemMapper.java @@ -11,16 +11,10 @@ public interface OrderItemMapper { @Mapping(target = "id", ignore = true) - @Mapping(source = "bookId", target = "bookId") - @Mapping(source = "bookTitle", target = "bookTitle") - @Mapping(source = "quantity", target = "quantity") - @Mapping(source = "price", target = "price") OrderItemDto toDtoFromCart(CartItemDto cartItemDto); @Mapping(source = "bookId", target = "book.id") @Mapping(source = "bookTitle", target = "book.title") - @Mapping(source = "price", target = "price") - @Mapping(source = "quantity", target = "quantity") OrderItem toModel(OrderItemDto orderItemDto); @Mapping(source = "book.id", target = "bookId") diff --git a/src/main/java/com/springm/store/model/Order.java b/src/main/java/com/springm/store/model/Order.java index 0f36f1b..164418a 100644 --- a/src/main/java/com/springm/store/model/Order.java +++ b/src/main/java/com/springm/store/model/Order.java @@ -6,6 +6,7 @@ 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; @@ -36,7 +37,7 @@ public class Order { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) private User user; @@ -56,12 +57,6 @@ public class Order { @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @ToString.Exclude @EqualsAndHashCode.Exclude - @JsonManagedReference - @JoinTable( - name = "orders_parts", - joinColumns = @JoinColumn(name = "order_id"), - inverseJoinColumns = @JoinColumn(name = "order_item_id") - ) private Set orderItems = new HashSet<>(); public enum Status { diff --git a/src/main/java/com/springm/store/service/OrderItemService.java b/src/main/java/com/springm/store/service/OrderItemService.java deleted file mode 100644 index 3e2b188..0000000 --- a/src/main/java/com/springm/store/service/OrderItemService.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.springm.store.service; - -import com.springm.store.dto.order.item.OrderItemDto; -import java.util.List; - -public interface OrderItemService { - List getItemsByOrderId(Long orderId); - - OrderItemDto getItemByOrderIdAndItemId(Long orderId, Long itemId); -} diff --git a/src/main/java/com/springm/store/service/OrderService.java b/src/main/java/com/springm/store/service/OrderService.java index ca410f0..6c050ca 100644 --- a/src/main/java/com/springm/store/service/OrderService.java +++ b/src/main/java/com/springm/store/service/OrderService.java @@ -2,6 +2,7 @@ import com.springm.store.dto.order.OrderResponseDto; import com.springm.store.dto.order.UpdateOrderStatusDto; +import com.springm.store.dto.order.item.OrderItemDto; import java.util.List; public interface OrderService { @@ -11,4 +12,7 @@ public interface OrderService { OrderResponseDto updateOrderStatus(Long orderId, UpdateOrderStatusDto orderStatus); + List getItemsByOrderId(Long orderId); + + OrderItemDto getItemByOrderIdAndItemId(Long orderId, Long itemId); } diff --git a/src/main/java/com/springm/store/service/impl/OrderItemServiceImpl.java b/src/main/java/com/springm/store/service/impl/OrderItemServiceImpl.java deleted file mode 100644 index 2cc2786..0000000 --- a/src/main/java/com/springm/store/service/impl/OrderItemServiceImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.springm.store.service.impl; - -import com.springm.store.dto.order.item.OrderItemDto; -import com.springm.store.exception.EntityNotFoundException; -import com.springm.store.mapper.OrderItemMapper; -import com.springm.store.repository.order.item.OrderItemRepository; -import com.springm.store.service.OrderItemService; -import java.util.List; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional -@RequiredArgsConstructor -public class OrderItemServiceImpl implements OrderItemService { - private final OrderItemRepository orderItemRepository; - private final OrderItemMapper orderItemMapper; - - @Override - public List getItemsByOrderId(Long orderId) { - return orderItemRepository.findByOrderId(orderId) - .stream() - .map(orderItemMapper::toDto) - .toList(); - } - - @Override - public OrderItemDto getItemByOrderIdAndItemId(Long orderId, Long itemId) { - return orderItemRepository.findByOrderIdAndId(orderId, itemId) - .map(orderItemMapper::toDto) - .orElseThrow(() -> new EntityNotFoundException("Item not found")); - } - -} diff --git a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java index f0e1853..c7dd212 100644 --- a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java @@ -2,6 +2,7 @@ import com.springm.store.dto.order.OrderResponseDto; import com.springm.store.dto.order.UpdateOrderStatusDto; +import com.springm.store.dto.order.item.OrderItemDto; import com.springm.store.exception.EntityNotFoundException; import com.springm.store.mapper.CartItemMapper; import com.springm.store.mapper.OrderItemMapper; @@ -12,6 +13,7 @@ import com.springm.store.model.User; import com.springm.store.repository.cart.ShoppingCartRepository; import com.springm.store.repository.order.OrderRepository; +import com.springm.store.repository.order.item.OrderItemRepository; import com.springm.store.service.OrderService; import java.math.BigDecimal; import java.time.LocalDateTime; @@ -27,6 +29,7 @@ @RequiredArgsConstructor public class OrderServiceImpl implements OrderService { private final OrderRepository orderRepository; + private final OrderItemRepository orderItemRepository; private final ShoppingCartRepository shoppingCartRepository; private final OrderMapper orderMapper; private final OrderItemMapper orderItemMapper; @@ -91,4 +94,19 @@ public OrderResponseDto updateOrderStatus(Long orderId, UpdateOrderStatusDto ord order.setStatus(orderStatus.getStatus()); return orderMapper.toResponseDto(orderRepository.save(order)); } + + @Override + public List getItemsByOrderId(Long orderId) { + return orderItemRepository.findByOrderId(orderId) + .stream() + .map(orderItemMapper::toDto) + .toList(); + } + + @Override + public OrderItemDto getItemByOrderIdAndItemId(Long orderId, Long itemId) { + return orderItemRepository.findByOrderIdAndId(orderId, itemId) + .map(orderItemMapper::toDto) + .orElseThrow(() -> new EntityNotFoundException("Item not found")); + } } diff --git a/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java b/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java index adcd5fd..da4415e 100644 --- a/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/UserDetailsServiceImpl.java @@ -1,6 +1,6 @@ package com.springm.store.service.impl; -import com.springm.store.exception.UserNotFoundException; +import com.springm.store.exception.EntityNotFoundException; import com.springm.store.model.User; import com.springm.store.repository.user.UserRepository; import lombok.RequiredArgsConstructor; @@ -37,7 +37,7 @@ public Long getCurrentUserId() { public User getCurrentUser() { Long userId = getCurrentUserId(); return userRepository.findById(userId) - .orElseThrow(() -> new UserNotFoundException( + .orElseThrow(() -> new EntityNotFoundException( "User with id " + userId + " not found!" )); } diff --git a/src/main/resources/db/changelog/changes/12-create-orders-parts-table.yaml b/src/main/resources/db/changelog/changes/12-create-orders-parts-table.yaml deleted file mode 100644 index 4f975d1..0000000 --- a/src/main/resources/db/changelog/changes/12-create-orders-parts-table.yaml +++ /dev/null @@ -1,40 +0,0 @@ -databaseChangeLog: - - changeSet: - id: create-books-categories-table - author: jelors - changes: - - createTable: - tableName: orders_parts - columns: - - column: - name: order_id - type: BIGINT - constraints: - nullable: false - - - column: - name: order_item_id - type: BIGINT - constraints: - nullable: false - - - addForeignKeyConstraint: - baseTableName: orders_parts - baseColumnNames: order_id - referencedTableName: orders - referencedColumnNames: id - onDelete: CASCADE - constraintName: fk_orders_parts_order - - - addForeignKeyConstraint: - baseTableName: orders_parts - baseColumnNames: order_item_id - referencedTableName: order_items - referencedColumnNames: id - onDelete: CASCADE - constraintName: fk_orders_parts_order_item - - - addUniqueConstraint: - tableName: orders_parts - columnNames: order_id, order_item_id - constraintName: uk_orders_parts_unique diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 44c397a..1a705a2 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -21,5 +21,3 @@ databaseChangeLog: file: db/changelog/changes/10-create-orders-table.yaml - include: file: db/changelog/changes/11-create-order-items-table.yaml - - include: - file: db/changelog/changes/12-create-orders-parts-table.yaml \ No newline at end of file From 302b7b881c75c867ee6ef0d9a8684fc8f8c766b2 Mon Sep 17 00:00:00 2001 From: Andrii Honchar Date: Wed, 24 Dec 2025 12:46:21 +0200 Subject: [PATCH 10/10] fixes due to mentor's advice --- .../springm/store/controller/OrderController.java | 7 ++++--- .../store/dto/order/AddShippingAddressDto.java | 12 ++++++++++++ src/main/java/com/springm/store/model/Order.java | 4 +--- src/main/java/com/springm/store/model/OrderItem.java | 2 -- .../java/com/springm/store/service/OrderService.java | 3 ++- .../springm/store/service/impl/OrderServiceImpl.java | 5 +++-- 6 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/springm/store/dto/order/AddShippingAddressDto.java diff --git a/src/main/java/com/springm/store/controller/OrderController.java b/src/main/java/com/springm/store/controller/OrderController.java index a377745..e086c5a 100644 --- a/src/main/java/com/springm/store/controller/OrderController.java +++ b/src/main/java/com/springm/store/controller/OrderController.java @@ -1,5 +1,6 @@ package com.springm.store.controller; +import com.springm.store.dto.order.AddShippingAddressDto; import com.springm.store.dto.order.OrderResponseDto; import com.springm.store.dto.order.UpdateOrderStatusDto; import com.springm.store.dto.order.item.OrderItemDto; @@ -30,7 +31,7 @@ public class OrderController { @PreAuthorize("hasAnyRole('USER', 'ADMIN')") @Operation(summary = "Place an order", description = "Place an order") public ResponseEntity placeOrder( - @RequestBody String shippingAddress + @RequestBody AddShippingAddressDto shippingAddress ) { return new ResponseEntity( orderService.placeOrder(shippingAddress), @@ -64,7 +65,7 @@ public ResponseEntity updateStatus( ); } - @GetMapping("/orders/{orderId}/items") + @GetMapping("/{orderId}/items") @PreAuthorize("hasAnyRole('USER', 'ADMIN')") public ResponseEntity> getOrderItems(@PathVariable Long orderId) { return new ResponseEntity>( @@ -73,7 +74,7 @@ public ResponseEntity> getOrderItems(@PathVariable Long order ); } - @GetMapping("/orders/{orderId}/items/{id}") + @GetMapping("/{orderId}/items/{id}") @PreAuthorize("hasAnyRole('USER', 'ADMIN')") public ResponseEntity getOrderItem(@PathVariable Long orderId, @PathVariable Long id) { diff --git a/src/main/java/com/springm/store/dto/order/AddShippingAddressDto.java b/src/main/java/com/springm/store/dto/order/AddShippingAddressDto.java new file mode 100644 index 0000000..44b5302 --- /dev/null +++ b/src/main/java/com/springm/store/dto/order/AddShippingAddressDto.java @@ -0,0 +1,12 @@ +package com.springm.store.dto.order; + +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AddShippingAddressDto { + @NotBlank + private String shippingAddress; +} diff --git a/src/main/java/com/springm/store/model/Order.java b/src/main/java/com/springm/store/model/Order.java index 164418a..d8089b0 100644 --- a/src/main/java/com/springm/store/model/Order.java +++ b/src/main/java/com/springm/store/model/Order.java @@ -1,6 +1,5 @@ package com.springm.store.model; -import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -11,7 +10,6 @@ import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; -import jakarta.persistence.JoinTable; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; @@ -54,7 +52,7 @@ public class Order { @Column(nullable = false) private String shippingAddress; - @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true) @ToString.Exclude @EqualsAndHashCode.Exclude private Set orderItems = new HashSet<>(); diff --git a/src/main/java/com/springm/store/model/OrderItem.java b/src/main/java/com/springm/store/model/OrderItem.java index dcb631f..fe65cea 100644 --- a/src/main/java/com/springm/store/model/OrderItem.java +++ b/src/main/java/com/springm/store/model/OrderItem.java @@ -1,6 +1,5 @@ package com.springm.store.model; -import com.fasterxml.jackson.annotation.JsonBackReference; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -25,7 +24,6 @@ public class OrderItem { @ManyToOne(optional = false, fetch = FetchType.LAZY) @JoinColumn(name = "order_id", nullable = false) - @JsonBackReference private Order order; @ManyToOne(optional = false, fetch = FetchType.LAZY) diff --git a/src/main/java/com/springm/store/service/OrderService.java b/src/main/java/com/springm/store/service/OrderService.java index 6c050ca..27cf42e 100644 --- a/src/main/java/com/springm/store/service/OrderService.java +++ b/src/main/java/com/springm/store/service/OrderService.java @@ -1,12 +1,13 @@ package com.springm.store.service; +import com.springm.store.dto.order.AddShippingAddressDto; import com.springm.store.dto.order.OrderResponseDto; import com.springm.store.dto.order.UpdateOrderStatusDto; import com.springm.store.dto.order.item.OrderItemDto; import java.util.List; public interface OrderService { - OrderResponseDto placeOrder(String shippingAddress); + OrderResponseDto placeOrder(AddShippingAddressDto shippingAddressDto); List receiveOrderHistory(); diff --git a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java index c7dd212..ae1aa4d 100644 --- a/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java +++ b/src/main/java/com/springm/store/service/impl/OrderServiceImpl.java @@ -1,5 +1,6 @@ package com.springm.store.service.impl; +import com.springm.store.dto.order.AddShippingAddressDto; import com.springm.store.dto.order.OrderResponseDto; import com.springm.store.dto.order.UpdateOrderStatusDto; import com.springm.store.dto.order.item.OrderItemDto; @@ -37,7 +38,7 @@ public class OrderServiceImpl implements OrderService { private final UserDetailsServiceImpl userDetailsService; @Override - public OrderResponseDto placeOrder(String shippingAddress) { + public OrderResponseDto placeOrder(AddShippingAddressDto shippingAddressDto) { User user = userDetailsService.getCurrentUser(); ShoppingCart cart = shoppingCartRepository.findByUser(user) .orElseThrow(() -> new EntityNotFoundException( @@ -50,7 +51,7 @@ public OrderResponseDto placeOrder(String shippingAddress) { Order order = new Order(); order.setUser(user); - order.setShippingAddress(shippingAddress); + order.setShippingAddress(shippingAddressDto.getShippingAddress()); order.setOrderDate(LocalDateTime.now()); order.setStatus(Order.Status.ORDER_PLACED);