From 8d60122bd1adbefc42f100ea744525d79ee326f2 Mon Sep 17 00:00:00 2001 From: Bogdan <97698639+don-bigdad@users.noreply.github.com> Date: Wed, 15 Nov 2023 20:46:58 +0200 Subject: [PATCH] implement order logic --- .../controller/OrderController.java | 77 ++++++++++++ .../dto/order/OrderDto.java | 14 +++ .../dto/order/OrderItemDto.java | 6 + .../dto/order/RequestOrderDto.java | 6 + .../dto/order/UpdateRequestOrderStatus.java | 7 ++ .../springbootbookshop/entity/Book.java | 2 + .../springbootbookshop/entity/CartItem.java | 2 +- .../springbootbookshop/entity/Order.java | 60 +++++++++ .../springbootbookshop/entity/OrderItem.java | 49 ++++++++ .../springbootbookshop/entity/Status.java | 9 ++ .../mapper/OrderItemMapper.java | 18 +++ .../mapper/OrderMapper.java | 18 +++ .../repository/CartItemsRepository.java | 3 + .../repository/OrderItemsRepository.java | 16 +++ .../repository/OrderRepository.java | 14 +++ .../service/OrderService.java | 20 +++ .../service/impl/CartServiceImpl.java | 15 +-- .../service/impl/OrderServiceImpl.java | 117 ++++++++++++++++++ .../09-add-cart-id-to-users-table.yaml | 19 --- .../changes/09-add-orders-table.yaml | 53 ++++++++ .../changes/10-create-orders-items-table.yaml | 55 ++++++++ .../db/changelog/db.changelog-master.yaml | 6 +- 22 files changed, 558 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/example/springbootbookshop/controller/OrderController.java create mode 100644 src/main/java/com/example/springbootbookshop/dto/order/OrderDto.java create mode 100644 src/main/java/com/example/springbootbookshop/dto/order/OrderItemDto.java create mode 100644 src/main/java/com/example/springbootbookshop/dto/order/RequestOrderDto.java create mode 100644 src/main/java/com/example/springbootbookshop/dto/order/UpdateRequestOrderStatus.java create mode 100644 src/main/java/com/example/springbootbookshop/entity/Order.java create mode 100644 src/main/java/com/example/springbootbookshop/entity/OrderItem.java create mode 100644 src/main/java/com/example/springbootbookshop/entity/Status.java create mode 100644 src/main/java/com/example/springbootbookshop/mapper/OrderItemMapper.java create mode 100644 src/main/java/com/example/springbootbookshop/mapper/OrderMapper.java create mode 100644 src/main/java/com/example/springbootbookshop/repository/OrderItemsRepository.java create mode 100644 src/main/java/com/example/springbootbookshop/repository/OrderRepository.java create mode 100644 src/main/java/com/example/springbootbookshop/service/OrderService.java create mode 100644 src/main/java/com/example/springbootbookshop/service/impl/OrderServiceImpl.java delete mode 100644 src/main/resources/db/changelog/changes/09-add-cart-id-to-users-table.yaml create mode 100644 src/main/resources/db/changelog/changes/09-add-orders-table.yaml create mode 100644 src/main/resources/db/changelog/changes/10-create-orders-items-table.yaml diff --git a/src/main/java/com/example/springbootbookshop/controller/OrderController.java b/src/main/java/com/example/springbootbookshop/controller/OrderController.java new file mode 100644 index 0000000..1fdaf6d --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/controller/OrderController.java @@ -0,0 +1,77 @@ +package com.example.springbootbookshop.controller; + +import com.example.springbootbookshop.dto.cart.CartDto; +import com.example.springbootbookshop.dto.order.OrderDto; +import com.example.springbootbookshop.dto.order.OrderItemDto; +import com.example.springbootbookshop.dto.order.RequestOrderDto; +import com.example.springbootbookshop.dto.order.UpdateRequestOrderStatus; +import com.example.springbootbookshop.entity.User; +import com.example.springbootbookshop.service.OrderService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.constraints.Positive; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequiredArgsConstructor +@Tag(name = "Order management",description = "Endpoints make orders") +@RestController +@RequestMapping("/orders") +public class OrderController { + private final OrderService orderService; + + @PostMapping + @Operation(summary = "Make order") + @PreAuthorize("hasRole('USER')") + public CartDto makeOrder(Authentication authentication, + @RequestBody RequestOrderDto requestOrderDto) { + return orderService.save(getUserId(authentication), requestOrderDto); + } + + @PatchMapping("/{orderId}") + @Operation(summary = "Update order status (for admin only)") + @PreAuthorize("hasRole('ADMIN')") + public void updateStatus(@Positive @PathVariable Long orderId, + @RequestBody UpdateRequestOrderStatus updateStatus) { + orderService.updateOrderStatus(orderId, updateStatus); + } + + @GetMapping + @Operation(summary = "Get order history") + @PreAuthorize("hasRole('USER')") + public Set showOrderHistory(Authentication authentication) { + return orderService.showAllOrders(getUserId(authentication)); + } + + @GetMapping("/{orderId}/items/{itemId}") + @Operation(summary = "Get special item from order history") + @PreAuthorize("hasRole('USER')") + public OrderItemDto showOrderItem(Authentication authentication, + @PathVariable @Positive Long orderId, + @PathVariable @Positive Long itemId) { + return orderService.getOrderItem(getUserId(authentication), + orderId, itemId); + } + + @GetMapping("/{orderId}/items") + @Operation(summary = "Get special order from user history") + @PreAuthorize("hasRole('USER')") + public Set showOrder(Authentication authentication, + @PathVariable Long orderId) { + return orderService.getOrder(getUserId(authentication), orderId); + } + + private Long getUserId(Authentication authentication) { + User user = (User) authentication.getPrincipal(); + return user.getId(); + } +} diff --git a/src/main/java/com/example/springbootbookshop/dto/order/OrderDto.java b/src/main/java/com/example/springbootbookshop/dto/order/OrderDto.java new file mode 100644 index 0000000..e8cda7a --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/dto/order/OrderDto.java @@ -0,0 +1,14 @@ +package com.example.springbootbookshop.dto.order; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Set; + +public record OrderDto(Long id, + Long userId, + String status, + Set orderItems, + BigDecimal total, + LocalDateTime orderDate, + String shippingAddress) { +} diff --git a/src/main/java/com/example/springbootbookshop/dto/order/OrderItemDto.java b/src/main/java/com/example/springbootbookshop/dto/order/OrderItemDto.java new file mode 100644 index 0000000..6c788c2 --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/dto/order/OrderItemDto.java @@ -0,0 +1,6 @@ +package com.example.springbootbookshop.dto.order; + +public record OrderItemDto(Long id, + Long bookId, + Integer quantity){ +} diff --git a/src/main/java/com/example/springbootbookshop/dto/order/RequestOrderDto.java b/src/main/java/com/example/springbootbookshop/dto/order/RequestOrderDto.java new file mode 100644 index 0000000..356e49b --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/dto/order/RequestOrderDto.java @@ -0,0 +1,6 @@ +package com.example.springbootbookshop.dto.order; + +import jakarta.validation.constraints.NotBlank; + +public record RequestOrderDto(@NotBlank String shippingAddress) { +} diff --git a/src/main/java/com/example/springbootbookshop/dto/order/UpdateRequestOrderStatus.java b/src/main/java/com/example/springbootbookshop/dto/order/UpdateRequestOrderStatus.java new file mode 100644 index 0000000..28b3fa6 --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/dto/order/UpdateRequestOrderStatus.java @@ -0,0 +1,7 @@ +package com.example.springbootbookshop.dto.order; + +import com.example.springbootbookshop.entity.Status; +import jakarta.validation.constraints.NotBlank; + +public record UpdateRequestOrderStatus(@NotBlank Status status) { +} diff --git a/src/main/java/com/example/springbootbookshop/entity/Book.java b/src/main/java/com/example/springbootbookshop/entity/Book.java index 897dcf5..2772c51 100644 --- a/src/main/java/com/example/springbootbookshop/entity/Book.java +++ b/src/main/java/com/example/springbootbookshop/entity/Book.java @@ -55,5 +55,7 @@ public class Book { private Set categories = new HashSet<>(); @OneToMany(mappedBy = "book",orphanRemoval = true, cascade = CascadeType.REMOVE) + @ToString.Exclude + @EqualsAndHashCode.Exclude private List cartItems = new ArrayList<>(); } diff --git a/src/main/java/com/example/springbootbookshop/entity/CartItem.java b/src/main/java/com/example/springbootbookshop/entity/CartItem.java index 1b7360f..4522ac9 100644 --- a/src/main/java/com/example/springbootbookshop/entity/CartItem.java +++ b/src/main/java/com/example/springbootbookshop/entity/CartItem.java @@ -34,5 +34,5 @@ public class CartItem { @Column(nullable = false) @NotNull - private int quantity; + private Integer quantity; } diff --git a/src/main/java/com/example/springbootbookshop/entity/Order.java b/src/main/java/com/example/springbootbookshop/entity/Order.java new file mode 100644 index 0000000..11a0bba --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/entity/Order.java @@ -0,0 +1,60 @@ +package com.example.springbootbookshop.entity; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.Set; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; + +@Entity +@Data +@Table(name = "orders") +@SQLDelete(sql = "UPDATE orders SET is_deleted = TRUE WHERE id = ?") +@Where(clause = "is_deleted = false") +public class Order { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @ToString.Exclude + @EqualsAndHashCode.Exclude + private User user; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private Status status; + + @Column(nullable = false) + private BigDecimal total; + + @Column(nullable = false) + private LocalDateTime orderDate; + + @Column(nullable = false) + private String shippingAddress; + + @OneToMany(mappedBy = "order", orphanRemoval = true, + cascade = CascadeType.REMOVE) + @Column(nullable = false) + private Set orderItems = new HashSet<>(); + + @Column(nullable = false) + private boolean isDeleted = false; +} diff --git a/src/main/java/com/example/springbootbookshop/entity/OrderItem.java b/src/main/java/com/example/springbootbookshop/entity/OrderItem.java new file mode 100644 index 0000000..3000bee --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/entity/OrderItem.java @@ -0,0 +1,49 @@ +package com.example.springbootbookshop.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.math.BigDecimal; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; + +@Entity +@Data +@Table(name = "order_items") +@SQLDelete(sql = "UPDATE orders_items SET is_deleted = TRUE WHERE id = ?") +@Where(clause = "is_deleted = false") +public class OrderItem { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @ToString.Exclude + @EqualsAndHashCode.Exclude + @JoinColumn(name = "order_id") + private Order order; + + @ToString.Exclude + @EqualsAndHashCode.Exclude + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "book_id", nullable = false) + private Book book; + + @Column(nullable = false) + private Integer quantity; + + @Column(nullable = false) + private BigDecimal price; + + @Column(nullable = false) + private boolean isDeleted = false; +} diff --git a/src/main/java/com/example/springbootbookshop/entity/Status.java b/src/main/java/com/example/springbootbookshop/entity/Status.java new file mode 100644 index 0000000..c83db3e --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/entity/Status.java @@ -0,0 +1,9 @@ +package com.example.springbootbookshop.entity; + +public enum Status { + PENDING, + PROCESSING, + COMPLETED, + CANCELLED, + DELIVERED +} diff --git a/src/main/java/com/example/springbootbookshop/mapper/OrderItemMapper.java b/src/main/java/com/example/springbootbookshop/mapper/OrderItemMapper.java new file mode 100644 index 0000000..bd664b3 --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/mapper/OrderItemMapper.java @@ -0,0 +1,18 @@ +package com.example.springbootbookshop.mapper; + +import com.example.springbootbookshop.dto.order.OrderItemDto; +import com.example.springbootbookshop.entity.OrderItem; +import org.mapstruct.InjectionStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.NullValueCheckStrategy; + +@Mapper(componentModel = "spring", + injectionStrategy = InjectionStrategy.CONSTRUCTOR, + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + implementationPackage = ".impl") +public interface OrderItemMapper { + + @Mapping(source = "book.id", target = "bookId") + OrderItemDto toDto(OrderItem orderItem); +} diff --git a/src/main/java/com/example/springbootbookshop/mapper/OrderMapper.java b/src/main/java/com/example/springbootbookshop/mapper/OrderMapper.java new file mode 100644 index 0000000..23c06bc --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/mapper/OrderMapper.java @@ -0,0 +1,18 @@ +package com.example.springbootbookshop.mapper; + +import com.example.springbootbookshop.dto.order.OrderDto; +import com.example.springbootbookshop.entity.Order; +import org.mapstruct.InjectionStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.NullValueCheckStrategy; + +@Mapper(componentModel = "spring", + injectionStrategy = InjectionStrategy.CONSTRUCTOR, + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + implementationPackage = ".impl", + uses = OrderItemMapper.class) +public interface OrderMapper { + @Mapping(source = "user.id", target = "userId") + OrderDto toDto(Order order); +} diff --git a/src/main/java/com/example/springbootbookshop/repository/CartItemsRepository.java b/src/main/java/com/example/springbootbookshop/repository/CartItemsRepository.java index e3c9460..ca68124 100644 --- a/src/main/java/com/example/springbootbookshop/repository/CartItemsRepository.java +++ b/src/main/java/com/example/springbootbookshop/repository/CartItemsRepository.java @@ -4,6 +4,7 @@ import com.example.springbootbookshop.entity.Cart; import com.example.springbootbookshop.entity.CartItem; import java.util.Optional; +import java.util.Set; import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -14,4 +15,6 @@ public interface CartItemsRepository extends JpaRepository { Optional findByCartAndBook(Cart cart, Book book); Optional getCartItemsByIdAndCartId(Long itemId,Long cartId); + + Set findByCart(Cart cart); } diff --git a/src/main/java/com/example/springbootbookshop/repository/OrderItemsRepository.java b/src/main/java/com/example/springbootbookshop/repository/OrderItemsRepository.java new file mode 100644 index 0000000..bd11556 --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/repository/OrderItemsRepository.java @@ -0,0 +1,16 @@ +package com.example.springbootbookshop.repository; + +import com.example.springbootbookshop.dto.order.OrderItemDto; +import com.example.springbootbookshop.entity.Order; +import com.example.springbootbookshop.entity.OrderItem; +import java.util.Optional; +import java.util.Set; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface OrderItemsRepository extends JpaRepository { + Optional findByOrderAndId(Order order, Long id); + + Set findByOrder(Order order); +} diff --git a/src/main/java/com/example/springbootbookshop/repository/OrderRepository.java b/src/main/java/com/example/springbootbookshop/repository/OrderRepository.java new file mode 100644 index 0000000..4510f82 --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/repository/OrderRepository.java @@ -0,0 +1,14 @@ +package com.example.springbootbookshop.repository; + +import com.example.springbootbookshop.entity.Order; +import java.util.Set; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface OrderRepository extends JpaRepository { + + @EntityGraph(attributePaths = {"user", "orderItems"}) + Set findAllByUserId(Long userId); +} diff --git a/src/main/java/com/example/springbootbookshop/service/OrderService.java b/src/main/java/com/example/springbootbookshop/service/OrderService.java new file mode 100644 index 0000000..767c711 --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/service/OrderService.java @@ -0,0 +1,20 @@ +package com.example.springbootbookshop.service; + +import com.example.springbootbookshop.dto.cart.CartDto; +import com.example.springbootbookshop.dto.order.OrderDto; +import com.example.springbootbookshop.dto.order.OrderItemDto; +import com.example.springbootbookshop.dto.order.RequestOrderDto; +import com.example.springbootbookshop.dto.order.UpdateRequestOrderStatus; +import java.util.Set; + +public interface OrderService { + CartDto save(Long userId, RequestOrderDto requestOrderDto); + + OrderItemDto getOrderItem(Long userId, Long orderId, Long itemId); + + Set getOrder(Long userId, Long orderId); + + Set showAllOrders(Long userId); + + void updateOrderStatus(Long orderId, UpdateRequestOrderStatus status); +} diff --git a/src/main/java/com/example/springbootbookshop/service/impl/CartServiceImpl.java b/src/main/java/com/example/springbootbookshop/service/impl/CartServiceImpl.java index 7ed7888..818c3ba 100644 --- a/src/main/java/com/example/springbootbookshop/service/impl/CartServiceImpl.java +++ b/src/main/java/com/example/springbootbookshop/service/impl/CartServiceImpl.java @@ -46,13 +46,14 @@ public CartItemDto addItemToCart(Long userId, RequestCartItemDto requestCartItem + "doesn`t exist")); int quantityToAdd = requestCartItemDto.quantity(); CartItem cartItem = cartItemsRepository.findByCartAndBook(cart, book) - .orElseGet(() -> { - CartItem newCartItem = cartItemMapper.toEntity(requestCartItemDto); - newCartItem.setBook(book); - newCartItem.setCart(cart); - return newCartItem; - }); - cartItem.setQuantity(quantityToAdd + cartItem.getQuantity()); + .orElse(null); + if (cartItem == null) { + cartItem = cartItemMapper.toEntity(requestCartItemDto); + cartItem.setBook(book); + cartItem.setCart(cart); + } else { + cartItem.setQuantity(cartItem.getQuantity() + quantityToAdd); + } return cartItemMapper.toDto(cartItemsRepository.save(cartItem)); } diff --git a/src/main/java/com/example/springbootbookshop/service/impl/OrderServiceImpl.java b/src/main/java/com/example/springbootbookshop/service/impl/OrderServiceImpl.java new file mode 100644 index 0000000..8f9e8bd --- /dev/null +++ b/src/main/java/com/example/springbootbookshop/service/impl/OrderServiceImpl.java @@ -0,0 +1,117 @@ +package com.example.springbootbookshop.service.impl; + +import com.example.springbootbookshop.dto.cart.CartDto; +import com.example.springbootbookshop.dto.order.OrderDto; +import com.example.springbootbookshop.dto.order.OrderItemDto; +import com.example.springbootbookshop.dto.order.RequestOrderDto; +import com.example.springbootbookshop.dto.order.UpdateRequestOrderStatus; +import com.example.springbootbookshop.entity.Cart; +import com.example.springbootbookshop.entity.CartItem; +import com.example.springbootbookshop.entity.Order; +import com.example.springbootbookshop.entity.OrderItem; +import com.example.springbootbookshop.entity.Status; +import com.example.springbootbookshop.exception.EntityNotFoundException; +import com.example.springbootbookshop.mapper.CartMapper; +import com.example.springbootbookshop.mapper.OrderMapper; +import com.example.springbootbookshop.repository.CartItemsRepository; +import com.example.springbootbookshop.repository.CartRepository; +import com.example.springbootbookshop.repository.OrderItemsRepository; +import com.example.springbootbookshop.repository.OrderRepository; +import com.example.springbootbookshop.repository.UserRepository; +import com.example.springbootbookshop.service.OrderService; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class OrderServiceImpl implements OrderService { + private final OrderRepository orderRepository; + private final CartRepository cartRepository; + private final UserRepository userRepository; + private final CartItemsRepository cartItemsRepository; + private final CartMapper cartMapper; + private final OrderItemsRepository orderItemsRepository; + private final OrderMapper orderMapper; + + @Override + @Transactional + public CartDto save(Long userId, RequestOrderDto requestOrderDto) { + Cart cart = cartRepository.getCartByUserId(userId).get(); + if (cart.getCartItems().isEmpty()) { + throw new EntityNotFoundException("You cart is empty"); + } + Order order = new Order(); + order.setUser(userRepository.getReferenceById(userId)); + order.setShippingAddress(requestOrderDto.shippingAddress()); + order.setTotal(calculateTotal(cart)); + order.setOrderDate(LocalDateTime.now()); + order.setStatus(Status.PENDING); + orderRepository.save(order); + Set cartItems = cartItemsRepository.findByCart(cart); + + cartItems.stream() + .map(cartItem -> { + OrderItem orderItem = new OrderItem(); + orderItem.setOrder(order); + orderItem.setBook(cartItem.getBook()); + orderItem.setPrice(cartItem.getBook().getPrice() + .multiply(BigDecimal.valueOf(cartItem.getQuantity()))); + orderItem.setQuantity(cartItem.getQuantity()); + return orderItem; + }) + .forEach(orderItemsRepository::save); + + cartItemsRepository.deleteAll(cartItems); + return cartMapper.toDto(cart); + } + + @Override + public OrderItemDto getOrderItem(Long userId, Long orderId, Long itemId) { + Set userOrders = orderRepository.findAllByUserId(userId); + Order userOrder = userOrders.stream() + .filter(order -> order.getId().equals(orderId)) + .findFirst() + .orElseThrow(() -> new EntityNotFoundException( + "User doen`t have order with id: " + orderId)); + return orderItemsRepository.findByOrderAndId(userOrder, itemId).orElseThrow(() -> + new EntityNotFoundException("Item with id: " + itemId + " doesn`t found")); + } + + @Override + public Set getOrder(Long userId, Long orderId) { + Order orderItemsUser = orderRepository.findAllByUserId(userId).stream() + .filter(order -> order.getId().equals(orderId)) + .findFirst() + .orElseThrow(() -> new EntityNotFoundException("No order with id: " + orderId + + " for user with id: " + userId)); + return orderItemsRepository.findByOrder(orderItemsUser); + } + + @Override + public Set showAllOrders(Long userId) { + return orderRepository.findAllByUserId(userId).stream() + .map(orderMapper::toDto) + .collect(Collectors.toSet()); + } + + @Override + @Transactional + public void updateOrderStatus(Long orderId, + UpdateRequestOrderStatus status) { + Order order = orderRepository.getReferenceById(orderId); + order.setStatus(status.status()); + } + + private BigDecimal calculateTotal(Cart cart) { + return cart.getCartItems().stream() + .map(cartItem -> + BigDecimal.valueOf(cartItem.getQuantity()) + .multiply(cartItem.getBook().getPrice())) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } +} diff --git a/src/main/resources/db/changelog/changes/09-add-cart-id-to-users-table.yaml b/src/main/resources/db/changelog/changes/09-add-cart-id-to-users-table.yaml deleted file mode 100644 index dc34e87..0000000 --- a/src/main/resources/db/changelog/changes/09-add-cart-id-to-users-table.yaml +++ /dev/null @@ -1,19 +0,0 @@ -databaseChangeLog: - - changeSet: - id: add-cart-id-column-to-users - author: bohdan-maksymenko - changes: - - addColumn: - tableName: users - columns: - - column: - name: cart_id - type: BIGINT - constraints: - nullable: true - - addForeignKeyConstraint: - baseTableName: users - baseColumnNames: cart_id - referencedTableName: carts - referencedColumnNames: id - constraintName: FK_users_cart diff --git a/src/main/resources/db/changelog/changes/09-add-orders-table.yaml b/src/main/resources/db/changelog/changes/09-add-orders-table.yaml new file mode 100644 index 0000000..97721bf --- /dev/null +++ b/src/main/resources/db/changelog/changes/09-add-orders-table.yaml @@ -0,0 +1,53 @@ +databaseChangeLog: + - changeSet: + id: create-orders-table + author: bohdan-maksymenko + 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 + - column: + name: status + type: VARCHAR(255) + constraints: + nullable: false + - column: + name: total + type: DECIMAL(19, 2) + 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: BOOLEAN + defaultValueBoolean: false + constraints: + nullable: false + - addForeignKeyConstraint: + baseTableName: orders + baseColumnNames: user_id + referencedTableName: users + referencedColumnNames: id + constraintName: FK_orders_user + onDelete: CASCADE \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/10-create-orders-items-table.yaml b/src/main/resources/db/changelog/changes/10-create-orders-items-table.yaml new file mode 100644 index 0000000..7bd3c30 --- /dev/null +++ b/src/main/resources/db/changelog/changes/10-create-orders-items-table.yaml @@ -0,0 +1,55 @@ +databaseChangeLog: + - changeSet: + id: create-order-items-table + author: bohdan-maksymenko + 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 + - column: + name: book_id + type: BIGINT + constraints: + nullable: false + - column: + name: quantity + type: INTEGER + constraints: + nullable: false + - column: + name: price + type: DECIMAL(19, 2) + constraints: + nullable: false + - column: + name: is_deleted + type: BOOLEAN + defaultValueBoolean: false + constraints: + nullable: false + - addForeignKeyConstraint: + baseTableName: order_items + baseColumnNames: order_id + referencedTableName: orders + referencedColumnNames: id + constraintName: FK_order_items_order + onDelete: CASCADE + - addForeignKeyConstraint: + baseTableName: order_items + baseColumnNames: book_id + referencedTableName: books + referencedColumnNames: id + constraintName: FK_order_items_book + onDelete: CASCADE \ No newline at end of file diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index dec3f5c..7db6ddb 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -14,4 +14,8 @@ databaseChangeLog: - include: file: db/changelog/changes/07-create-carts-table.yaml - include: - file: db/changelog/changes/08-create-cart-items-table.yaml \ No newline at end of file + file: db/changelog/changes/08-create-cart-items-table.yaml + - include: + file: db/changelog/changes/09-add-orders-table.yaml + - include: + file: db/changelog/changes/10-create-orders-items-table.yaml \ No newline at end of file