Skip to content

Commit

Permalink
OutOfStockHandlingOption 추가에 따른 로직 수정 및 테스트 코드 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
daadaadaah committed Jun 17, 2023
1 parent 2d7d67b commit 6af352a
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public ResponseDto placeOrder(@Valid @RequestBody OrderForm orderForm) {
* - 재고 부족으로 주문이 불가능한 경우 409 error 예외 : 재고가 0이어서 불가능한 경우가 있을 수 있고, 재고는 2개인데, 주문량이 3개여서 주문이 불가능한 경우도 있을 수 있는데, 이 경우는 어떻게 처리할 것인가?
*/

orderService.placeOrder(orderForm);

return ResponseDto.builder()
.code(HttpStatus.CREATED.name())
.message("주문 접수가 완료되었습니다.")
Expand Down
21 changes: 11 additions & 10 deletions src/main/java/com/hcommerce/heecommerce/order/OrderService.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.hcommerce.heecommerce.order;

import com.hcommerce.heecommerce.inventory.InventoryCommandRepository;
import com.hcommerce.heecommerce.inventory.InventoryQueryRepository;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -44,18 +42,22 @@ public void placeOrder(OrderForm orderForm) {

int inventory = inventoryQueryRepository.get(key); // key에 해당 하는 값 없으면 Null 나옴 -> TODO : Null 처리 어떻게? Optional 활용?

if(inventory <= 0) {
int orderQuantity = orderForm.getOrderQuantity();

int realOrderQuantity = 0;

if(inventory <= 0 || (inventory < orderQuantity && orderForm.getOutOfStockHandlingOption() == OutOfStockHandlingOption.ALL_CANCEL)) {
throw new OrderOverStockException();
}

int orderQuantity = orderForm.getOrderQuantity();

if(orderQuantity > inventory) {
// TODO : OrderForm에 OutOfStockHandlingOption 추가 PR Merge 되면 로직 추가하기
if (inventory < orderQuantity && orderForm.getOutOfStockHandlingOption() == OutOfStockHandlingOption.PARTIAL_ORDER) {
realOrderQuantity = inventory; // 재고량 만큼만 주문
} else {
realOrderQuantity = orderQuantity;
}

// 2. 재고량 감소
int currentInventory = inventoryCommandRepository.decreaseByAmount(key, orderQuantity); // TODO : 결제가 실패하여 재고량 다시 원상복귀해야할 때도, 분산락 걸어줘야 되나?
int currentInventory = inventoryCommandRepository.decreaseByAmount(key, realOrderQuantity); // TODO : 결제가 실패하여 재고량 다시 원상복귀해야할 때도, 분산락 걸어줘야 되나?

if(currentInventory == 0) {
// TODO : [품절 처리] Redis에 저장된 dealproducts 목록에서 딜 상품 상태 오픈 -> 품절로 변경
Expand All @@ -68,11 +70,10 @@ public void placeOrder(OrderForm orderForm) {
boolean isSuccessPayment = false; // TODO : 임시 데이터

if(!isSuccessPayment) {
inventoryCommandRepository.increaseByAmount(key, orderQuantity);
inventoryCommandRepository.increaseByAmount(key, realOrderQuantity);
return;
}


/**
* 바로 MySQL을 사용한 것과 AWS SQS를 사용한 것과 어떤 차이가 있을까?
* 주문, 배송, 결제 가 각각 다른 Table 또는 다른 DB에 있을 때 이 작업 단위를 원자 단위로 하고 싶거나 또는
Expand Down
110 changes: 102 additions & 8 deletions src/test/java/com/hcommerce/heecommerce/order/OrderControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,11 @@ void it_returns_401_Error() throws Exception {
@DisplayName("POST /orders")
class Describe_PlaceOrder_API {
@Nested
@DisplayName("when order is successful")
@DisplayName("with orderQuantity < inventory")
class Context_When_Order_Is_Successful {
@Test
@DisplayName("returns 201")
void it_returns_201() throws Exception {
void It_returns_201() throws Exception {
// when
OrderForm orderForm = OrderForm.builder()
.userId(1)
Expand Down Expand Up @@ -212,11 +212,106 @@ void it_returns_201() throws Exception {
}

@Nested
@DisplayName("when order fails due to invalid orderForm with orderQuantity > maxOrderQuantityPerOrder")
class Context_When_Order_Fails {
@DisplayName("with orderQuantity > inventory and outOfStockHandlingOption is `PARTIAL_ORDER`")
class Context_With_OrderQuantity_Exceeds_Inventory_And_OutOfStockHandlingOption_Is_PARTIAL_ORDER {
@Test
@DisplayName("returns 201")
void It_returns_201() throws Exception {
// given
UUID UUID_WITH_ORDER_QUANTITY_EXCEEDING_INVENTORY = UUID.randomUUID();

int ORDER_QUANTITY_EXCEEDING_INVENTORY = 5;

OutOfStockHandlingOption PARTIAL_ORDER = OutOfStockHandlingOption.PARTIAL_ORDER;

// when
OrderForm orderForm = OrderForm.builder()
.userId(1)
.recipientInfoForm(
RecipientInfoForm.builder()
.recipientName("leecommerce")
.recipientPhoneNumber("01087654321")
.recipientAddress("서울시 ")
.recipientDetailAddress("101호")
.shippingRequest("빠른 배송 부탁드려요!")
.build()
)
.outOfStockHandlingOption(PARTIAL_ORDER)
.dealProductUuid(UUID_WITH_ORDER_QUANTITY_EXCEEDING_INVENTORY)
.orderQuantity(ORDER_QUANTITY_EXCEEDING_INVENTORY)
.paymentType(PaymentType.CREDIT_CARD)
.build();

String content = objectMapper.writeValueAsString(orderForm);

ResultActions resultActions = mockMvc.perform(
post("/orders")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(content)
);

// then
resultActions.andExpect(status().isCreated());
}
}

@Nested
@DisplayName("with orderQuantity > inventory and outOfStockHandlingOption is `ALL_CANCEL`")
class Context_With_OrderQuantity_Exceeds_Inventory_And_OutOfStockHandlingOption_Is_ALL_CANCEL {
@Test
@DisplayName("returns 409 error")
void It_returns_409() throws Exception {
// given
UUID UUID_WITH_ORDER_QUANTITY_EXCEEDING_INVENTORY = UUID.randomUUID();

int ORDER_QUANTITY_EXCEEDING_INVENTORY = 5;

OutOfStockHandlingOption ALL_CANCEL = OutOfStockHandlingOption.ALL_CANCEL;

// when
OrderForm orderForm = OrderForm.builder()
.userId(1)
.recipientInfoForm(
RecipientInfoForm.builder()
.recipientName("leecommerce")
.recipientPhoneNumber("01087654321")
.recipientAddress("서울시 ")
.recipientDetailAddress("101호")
.shippingRequest("빠른 배송 부탁드려요!")
.build()
)
.outOfStockHandlingOption(ALL_CANCEL)
.dealProductUuid(UUID_WITH_ORDER_QUANTITY_EXCEEDING_INVENTORY)
.orderQuantity(ORDER_QUANTITY_EXCEEDING_INVENTORY)
.paymentType(PaymentType.CREDIT_CARD)
.build();

String content = objectMapper.writeValueAsString(orderForm);

ResultActions resultActions = mockMvc.perform(
post("/orders")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(content)
);

// then
resultActions.andExpect(status().isConflict());
}
}

@Nested
@DisplayName("with orderQuantity > maxOrderQuantityPerOrder")
class Context_With_OrderQuantity_Exceeds_MaxOrderQuantityPerOrder {
@Test
@DisplayName("returns 400 error")
void it_returns_400() throws Exception {
void It_returns_400() throws Exception {
// given
UUID UUID_WITH_MAX_ORDER_QUANTITY_PER_ORDER_OF_10 = UUID.randomUUID();

int ORDER_QUANTITY_EXCEEDING_MAX_ORDER_QUANTITY_PER_ORDER = 12;

// when
OrderForm orderForm = OrderForm.builder()
.userId(1)
Expand All @@ -230,8 +325,8 @@ void it_returns_400() throws Exception {
.build()
)
.outOfStockHandlingOption(OutOfStockHandlingOption.ALL_CANCEL)
.dealProductUuid(UUID.randomUUID())
.orderQuantity(12)
.dealProductUuid(UUID_WITH_MAX_ORDER_QUANTITY_PER_ORDER_OF_10)
.orderQuantity(ORDER_QUANTITY_EXCEEDING_MAX_ORDER_QUANTITY_PER_ORDER)
.paymentType(PaymentType.CREDIT_CARD)
.build();

Expand All @@ -247,7 +342,6 @@ void it_returns_400() throws Exception {
// then
resultActions.andExpect(status().isBadRequest());
}

}
}
}

0 comments on commit 6af352a

Please sign in to comment.