Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 상품 주문과 식권 사용 기능 구현(상품 주문 시 포인트 소모는 todo) #45

Merged
merged 8 commits into from
Nov 19, 2024
4 changes: 4 additions & 0 deletions src/main/java/com/jangburich/domain/common/BaseEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ public abstract class BaseEntity {
@Enumerated(value = EnumType.STRING)
@Column(name = "status")
private Status status = Status.ACTIVE;

public void updateStatus(Status status) {
this.status = status;
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package com.jangburich.domain.order.application;

import com.amazonaws.services.kms.model.NotFoundException;
import com.jangburich.domain.common.Status;
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.Orders;
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.request.OrderRequest;
import com.jangburich.domain.order.dto.response.CartResponse;
import com.jangburich.domain.order.dto.response.CartResponse.GetCartItemsResponse;
import com.jangburich.domain.order.dto.response.GetCartItemsResponse;
import com.jangburich.domain.store.domain.Store;
import com.jangburich.domain.store.domain.repository.StoreRepository;
import com.jangburich.domain.team.domain.Team;
import com.jangburich.domain.team.domain.repository.TeamRepository;
import com.jangburich.domain.user.domain.User;
import com.jangburich.domain.user.domain.repository.UserRepository;
import com.jangburich.global.payload.Message;
Expand All @@ -27,6 +34,8 @@ public class OrderService {
private final UserRepository userRepository;
private final MenuRepository menuRepository;
private final StoreRepository storeRepository;
private final OrdersRepository ordersRepository;
private final TeamRepository teamRepository;

@Transactional
public Message addCart(String userProviderId, AddCartRequest addCartRequest) {
Expand All @@ -46,7 +55,7 @@ public Message addCart(String userProviderId, AddCartRequest addCartRequest) {

if (optionalCart.isPresent()) {
Cart existingCart = optionalCart.get();
existingCart.updateQuantity(addCartRequest.quantity());
existingCart.updateQuantity(existingCart.getQuantity() + addCartRequest.quantity());

return Message.builder()
.message("장바구니에 상품을 추가했습니다.")
Expand All @@ -72,7 +81,7 @@ public CartResponse getCartItems(String userProviderId) {
User user = userRepository.findByProviderId(userProviderId)
.orElseThrow(() -> new NullPointerException());

List<Cart> carts = cartRepository.findAllByUser(user);
List<Cart> carts = cartRepository.findAllByUserAndStatus(user, Status.ACTIVE);

if (carts.isEmpty()) {
return CartResponse.of(List.of(), 0);
Expand All @@ -92,4 +101,92 @@ public CartResponse getCartItems(String userProviderId) {

return cartResponse;
}

@Transactional
public Message order(String userProviderId, OrderRequest orderRequest) {
User user = userRepository.findByProviderId(userProviderId)
.orElseThrow(() -> new NullPointerException());

Store store = storeRepository.findById(orderRequest.storeId())
.orElseThrow(() -> new IllegalArgumentException("유효하지 않은 가게 id 입니다."));

Team team = teamRepository.findById(orderRequest.teamId())
.orElseThrow(() -> new IllegalArgumentException("유효하지 않은 그룹 id 입니다."));

List<Cart> existingCarts = cartRepository.findAllByUserAndStore(user, store);

List<Cart> mergedCarts = mergeCarts(existingCarts, orderRequest.items(), user, store);


Orders orders = saveOrder(user, store, team, orderRequest);

associateCartsWithOrder(mergedCarts, orders);

cartRepository.saveAll(mergedCarts);

return Message.builder()
.message("주문이 완료되었습니다.")
.build();
}

private List<Cart> mergeCarts(List<Cart> existingCarts, List<OrderRequest.OrderItemRequest> items, User user, Store store) {
for (OrderRequest.OrderItemRequest item : items) {
Optional<Cart> existingCart = findCartByMenuId(existingCarts, item.menuId());
if (existingCart.isPresent()) {
existingCart.get().updateQuantity(existingCart.get().getQuantity() + item.quantity());
existingCart.get().updateStatus(Status.INACTIVE);
continue;
}
Cart newCart = createNewCart(item, user, store);
existingCarts.add(newCart);
}
return existingCarts;
}

private Optional<Cart> findCartByMenuId(List<Cart> carts, Long menuId) {
return carts.stream()
.filter(cart -> cart.getMenu().getId().equals(menuId))
.findFirst();
}

private Cart createNewCart(OrderRequest.OrderItemRequest item, User user, Store store) {
Menu menu = menuRepository.findById(item.menuId())
.orElseThrow(() -> new IllegalArgumentException("유효하지 않은 메뉴 ID입니다."));
return Cart.builder()
.quantity(item.quantity())
.menu(menu)
.user(user)
.store(store)
.orders(null)
.build();
}

private Orders saveOrder(User user, Store store, Team team, OrderRequest orderRequest) {
Orders orders = Orders.builder()
.store(store)
.user(user)
.team(team)
.build();
return ordersRepository.save(orders);
}

private void associateCartsWithOrder(List<Cart> carts, Orders orders) {
carts.forEach(cart -> cart.updateOrders(orders));
}

public Message useMealTicket(String userProviderId, Long orderId) {
User user = userRepository.findByProviderId(userProviderId)
.orElseThrow(() -> new NullPointerException());

Orders orders = ordersRepository.findById(orderId)
.orElseThrow(() -> new NotFoundException("식권을 찾을 수 없습니다"));

orders.validateUser(user);

orders.updateStatus(Status.INACTIVE);

return Message.builder()
.message("식권을 사용했습니다.")
.build();
}
}
6 changes: 5 additions & 1 deletion src/main/java/com/jangburich/domain/order/domain/Cart.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ public Cart(Integer quantity, Orders orders, Menu menu, User user, Store store)
}

public void updateQuantity(int quantity) {
this.quantity += quantity;
this.quantity = quantity;
}

public void updateOrders(Orders orders) {
this.orders = orders;
}
}
15 changes: 15 additions & 0 deletions src/main/java/com/jangburich/domain/order/domain/Orders.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

Expand All @@ -37,4 +38,18 @@ public class Orders extends BaseEntity {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;


@Builder
public Orders(Store store, User user, Team team) {
this.store = store;
this.user = user;
this.team = team;
}

public void validateUser(User user) {
if (!this.user.equals(user)) {
throw new IllegalArgumentException("유저 정보가 일치하지 않습니다.");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.jangburich.domain.order.domain.repository;

import com.jangburich.domain.common.Status;
import com.jangburich.domain.order.domain.Cart;
import com.jangburich.domain.store.domain.Store;
import com.jangburich.domain.user.domain.User;
import java.util.List;
import java.util.Optional;
Expand All @@ -14,5 +16,7 @@ public interface CartRepository extends JpaRepository<Cart, Long> {
@Query("SELECT c FROM Cart c WHERE c.user.userId = :userId AND c.menu.id = :menuId")
Optional<Cart> findByUserIdAndMenuId(@Param("userId") Long userId, @Param("menuId") Long menuId);

List<Cart> findAllByUser(User user);
List<Cart> findAllByUserAndStore(User user, Store store);

List<Cart> findAllByUserAndStatus(User user, Status status);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.jangburich.domain.order.dto.request;

import java.util.List;

public record OrderRequest(
Long storeId,
Long teamId,
List<OrderItemRequest> items
) {
public static record OrderItemRequest(
Long menuId,
Integer quantity
) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public record CartResponse(
) {
public static CartResponse of(List<GetCartItemsResponse> cartItems, Integer discountAmount) {
int totalAmount = cartItems.stream()
.mapToInt(item -> item.menuPrice * item.quantity)
.mapToInt(item -> item.menuPrice() * item.quantity())
.sum();

discountAmount = 0;
Expand All @@ -20,14 +20,4 @@ public static CartResponse of(List<GetCartItemsResponse> cartItems, Integer disc
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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.jangburich.domain.order.dto.response;

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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.request.OrderRequest;
import com.jangburich.domain.order.dto.response.CartResponse;
import com.jangburich.global.payload.Message;
import com.jangburich.global.payload.ResponseCustom;
Expand All @@ -11,6 +12,7 @@
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
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;
Expand Down Expand Up @@ -40,4 +42,21 @@ public ResponseCustom<CartResponse> getCartItems(
) {
return ResponseCustom.OK(orderService.getCartItems(AuthenticationParser.parseUserId(authentication)));
}
}

@Operation(summary = "상품 주문", description = "상품을 주문합니다.")
@PostMapping
public ResponseCustom<Message> order(
Authentication authentication,
@RequestBody OrderRequest orderRequest
) {
return ResponseCustom.OK(orderService.order(AuthenticationParser.parseUserId(authentication), orderRequest));
}

@Operation(summary = "식권 사용", description = "식권을 사용합니다.")
public ResponseCustom<Message> useMealTicket(
Authentication authentication,
@PathVariable Long orderId
) {
return ResponseCustom.OK(orderService.useMealTicket(AuthenticationParser.parseUserId(authentication), orderId));
}
}