JPA1 - 주문 도메인 개발

young·2023년 5월 15일
0

Spring Boot

목록 보기
12/19
post-thumbnail

🖇️주문 엔티티, 주문상품 엔티티 개발

기능

  • createOrder() : 주문 엔티티를 생성할 때 사용하고,주문 회원, 배송정보, 주문상품의 정보를 받아서 실제 주문 엔티티 생성
  • cancel() : 주문 취소시 사용하고, 주문 상태를 취소로 변경하고 주문상품에 주문 취소 알림. 만약 이미 배송을 완료한 상품이면 주문을 취소하지 못하도록 예외 발생
  • 전체 주문 가격 조회: 주문 시 사용한 전체 주문 가격을 조회, 전체 주문 가격을 알려면 각각의 주문상품가격을 알아야 한다. 로직을 보면 연관된 주문상품들의 가격을 조회해서 더한 값을 반환

생성 메서드

📍Order.java
생성 메서드 : 앞으로 생성할 때 이 아이만 변경하면 됨

public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems){
        Order order = new Order();
        order.setMember(member);
        order.setDelivery(delivery);
        for(OrderItem orderItem : orderItems){
            order.addOrderItem(orderItem);
        }
        order.setStatus(OrderStatus.ORDER);
        order.setOrderDate(LocalDateTime.now());
        return order;
    }

📍OrderItem.java

public static OrderItem createOrderItem(Item item, int orderPrice, int count){
        OrderItem orderItem = new OrderItem();
        orderItem.setItem(item);
        orderItem.setOrderPrice(orderPrice);
        orderItem.setCount(count);

        item.removeStock(count);
        return orderItem;
    }

비즈니스 로직

📍Order.java-주문 취소

public void cancel(){
    if(delivery.getStatus()==DeliveryStatus.COMP)
    {
    throw new IllegalStateException("이미 배송완료로  취소 불가");}
    this.setStatus(OrderStatus.CANCEL);
    for(OrderItem orderItem : orderItems){
        orderItem.cancel();
    }
}

📍OrderItem.java
재고 상태를 원상복구 해줘야 함

public void cancel() {
    getItem().addStock(count);
}

조회 로직 - 전체 주문 가격 조회

📍Order.java - 전체 주문 가격 조회

public int getTotalPrice(){
    int totalPrice = 0;
    for(OrderItem orderItem : orderItems){
        totalPrice += orderItem.getTotalPrice()
    }
    return totalPrice;
}

📍OrderItem.java - 주문 상품 전체 가격 조회

public int getTotalPrice(){
    return getOrderPrice() * getCount();
}

🖇️주문 리포지토리 개발

  • 주문 리포지토리에는 주문 엔티티를 저장하고 검색하는 기능 마지막의 findAll(OrderSearch orderSearch) 메서드 -> 주문 검색 기능

🖇️주문 서비스 개발

 /** 주문 */
 // 엔티티 조회
	Member member = memberRepository.findOne(memberId);
	Item item = itemRepository.findOne(itemId);
// 배송정보 조회
	Delivery delivery = new Delivery();
	delivery.setAddress(member.getAddress());
	delivery.setStatus(DeliveryStatus.READY);
//주문상품 생성
	OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(),count);
 //주문 생성
	Order order = Order.createOrder(member,delivery, orderItem);
//주문 저장
	orderRepository.save(order);
	return order.getId();

/** 주문 취소 */
@Transactional
public void cancelOrder(Long orderId){
	Order order = orderRepository.findOne(orderId);  //주문 엔티티 조회
	order.cancel();                                  //주문 취소
}
/** 주문 검색 
public List<Order> findOrders(OrderSearch orderSearch) {
    return orderRepository.findAll(orderSearch);
}
*/

주문 저장 orderRepository.save(order);
: Order.java에서 orderItem을 CascadeType.All 옵션 설정으로
오더와 딜리버리가 같이 persist된다.

@NoArgsConstructor(access = AccessLevel.PROTECTED)

📎링크 참고

🖇️주문 기능 테스트

@Test(expected = NotEnoughStockException.class)

private Member createMember() {
	Member member = new Member();
	member.setName("회원1");
	member.setAddress(new Address());
	em.persist(member);
	return member;
}
private Book createBook(String name, int price, int stockQuantity) {
	Book book = new Book();
	book.setName(name);
    book.setStockQuantity(stockQuantity);
	book.setPrice(price);
    em.persist(book);
    return book;
}
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class OrderServiceTest {
    @PersistenceContext
    EntityManager em;
    @Autowired OrderService orderService;
    @Autowired OrderRepository orderRepository;
    @Test
    public void 상품주문() throws Exception {
        //Given
        Member member = createMember();
        Item item = createBook("시골 JPA", 10000, 10);
        int orderCount = 2;
        //When
        Long orderId = orderService.order(member.getId(), item.getId(), orderCount);
        //Then
        Order getOrder = orderRepository.findOne(orderId);
        assertEquals("상품 주문시 상태는 ORDER",OrderStatus.ORDER, getOrder.getStatus());
        assertEquals("주문한 상품 종류 수가 정확해야 한다.",1, getOrder.getOrderItems().size());
        assertEquals("주문 가격은 가격 * 수량이다.", 10000 * 2, getOrder.getTotalPrice());
        assertEquals("주문 수량만큼 재고가 줄어야 한다.",8, item.getStockQuantity());
    }
    @Test(expected = NotEnoughStockException.class)
    public void 상품주문_재고수량초과() throws Exception {
        //Given
        Member member = createMember();
        Item item = createBook("시골 JPA", 10000, 10);
        int orderCount = 11; //재고보다 많은 수량
        //When
        orderService.order(member.getId(), item.getId(), orderCount);
        //Then
        fail("재고 수량 부족 예외");
    }
    @Test
    public void 주문취소() {
        //Given
        Member member = createMember();
        Item item = createBook("시골 JPA", 10000, 10);
        int orderCount = 2;

        Long orderId = orderService.order(member.getId(), item.getId(), orderCount);
        //When
        orderService.cancelOrder(orderId);
        //Then
        Order getOrder = orderRepository.findOne(orderId);
        assertEquals("주문 취소시 상태는 CANCEL 이다.",OrderStatus.CANCEL, getOrder.getStatus());
        assertEquals("주문이 취소된 상품은 그만큼 재고가 증가해야 한다.", 10, item.getStockQuantity());
    }
    
}

=

🖇️주문 검색 기능 개발

= orderSearch를 완성시키는 과정
📍OrderSearch.java

@Getter @Setter
public class OrderSearch {
    private String memberName;
    private OrderStatus orderStatus; // 주문 상태[ORDER, CANCEL]
}
public List<Order> findAll(OrderSearch orderSearch){ }

Jpa에서의 동적 쿼리 ?

동적쿼리 : 특정 조건들이나 상황에 따라 변경되는 쿼리를 의미

JPQL ?

JPA에서 지원하는 다양한 방식의 쿼리 중 하나

  • 객체 그 자체를 테이블이라 생각하는 대표적인 객체지향 쿼리
  • 현재 DB에 대한 지식이 없다는 가정 하에 사용할 때 유리
    Entity 객체 그 자체가 Table이며, 어떤 Table이 존재하는 지 일일히 분석할 필요없이 객체들만 보고 쿼리를 짤 수 있는 특징
  • JPQL 쿼리를 처리하는 것이 EntityManager를 활용하는 것
profile
ฅʕ•̫͡•ʔฅ

0개의 댓글