Skip to content

Commit

Permalink
refactor: saveOrder 리팩토링
Browse files Browse the repository at this point in the history
- 과정별 인터페이스 생성
- 파사드 패턴 적용
  • Loading branch information
axhtl committed Jul 17, 2024
1 parent c0c452f commit fc0d945
Show file tree
Hide file tree
Showing 18 changed files with 288 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.store.clothstar.order.service.OrderSave;

import org.store.clothstar.member.domain.Address;
import org.store.clothstar.member.domain.Member;
import org.store.clothstar.order.domain.Order;
import org.store.clothstar.order.dto.request.CreateOrderRequest;

public interface OrderCreator {
Order createOrder(CreateOrderRequest request,Member member,Address address);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.store.clothstar.order.service.OrderSave;

import org.springframework.stereotype.Service;
import org.store.clothstar.member.domain.Address;
import org.store.clothstar.member.domain.Member;
import org.store.clothstar.order.domain.Order;
import org.store.clothstar.order.dto.request.CreateOrderRequest;


@Service
public class OrderCreatorImpl implements OrderCreator {

@Override
public Order createOrder(CreateOrderRequest request,Member member,Address address) {
return request.toOrder(member, address);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.store.clothstar.order.service.OrderSave;

import org.store.clothstar.order.domain.Order;
import org.store.clothstar.order.domain.OrderDetail;

public interface OrderDetailAdder {
void addOrderDetail(Order order, OrderDetail orderDetail);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.store.clothstar.order.service.OrderSave;

import org.springframework.stereotype.Service;
import org.store.clothstar.order.domain.Order;
import org.store.clothstar.order.domain.OrderDetail;

@Service
public class OrderDetailAdderImpl implements OrderDetailAdder {
@Override
public void addOrderDetail(Order order, OrderDetail orderDetail) {
order.addOrderDetail(orderDetail);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.store.clothstar.order.service.OrderSave;

import org.store.clothstar.order.domain.Order;
import org.store.clothstar.order.domain.OrderDetail;
import org.store.clothstar.order.dto.request.CreateOrderDetailRequest;
import org.store.clothstar.product.entity.ProductEntity;
import org.store.clothstar.productLine.entity.ProductLineEntity;

public interface OrderDetailCreator {
OrderDetail createOrderDetail(CreateOrderDetailRequest createOrderDetailRequest, Order order, ProductLineEntity productLineEntity, ProductEntity productEntity);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.store.clothstar.order.service.OrderSave;

import org.springframework.stereotype.Service;
import org.store.clothstar.order.domain.Order;
import org.store.clothstar.order.domain.OrderDetail;
import org.store.clothstar.order.dto.request.CreateOrderDetailRequest;
import org.store.clothstar.product.entity.ProductEntity;
import org.store.clothstar.productLine.entity.ProductLineEntity;

@Service
public class OrderDetailCreatorImpl implements OrderDetailCreator {
@Override
public OrderDetail createOrderDetail(CreateOrderDetailRequest createOrderDetailRequest, Order order, ProductLineEntity productLineEntity, ProductEntity productEntity) {
return createOrderDetailRequest.toOrderDetail(order, productLineEntity, productEntity);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.store.clothstar.order.service.OrderSave;

import org.store.clothstar.order.dto.request.CreateOrderDetailRequest;
import org.store.clothstar.product.entity.ProductEntity;

public interface OrderDetailValidator {
void validateOrderDetail(CreateOrderDetailRequest request, ProductEntity product);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.store.clothstar.order.service.OrderSave;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import org.store.clothstar.order.dto.request.CreateOrderDetailRequest;
import org.store.clothstar.product.entity.ProductEntity;

@Service
public class OrderDetailValidatorImpl implements OrderDetailValidator{
@Override
public void validateOrderDetail(CreateOrderDetailRequest request, ProductEntity product) {
if (request.getQuantity() > product.getStock()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "주문 개수가 재고보다 더 많습니다.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.store.clothstar.order.service.OrderSave;

import org.store.clothstar.order.domain.Order;
import org.store.clothstar.order.domain.OrderDetail;

public interface OrderPriceUpdater {
void updateOrderPrice(Order order, OrderDetail orderDetail);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.store.clothstar.order.service.OrderSave;

import org.springframework.stereotype.Service;
import org.store.clothstar.order.domain.Order;
import org.store.clothstar.order.domain.OrderDetail;

@Service
public class OrderPriceUpdaterImpl implements OrderPriceUpdater {
@Override
public void updateOrderPrice(Order order, OrderDetail orderDetail) {
int newTotalProductsPrice = order.getTotalPrice().getProducts() + orderDetail.getPrice().getOneKindTotalPrice();
int newTotalPaymentPrice =
order.getTotalPrice().getProducts() + order.getTotalPrice().getShipping() + orderDetail.getPrice().getOneKindTotalPrice();

order.getTotalPrice().updatePrices(newTotalProductsPrice, newTotalPaymentPrice);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package org.store.clothstar.order.service.OrderSave;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
import org.store.clothstar.member.domain.Address;
import org.store.clothstar.member.domain.Member;
import org.store.clothstar.member.service.AddressService;
import org.store.clothstar.member.service.MemberService;
import org.store.clothstar.order.domain.Order;
import org.store.clothstar.order.domain.OrderDetail;
import org.store.clothstar.order.dto.request.CreateOrderDetailRequest;
import org.store.clothstar.order.dto.request.CreateOrderRequest;
import org.store.clothstar.order.dto.request.OrderRequestWrapper;
import org.store.clothstar.product.entity.ProductEntity;
import org.store.clothstar.product.service.ProductService;
import org.store.clothstar.productLine.entity.ProductLineEntity;
import org.store.clothstar.productLine.service.ProductLineService;

@Service
public class OrderSaveFacade {

private final MemberService memberService;
private final AddressService addressService;
private final ProductService productService;
private final ProductLineService productLineService;
private final OrderCreator orderCreator;
private final OrderDetailValidator orderDetailValidator;
private final OrderDetailCreator orderDetailCreator;
private final OrderDetailAdder orderDetailAdder;
private final OrderSaver orderSaver;
private final OrderPriceUpdater orderPriceUpdater;
private final StockUpdater stockUpdater;


public OrderSaveFacade(
MemberService memberService, AddressService addressService
, ProductService productService, ProductLineService productLineService
, OrderCreator orderCreator
, OrderDetailValidator orderDetailValidator
, OrderDetailCreator orderDetailCreator
, OrderDetailAdder orderDetailAdder
, OrderSaver orderSaver
, OrderPriceUpdater orderPriceUpdater
, StockUpdater stockUpdater
) {
this.memberService = memberService;
this.addressService = addressService;
this.productService = productService;
this.productLineService = productLineService;
this.orderCreator=orderCreator;
this.orderDetailValidator = orderDetailValidator;
this.orderDetailCreator = orderDetailCreator;
this.orderDetailAdder=orderDetailAdder;
this.orderSaver=orderSaver;
this.orderPriceUpdater=orderPriceUpdater;
this.stockUpdater=stockUpdater;
}

@Transactional
public Long saveOrder(OrderRequestWrapper orderRequestWrapper) {
CreateOrderRequest createOrderRequest = orderRequestWrapper.getCreateOrderRequest();
CreateOrderDetailRequest createOrderDetailRequest = orderRequestWrapper.getCreateOrderDetailRequest();
Member member = memberService.getMemberByMemberId(createOrderRequest.getMemberId());
Address address = addressService.getAddressById(createOrderRequest.getAddressId());
ProductLineEntity productLineEntity = productLineService.findById(createOrderDetailRequest.getProductLineId())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "상품을 찾을 수 없습니다"));
ProductEntity productEntity = productService.findById(createOrderDetailRequest.getProductId())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "상품 옵션을 찾을 수 없습니다"));

// 요청 DTO로부터 주문 생성
Order order = orderCreator.createOrder(createOrderRequest,member,address);

// 주문상세 생성 유효성 검사
orderDetailValidator.validateOrderDetail(createOrderDetailRequest,productEntity);

// 주문상세 생성
OrderDetail orderDetail = orderDetailCreator.createOrderDetail(createOrderDetailRequest, order, productLineEntity, productEntity);

// 주문에 주문상세 추가
orderDetailAdder.addOrderDetail(order, orderDetail);

// 주문 저장 (orderDetail은 cascade 설정에 의해 자동 저장됨)
orderSaver.saveOrder(order);

// 주문 정보 업데이트
orderPriceUpdater.updateOrderPrice(order,orderDetail);

// 주문 수량만큼 상품 재고 차감
stockUpdater.updateStock(productEntity,orderDetail.getQuantity());

return order.getOrderId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.store.clothstar.order.service.OrderSave;

import org.store.clothstar.order.domain.Order;

public interface OrderSaver {
void saveOrder(Order order);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.store.clothstar.order.service.OrderSave;

import org.springframework.stereotype.Service;
import org.store.clothstar.order.domain.Order;
import org.store.clothstar.order.repository.order.OrderUserRepository;

@Service
public class OrderSaverImpl implements OrderSaver{
private final OrderUserRepository orderUserRepository;

public OrderSaverImpl(OrderUserRepository orderUserRepository) {
this.orderUserRepository = orderUserRepository;
}
@Override
public void saveOrder(Order order) {
orderUserRepository.save(order);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.store.clothstar.order.service.OrderSave;

import org.store.clothstar.product.entity.ProductEntity;

public interface StockUpdater {
void updateStock(ProductEntity product, int quantity);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.store.clothstar.order.service.OrderSave;

import org.springframework.stereotype.Service;
import org.store.clothstar.product.entity.ProductEntity;
import org.store.clothstar.product.service.ProductService;

@Service
public class StockUpdaterImpl implements StockUpdater {

private static ProductService productService;

public StockUpdaterImpl(ProductService productService){
this.productService=productService;
}

@Override
public void updateStock(ProductEntity product, int quantity) {
productService.updateProductStock(product, quantity);
}
}
49 changes: 9 additions & 40 deletions src/main/java/org/store/clothstar/order/service/OrderService.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@
import org.store.clothstar.order.domain.type.Status;
import org.store.clothstar.order.domain.vo.OrderDetailDTO;
import org.store.clothstar.order.dto.reponse.OrderResponse;
import org.store.clothstar.order.dto.request.CreateOrderDetailRequest;
import org.store.clothstar.order.dto.request.CreateOrderRequest;
import org.store.clothstar.order.dto.request.OrderRequestWrapper;
import org.store.clothstar.order.repository.order.OrderDetailRepository;
import org.store.clothstar.order.repository.order.OrderUserRepository;
import org.store.clothstar.order.service.OrderSave.*;
import org.store.clothstar.product.entity.ProductEntity;
import org.store.clothstar.product.service.ProductService;
import org.store.clothstar.productLine.entity.ProductLineEntity;
Expand All @@ -42,19 +41,24 @@ public class OrderService {
private final OrderDetailService orderDetailService;
private final ProductService productService;
private final ProductLineService productLineService;
private final OrderSaveFacade orderSaveFacade;


public OrderService(
OrderUserRepository orderUserRepository
, MemberService memberService, AddressService addressService
, OrderDetailService orderDetailService, OrderDetailRepository orderDetailRepository,
ProductService productService, ProductLineService productLineService) {
, OrderDetailService orderDetailService, OrderDetailRepository orderDetailRepository
, ProductService productService, ProductLineService productLineService
, OrderSaveFacade orderSaveFacade
) {
this.orderUserRepository = orderUserRepository;
this.memberService = memberService;
this.addressService = addressService;
this.orderDetailRepository = orderDetailRepository;
this.orderDetailService = orderDetailService;
this.productService = productService;
this.productLineService = productLineService;
this.orderSaveFacade=orderSaveFacade;
}

@Transactional(readOnly = true)
Expand Down Expand Up @@ -156,42 +160,7 @@ public Slice<OrderResponse> getAllOrderSlicePaging(Pageable pageable) {

@Transactional
public Long saveOrder(OrderRequestWrapper orderRequestWrapper) {
CreateOrderRequest createOrderRequest = orderRequestWrapper.getCreateOrderRequest();
CreateOrderDetailRequest createOrderDetailRequest = orderRequestWrapper.getCreateOrderDetailRequest();

// 주문 생성
Member member = memberService.getMemberByMemberId(createOrderRequest.getMemberId());
Address address = addressService.getAddressById(createOrderRequest.getAddressId());

Order order = createOrderRequest.toOrder(member, address);

ProductLineEntity productLineEntity = productLineService.findById(createOrderDetailRequest.getProductLineId())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "상품을 찾을 수 없습니다"));
ProductEntity productEntity = productService.findById(createOrderDetailRequest.getProductId())
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "상품 옵션을 찾을 수 없습니다"));

// 주문상세 생성 유효성 검사
if (createOrderDetailRequest.getQuantity() > productEntity.getStock()) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "주문 개수가 재고보다 더 많습니다.");
}

OrderDetail orderDetail = createOrderDetailRequest.toOrderDetail(order, productLineEntity, productEntity);
order.addOrderDetail(orderDetail); // 주문에 주문상세 추가

// 주문 저장 (orderDetail은 cascade 설정에 의해 자동 저장됨)
orderUserRepository.save(order);

// 주문 정보 업데이트
int newTotalProductsPrice = order.getTotalPrice().getProducts() + orderDetail.getPrice().getOneKindTotalPrice();
int newTotalPaymentPrice =
order.getTotalPrice().getProducts() + order.getTotalPrice().getShipping() + orderDetail.getPrice().getOneKindTotalPrice();

order.getTotalPrice().updatePrices(newTotalProductsPrice, newTotalPaymentPrice);

// 주문 수량만큼 상품 재고 차감
orderDetailService.updateProductStock(productEntity, orderDetail.getQuantity());

return order.getOrderId();
return orderSaveFacade.saveOrder(orderRequestWrapper);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,4 +97,10 @@ public List<ProductEntity> findByIdIn(List<Long> productIds) {
public Optional<ProductEntity> findById(Long productId) {
return productRepository.findById(productId);
}

@Transactional
public void updateProductStock(ProductEntity productEntity, int quantity) {
long updatedStock = productEntity.getStock() - quantity;
productEntity.updateStock(updatedStock);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ void getWaitingOrder_test() {
Long productId = 3L;
Long productLineId = 4L;

//TODO 추후 개선 예정
List<Order> waitingOrders = List.of(order);
given(orderSellerRepository.findWaitingOrders()).willReturn(waitingOrders);
given(order.getMemberId()).willReturn(memberId);
Expand Down

0 comments on commit fc0d945

Please sign in to comment.