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] 장바구니에 현재까지 담은 음식 상품의 금액을 볼 수 있는 기능 추가 #70

Merged
24 changes: 21 additions & 3 deletions src/main/java/camp/woowak/lab/cart/domain/Cart.java
june-777 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,27 @@

@Getter
public class Cart {
private String customerId;
private List<Menu> menuList;
private final String customerId;
private final List<Menu> menuList;

/**
* 생성될 때 무조건 cart가 비어있도록 구현
*
* @param customerId 장바구니 소유주의 ID값입니다.
*/
public Cart(String customerId) {
this(customerId, new LinkedList<>());
}

/**
* 해당 Domain을 사용하는 같은 패키지내의 클래스, 혹은 자식 클래스는 List를 커스텀할 수 있습니다.
*
* @param customerId 장바구니 소유주의 ID값입니다.
* @param menuList 장바구니에 사용될 List입니다.
*/
protected Cart(String customerId, List<Menu> menuList) {
this.customerId = customerId;
this.menuList = new LinkedList<>();
this.menuList = menuList;
}

public void addMenu(Menu menu) {
Expand All @@ -36,6 +46,14 @@ public void addMenu(Menu menu) {
this.menuList.add(menu);
}

public long getTotalPrice() {
return this.menuList.stream()
.map(Menu::getPrice)
.mapToLong(Long::valueOf)
.boxed()
.reduce(0L, Long::sum);
}

private void validateStoreOpenTime(Store store) {
if (!store.isOpen()) {
StoreTime storeTime = store.getStoreTime();
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/camp/woowak/lab/cart/service/CartService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import camp.woowak.lab.cart.exception.MenuNotFoundException;
import camp.woowak.lab.cart.repository.CartRepository;
import camp.woowak.lab.cart.service.command.AddCartCommand;
import camp.woowak.lab.cart.service.command.CartTotalPriceCommand;
import camp.woowak.lab.menu.domain.Menu;
import camp.woowak.lab.menu.repository.MenuRepository;

Expand Down Expand Up @@ -34,6 +35,11 @@ public void addMenu(AddCartCommand command) {
cartRepository.save(customerCart);
}

public long getTotalPrice(CartTotalPriceCommand command) {
return getCart(command.customerId())
.getTotalPrice();
}

private Cart getCart(String customerId) {
return cartRepository.findByCustomerId(customerId)
.orElse(cartRepository.save(new Cart(customerId)));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package camp.woowak.lab.cart.service.command;

public record CartTotalPriceCommand(
String customerId
) {
}
14 changes: 14 additions & 0 deletions src/main/java/camp/woowak/lab/web/api/cart/CartApiController.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package camp.woowak.lab.web.api.cart;

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;
import org.springframework.web.bind.annotation.RestController;

import camp.woowak.lab.cart.service.CartService;
import camp.woowak.lab.cart.service.command.AddCartCommand;
import camp.woowak.lab.cart.service.command.CartTotalPriceCommand;
import camp.woowak.lab.web.authentication.LoginCustomer;
import camp.woowak.lab.web.authentication.annotation.AuthenticationPrincipal;
import camp.woowak.lab.web.dto.request.cart.AddCartRequest;
import camp.woowak.lab.web.dto.response.cart.AddCartResponse;
import camp.woowak.lab.web.dto.response.cart.CartTotalPriceResponse;
import lombok.extern.slf4j.Slf4j;

@RestController
Expand All @@ -33,4 +36,15 @@ public AddCartResponse addCart(
log.info("Customer({}) add Menu({}) in Cart", loginCustomer.getId(), addCartRequest.menuId());
return new AddCartResponse(true);
}

@GetMapping("/price")
public CartTotalPriceResponse getCartTotalPrice(
@AuthenticationPrincipal LoginCustomer loginCustomer
) {
CartTotalPriceCommand command = new CartTotalPriceCommand(loginCustomer.getId().toString());
long totalPrice = cartService.getTotalPrice(command);

log.info("Customer({})'s total price in cart is {}", loginCustomer.getId(), totalPrice);
return new CartTotalPriceResponse(totalPrice);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package camp.woowak.lab.web.dto.response.cart;

public record CartTotalPriceResponse(
long totalPrice
) {
}
136 changes: 136 additions & 0 deletions src/test/java/camp/woowak/lab/cart/domain/CartTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package camp.woowak.lab.cart.domain;

import static org.assertj.core.api.Assertions.*;

import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import camp.woowak.lab.cart.exception.OtherStoreMenuException;
import camp.woowak.lab.cart.exception.StoreNotOpenException;
import camp.woowak.lab.fixture.CartFixture;
import camp.woowak.lab.menu.domain.Menu;
import camp.woowak.lab.menu.domain.MenuCategory;
import camp.woowak.lab.payaccount.domain.PayAccount;
import camp.woowak.lab.store.domain.Store;
import camp.woowak.lab.vendor.domain.Vendor;
import camp.woowak.lab.web.authentication.NoOpPasswordEncoder;

@DisplayName("Cart 클래스는")
class CartTest implements CartFixture {
private final String customerId = UUID.randomUUID().toString();

private List<Menu> cartList;
private Cart cart;
private Menu menu;
private int minPrice = 8000;
private Store store;
private Vendor vendor;

@BeforeEach
void setUp() {
cartList = new LinkedList<>();
cart = new Cart(customerId, cartList);

vendor = createSavedVendor(UUID.randomUUID(), new PayAccount(), new NoOpPasswordEncoder());
store = createSavedStore(1L, vendor, "중화반점", minPrice,
LocalDateTime.now().minusMinutes(10).withSecond(0).withNano(0),
LocalDateTime.now().plusMinutes(10).withSecond(0).withNano(0));
menu = createSavedMenu(1L, store, new MenuCategory(store, "중식"), "짜장면", 9000);
}

@Nested
@DisplayName("addMenu 메서드")
class AddMenuTest {
@Test
@DisplayName("Menu를 받으면 cart에 저장된다.")
void addMenuTest() {
//given

//when
cart.addMenu(menu);

//then
assertThat(cartList.get(0)).isEqualTo(menu);
}

@Test
@DisplayName("열지 않은 가게의 메뉴를 담으면 StoreNotOpenException을 던진다.")
void storeNotOpenExceptionTest() {
//given
Store closedStore = createSavedStore(2L, vendor, "closed", minPrice,
LocalDateTime.now().minusMinutes(30).withSecond(0).withNano(0),
LocalDateTime.now().minusMinutes(10).withSecond(0).withNano(0));
Menu closedMenu = createSavedMenu(2L, closedStore, new MenuCategory(closedStore, "중식"), "짬뽕", 9000);

//when & then
assertThatThrownBy(() -> cart.addMenu(closedMenu))
.isExactlyInstanceOf(StoreNotOpenException.class);
assertThat(cartList).isEmpty();
}

@Test
@DisplayName("다른 가게의 메뉴를 함께 담으면 OtherStoreMenuException을 던진다.")
void otherStoreMenuExceptionTest() {
//given
cart.addMenu(menu);

Store otherStore = createSavedStore(2L, vendor, "closed", minPrice,
LocalDateTime.now().minusMinutes(30).withSecond(0).withNano(0),
LocalDateTime.now().plusMinutes(30).withSecond(0).withNano(0));
Menu otherStoreMenu = createSavedMenu(2L, otherStore, new MenuCategory(otherStore, "중식"), "짬뽕", 9000);

//when & then
assertThatThrownBy(() -> cart.addMenu(otherStoreMenu))
.isExactlyInstanceOf(OtherStoreMenuException.class);
assertThat(cartList).doesNotContain(otherStoreMenu);
assertThat(cartList).contains(menu);
}
}

@Nested
@DisplayName("totalPrice 메서드는")
class GetTotalPriceTest {
@Test
@DisplayName("장바구니가 비어있으면 0원을 return한다.")
void getTotalPriceWithEmptyList() {
//given

//when
long totalPrice = cart.getTotalPrice();

//then
assertThat(totalPrice).isEqualTo(0);
}

@Test
@DisplayName("현재 장바구니에 담긴 모든 메뉴의 총 금액을 return 받는다.")
void getTotalPriceTest() {
//given
MenuCategory menuCategory = new MenuCategory(store, "중식");
int price1 = 1000;
Menu menu1 = createSavedMenu(2L, store, menuCategory, "짜장면1", price1);
cart.addMenu(menu1);

int price2 = 2000;
Menu menu2 = createSavedMenu(3L, store, menuCategory, "짬뽕1", price2);
cart.addMenu(menu2);

int price3 = Integer.MAX_VALUE;
Menu menu3 = createSavedMenu(4L, store, menuCategory, "황제정식", price3);
cart.addMenu(menu3);

//when
long totalPrice = cart.getTotalPrice();

//then
assertThat(totalPrice).isEqualTo((long)price1 + (long)price2 + (long)price3);
}
}
}
69 changes: 62 additions & 7 deletions src/test/java/camp/woowak/lab/cart/service/CartServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import camp.woowak.lab.cart.exception.StoreNotOpenException;
import camp.woowak.lab.cart.repository.CartRepository;
import camp.woowak.lab.cart.service.command.AddCartCommand;
import camp.woowak.lab.cart.service.command.CartTotalPriceCommand;
import camp.woowak.lab.customer.domain.Customer;
import camp.woowak.lab.customer.repository.CustomerRepository;
import camp.woowak.lab.menu.domain.Menu;
Expand Down Expand Up @@ -66,6 +67,7 @@ class CartServiceTest {

private Customer customer;
private Menu menu;
private MenuCategory menuCategory;
private Store store;
private Vendor vendor;

Expand All @@ -77,7 +79,9 @@ void setUp() {

store = createStore(vendor, "중화반점", minOrderPrice, startTime, endTime);

menu = createMenu(store, "짜장면", 90000);
menuCategory = createMenuCategory(store, "중식");

menu = createMenu(store, menuCategory, "짜장면", 90000);
}

@Nested
Expand Down Expand Up @@ -118,7 +122,8 @@ void throwExceptionWhenAddMenuInCartWithClosedStoresMenu() {
LocalDateTime startTime = LocalDateTime.now().minusMinutes(10).withSecond(0).withNano(0);
LocalDateTime endTime = LocalDateTime.now().minusMinutes(1).withSecond(0).withNano(0);
Store closedStore = createStore(vendor, "오픈 전의 중화반점", 8000, startTime, endTime);
Menu menu = createMenu(closedStore, "닫힌 가게의 메뉴", 1000);
MenuCategory closedMenuCategory = createMenuCategory(closedStore, "닫힌 카테고리");
Menu menu = createMenu(closedStore, closedMenuCategory, "닫힌 가게의 메뉴", 1000);

AddCartCommand command = new AddCartCommand(customer.getId().toString(), menu.getId());

Expand All @@ -132,7 +137,8 @@ void throwExceptionWhenAddMenuInCartWithClosedStoresMenu() {
void throwExceptionWhenAddMenuInCartWithOtherStoresMenu() {
//given
Store otherStore = createStore(vendor, "다른집", 8000, startTime, endTime);
Menu otherStoresMenu = createMenu(otherStore, "다른집 짜장면", 9000);
MenuCategory otherMenuCategory = createMenuCategory(otherStore, "다른집 카테고리");
Menu otherStoresMenu = createMenu(otherStore, otherMenuCategory, "다른집 짜장면", 9000);

AddCartCommand command1 = new AddCartCommand(customer.getId().toString(), menu.getId());
cartService.addMenu(command1);
Expand All @@ -144,10 +150,59 @@ void throwExceptionWhenAddMenuInCartWithOtherStoresMenu() {
}
}

private Menu createMenu(Store store, String name, int price) {
MenuCategory menuCategory = new MenuCategory(store, "카테고리1");
menuCategoryRepository.saveAndFlush(menuCategory);
Menu menu1 = new Menu(store, menuCategory,name, price,"imageUrl");
@Nested
@DisplayName("getTotalPrice 메서드")
class GetTotalPrice {
@Nested
@DisplayName("totalPrice 메서드는")
class GetTotalPriceTest {
@Test
@DisplayName("장바구니가 비어있으면 0원을 return한다.")
void getTotalPriceWithEmptyList() {
//given
CartTotalPriceCommand command = new CartTotalPriceCommand(customer.getId().toString());

//when
long totalPrice = cartService.getTotalPrice(command);

//then
assertThat(totalPrice).isEqualTo(0);
}

@Test
@DisplayName("현재 장바구니에 담긴 모든 메뉴의 총 금액을 return 받는다.")
void getTotalPriceTest() {
//given
int price1 = 1000;
Menu menu1 = createMenu(store, menuCategory, "짜장면1", price1);
cartService.addMenu(new AddCartCommand(customer.getId().toString(), menu1.getId()));

int price2 = 2000;
Menu menu2 = createMenu(store, menuCategory, "짬뽕1", price2);
cartService.addMenu(new AddCartCommand(customer.getId().toString(), menu2.getId()));

int price3 = Integer.MAX_VALUE;
Menu menu3 = createMenu(store, menuCategory, "황제정식", price3);
cartService.addMenu(new AddCartCommand(customer.getId().toString(), menu3.getId()));

CartTotalPriceCommand command = new CartTotalPriceCommand(customer.getId().toString());

//when
long totalPrice = cartService.getTotalPrice(command);

//then
assertThat(totalPrice).isEqualTo((long)price1 + (long)price2 + (long)price3);
}
}
}

private MenuCategory createMenuCategory(Store store, String name) {
MenuCategory menuCategory1 = new MenuCategory(store, name);
return menuCategoryRepository.saveAndFlush(menuCategory1);
}

private Menu createMenu(Store store, MenuCategory menuCategory, String name, int price) {
Menu menu1 = new Menu(store, menuCategory, name, price, "imageUrl");
menuRepository.saveAndFlush(menu1);

return menu1;
Expand Down
31 changes: 31 additions & 0 deletions src/test/java/camp/woowak/lab/fixture/CartFixture.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package camp.woowak.lab.fixture;

import java.time.LocalDateTime;
import java.util.UUID;

import camp.woowak.lab.menu.TestMenu;
import camp.woowak.lab.menu.domain.Menu;
import camp.woowak.lab.menu.domain.MenuCategory;
import camp.woowak.lab.payaccount.domain.PayAccount;
import camp.woowak.lab.store.TestStore;
import camp.woowak.lab.store.domain.Store;
import camp.woowak.lab.vendor.TestVendor;
import camp.woowak.lab.vendor.domain.Vendor;
import camp.woowak.lab.web.authentication.PasswordEncoder;

public interface CartFixture {
default Vendor createSavedVendor(UUID id, PayAccount payAccount, PasswordEncoder passwordEncoder) {
return new TestVendor(
id, "vendorName", "vendorEmail@example.com", "vendorPassword", "010-0000-0000", payAccount,
passwordEncoder);
}

default Store createSavedStore(Long id, Vendor vendor, String name, int minOrderPrice, LocalDateTime startTIme,
LocalDateTime endTime) {
return new TestStore(id, vendor, name, "송파", "010-1234-5678", minOrderPrice, startTIme, endTime);
}

default Menu createSavedMenu(Long id, Store store, MenuCategory menuCategory, String name, int price) {
return new TestMenu(id, store, menuCategory, name, price);
}
}
Loading