From eae121a049b7f0715d251924b519a5bbb875dda8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=ED=98=81?= Date: Tue, 19 Nov 2024 11:32:00 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B0=94=EA=B5=AC?= =?UTF-8?q?=EB=8B=88=20=EC=B6=94=EA=B0=80=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#41)=20(#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../order/application/OrderService.java | 68 +++++++++++++++++++ .../jangburich/domain/order/domain/Cart.java | 26 +++++++ .../domain/repository/CartRepository.java | 14 ++++ .../domain/repository/OrdersRepository.java | 9 +++ .../order/dto/request/AddCartRequest.java | 8 +++ .../order/presentation/OrderController.java | 33 +++++++++ .../StoreQueryDslRepositoryImpl.java | 10 ++- 7 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/jangburich/domain/order/application/OrderService.java create mode 100644 src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java create mode 100644 src/main/java/com/jangburich/domain/order/domain/repository/OrdersRepository.java create mode 100644 src/main/java/com/jangburich/domain/order/dto/request/AddCartRequest.java create mode 100644 src/main/java/com/jangburich/domain/order/presentation/OrderController.java diff --git a/src/main/java/com/jangburich/domain/order/application/OrderService.java b/src/main/java/com/jangburich/domain/order/application/OrderService.java new file mode 100644 index 0000000..f547aeb --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/application/OrderService.java @@ -0,0 +1,68 @@ +package com.jangburich.domain.order.application; + +import com.jangburich.domain.menu.domain.Menu; +import com.jangburich.domain.menu.domain.repository.MenuRepository; +import com.jangburich.domain.order.domain.Cart; +import com.jangburich.domain.order.domain.repository.CartRepository; +import com.jangburich.domain.order.domain.repository.OrdersRepository; +import com.jangburich.domain.order.dto.request.AddCartRequest; +import com.jangburich.domain.store.domain.Store; +import com.jangburich.domain.store.domain.repository.StoreRepository; +import com.jangburich.domain.user.domain.User; +import com.jangburich.domain.user.domain.repository.UserRepository; +import com.jangburich.global.payload.Message; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class OrderService { + + private final CartRepository cartRepository; + private final UserRepository userRepository; + private final MenuRepository menuRepository; + private final StoreRepository storeRepository; + + @Transactional + public Message addCart(String userProviderId, AddCartRequest addCartRequest) { + User user = userRepository.findByProviderId(userProviderId) + .orElseThrow(() -> new NullPointerException()); + + Menu menu = menuRepository.findById(addCartRequest.menuId()) + .orElseThrow(() -> new IllegalArgumentException("등록된 메뉴를 찾을 수 없습니다.")); + + System.out.println("menu.getId() = " + menu.getId()); + System.out.println("user.getUserId() = " + user.getUserId()); + + Optional optionalCart = cartRepository.findByUserIdAndMenuId(user.getUserId(), menu.getId()); + + Store store = storeRepository.findById(addCartRequest.storeId()) + .orElseThrow(() -> new IllegalArgumentException("유효하지 않은 가게 id 입니다.")); + + if (optionalCart.isPresent()) { + Cart existingCart = optionalCart.get(); + existingCart.updateQuantity(addCartRequest.quantity()); + + return Message.builder() + .message("장바구니에 상품을 추가했습니다.") + .build(); + } + + Cart newCart = Cart.builder() + .quantity(addCartRequest.quantity()) + .menu(menu) + .user(user) + .store(store) + .orders(null) + .build(); + + cartRepository.save(newCart); + + return Message.builder() + .message("장바구니에 상품을 추가했습니다.") + .build(); + } +} diff --git a/src/main/java/com/jangburich/domain/order/domain/Cart.java b/src/main/java/com/jangburich/domain/order/domain/Cart.java index 014f63d..0be2f63 100644 --- a/src/main/java/com/jangburich/domain/order/domain/Cart.java +++ b/src/main/java/com/jangburich/domain/order/domain/Cart.java @@ -2,6 +2,8 @@ import com.jangburich.domain.common.BaseEntity; import com.jangburich.domain.menu.domain.Menu; +import com.jangburich.domain.store.domain.Store; +import com.jangburich.domain.user.domain.User; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -10,7 +12,9 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import java.util.List; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -34,4 +38,26 @@ public class Cart extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "menu_id") private Menu menu; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id") + private Store store; + + + @Builder + public Cart(Integer quantity, Orders orders, Menu menu, User user, Store store) { + this.quantity = quantity; + this.orders = orders; + this.menu = menu; + this.user = user; + this.store = store; + } + + public void updateQuantity(int quantity) { + this.quantity += quantity; + } } diff --git a/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java b/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java new file mode 100644 index 0000000..51cd8a7 --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java @@ -0,0 +1,14 @@ +package com.jangburich.domain.order.domain.repository; + +import com.jangburich.domain.order.domain.Cart; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface CartRepository extends JpaRepository { + @Query("SELECT c FROM Cart c WHERE c.user.userId = :userId AND c.menu.id = :menuId") + Optional findByUserIdAndMenuId(@Param("userId") Long userId, @Param("menuId") Long menuId); +} diff --git a/src/main/java/com/jangburich/domain/order/domain/repository/OrdersRepository.java b/src/main/java/com/jangburich/domain/order/domain/repository/OrdersRepository.java new file mode 100644 index 0000000..b1e47b8 --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/domain/repository/OrdersRepository.java @@ -0,0 +1,9 @@ +package com.jangburich.domain.order.domain.repository; + +import com.jangburich.domain.order.domain.Orders; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface OrdersRepository extends JpaRepository { +} diff --git a/src/main/java/com/jangburich/domain/order/dto/request/AddCartRequest.java b/src/main/java/com/jangburich/domain/order/dto/request/AddCartRequest.java new file mode 100644 index 0000000..0f9e71b --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/dto/request/AddCartRequest.java @@ -0,0 +1,8 @@ +package com.jangburich.domain.order.dto.request; + +public record AddCartRequest( + Long storeId, + Long menuId, + int quantity +) { +} \ No newline at end of file diff --git a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java new file mode 100644 index 0000000..e403e6a --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java @@ -0,0 +1,33 @@ +package com.jangburich.domain.order.presentation; + +import com.jangburich.domain.order.application.OrderService; +import com.jangburich.domain.order.dto.request.AddCartRequest; +import com.jangburich.global.payload.Message; +import com.jangburich.global.payload.ResponseCustom; +import com.jangburich.utils.parser.AuthenticationParser; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.Authentication; +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", description = "Order API") +@RestController +@RequiredArgsConstructor +@RequestMapping("/orders") +public class OrderController { + + private final OrderService orderService; + + @Operation(summary = "장바구니 담기", description = "장바구니에 물건과 수량을 담습니다.") + @PostMapping("/cart") + public ResponseCustom addCart( + Authentication authentication, + @RequestBody AddCartRequest addCartRequest + ) { + return ResponseCustom.OK(orderService.addCart(AuthenticationParser.parseUserId(authentication), addCartRequest)); + } +} diff --git a/src/main/java/com/jangburich/domain/store/domain/repository/StoreQueryDslRepositoryImpl.java b/src/main/java/com/jangburich/domain/store/domain/repository/StoreQueryDslRepositoryImpl.java index 30ef5c1..03f15e6 100644 --- a/src/main/java/com/jangburich/domain/store/domain/repository/StoreQueryDslRepositoryImpl.java +++ b/src/main/java/com/jangburich/domain/store/domain/repository/StoreQueryDslRepositoryImpl.java @@ -34,13 +34,15 @@ public Page findStoresByCategory(Long userId, Integer sear double myCurrentLat = storeSearchCondition.lat(); double myCurrentLon = storeSearchCondition.lon(); + BooleanExpression categoryCondition = isAllCategory(category); + List results = queryFactory .select(new QSearchStoresResponse(store.id, store.name, Expressions.FALSE, store.category, Expressions.constant(1.0), Expressions.constant("open"), store.closeTime.stringValue(), store.contactNumber, store.representativeImage)) .from(store) .where( - store.category.eq(category), + categoryCondition, withinSearchRadius(myCurrentLat, myCurrentLon, searchRadius, store.latitude, store.longitude) ) .orderBy(store.id.desc()) @@ -52,7 +54,7 @@ public Page findStoresByCategory(Long userId, Integer sear .select(store.count()) .from(store) .where( - store.category.eq(category), + categoryCondition, withinSearchRadius(myCurrentLat, myCurrentLon, searchRadius, store.latitude, store.longitude) ); @@ -93,6 +95,10 @@ public Page findStores(Long userId, String keyword, return PageableExecutionUtils.getPage(results, pageable, () -> countQuery.fetch().size()); } + private BooleanExpression isAllCategory(Category category) { + return category == Category.ALL ? Expressions.TRUE : store.category.eq(category); + } + // TO DO private BooleanExpression isStoreCurrentlyOpen(String openTime, String closeTime) { DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm"); From c6f9bd4491ca8ae57b002096a6bdf24fcd95c74f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=ED=98=81?= Date: Tue, 19 Nov 2024 12:41:33 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B0=94=EA=B5=AC?= =?UTF-8?q?=EB=8B=88=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#43)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 장바구니 추가 기능 구현 * feat: 장바구니 조회 기능 구현 --- .../order/application/OrderService.java | 29 +++++++++++++++- .../domain/repository/CartRepository.java | 4 +++ .../order/dto/response/CartResponse.java | 33 +++++++++++++++++++ .../order/presentation/OrderController.java | 12 ++++++- 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java diff --git a/src/main/java/com/jangburich/domain/order/application/OrderService.java b/src/main/java/com/jangburich/domain/order/application/OrderService.java index f547aeb..87c6a6f 100644 --- a/src/main/java/com/jangburich/domain/order/application/OrderService.java +++ b/src/main/java/com/jangburich/domain/order/application/OrderService.java @@ -4,13 +4,15 @@ import com.jangburich.domain.menu.domain.repository.MenuRepository; import com.jangburich.domain.order.domain.Cart; import com.jangburich.domain.order.domain.repository.CartRepository; -import com.jangburich.domain.order.domain.repository.OrdersRepository; import com.jangburich.domain.order.dto.request.AddCartRequest; +import com.jangburich.domain.order.dto.response.CartResponse; +import com.jangburich.domain.order.dto.response.CartResponse.GetCartItemsResponse; import com.jangburich.domain.store.domain.Store; import com.jangburich.domain.store.domain.repository.StoreRepository; import com.jangburich.domain.user.domain.User; import com.jangburich.domain.user.domain.repository.UserRepository; import com.jangburich.global.payload.Message; +import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -65,4 +67,29 @@ public Message addCart(String userProviderId, AddCartRequest addCartRequest) { .message("장바구니에 상품을 추가했습니다.") .build(); } + + public CartResponse getCartItems(String userProviderId) { + User user = userRepository.findByProviderId(userProviderId) + .orElseThrow(() -> new NullPointerException()); + + List carts = cartRepository.findAllByUser(user); + + if (carts.isEmpty()) { + return CartResponse.of(List.of(), 0); + } + + List cartItems = carts.stream() + .map(cart -> GetCartItemsResponse.of( + cart.getMenu().getName(), + cart.getMenu().getDescription(), + cart.getQuantity(), + cart.getMenu().getPrice() + )) + .toList(); + + int discountAmount = 0; + CartResponse cartResponse = CartResponse.of(cartItems, discountAmount); + + return cartResponse; + } } diff --git a/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java b/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java index 51cd8a7..3e82e3b 100644 --- a/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java +++ b/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java @@ -1,6 +1,8 @@ package com.jangburich.domain.order.domain.repository; import com.jangburich.domain.order.domain.Cart; +import com.jangburich.domain.user.domain.User; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -11,4 +13,6 @@ public interface CartRepository extends JpaRepository { @Query("SELECT c FROM Cart c WHERE c.user.userId = :userId AND c.menu.id = :menuId") Optional findByUserIdAndMenuId(@Param("userId") Long userId, @Param("menuId") Long menuId); + + List findAllByUser(User user); } diff --git a/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java b/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java new file mode 100644 index 0000000..2cb6307 --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java @@ -0,0 +1,33 @@ +package com.jangburich.domain.order.dto.response; + +import java.util.List; + +public record CartResponse( + List cartItems, + Integer totalAmount, + Integer discountAmount, + Integer finalAmount +) { + public static CartResponse of(List cartItems, Integer discountAmount) { + int totalAmount = cartItems.stream() + .mapToInt(item -> item.menuPrice * item.quantity) + .sum(); + + discountAmount = 0; + + int finalAmount = totalAmount - discountAmount; + + return new CartResponse(cartItems, totalAmount, discountAmount, finalAmount); + } + + public record GetCartItemsResponse( + String menuName, + String menuDescription, + Integer quantity, + Integer menuPrice + ) { + public static GetCartItemsResponse of(String menuName, String menuDescription, Integer quantity, Integer menuPrice) { + return new GetCartItemsResponse(menuName, menuDescription, quantity, menuPrice); + } + } +} diff --git a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java index e403e6a..914e958 100644 --- a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java +++ b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java @@ -2,6 +2,7 @@ import com.jangburich.domain.order.application.OrderService; import com.jangburich.domain.order.dto.request.AddCartRequest; +import com.jangburich.domain.order.dto.response.CartResponse; import com.jangburich.global.payload.Message; import com.jangburich.global.payload.ResponseCustom; import com.jangburich.utils.parser.AuthenticationParser; @@ -9,6 +10,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -23,11 +25,19 @@ public class OrderController { private final OrderService orderService; @Operation(summary = "장바구니 담기", description = "장바구니에 물건과 수량을 담습니다.") - @PostMapping("/cart") + @PostMapping("/carts") public ResponseCustom addCart( Authentication authentication, @RequestBody AddCartRequest addCartRequest ) { return ResponseCustom.OK(orderService.addCart(AuthenticationParser.parseUserId(authentication), addCartRequest)); } + + @Operation(summary = "장바구니 조회", description = "장바구니에 담은 상품을 조회합니다.") + @GetMapping("/carts") + public ResponseCustom getCartItems( + Authentication authentication + ) { + return ResponseCustom.OK(orderService.getCartItems(AuthenticationParser.parseUserId(authentication))); + } }