package jpabook.jpashop.domain;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "orders")
@Getter @Setter
public class Order {
@Id @GeneratedValue
@Column(name = "order_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "delivery_id")
private Delivery delivery;
private LocalDateTime orderDate; //주문 시간
@Enumerated(EnumType.STRING)
private OrderStatus status; //주문 상태 [ORDER, CANCEL]
//연관관계 편입 메소드
public void setMember(Member member){
this.member = member;
member.getOrders().add(this);
}
public void addOrderItem(OrderItem orderItem){
orderItems.add(orderItem);
orderItem.setOrder(this);
}
public void setDelivery(Delivery delivery){
this.delivery = delivery;
delivery.setOrder(this);
}
// 생성 메소드
public static Order crteateOrder(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;
}
// 주문 취소
public void cancel(){
if (delivery.getStatus() == DeliveryStatus.COMP) {
throw new IllegalStateException("이미 배송완료된 상품은 취소가 불가능합니다.");
}
this.setStatus(OrderStatus.CANCEL);
for (OrderItem orderItem: orderItems) {
orderItem.cancel(); //주문했던 상품에 각각 취소날리기
}
}
// 조회 로직
// 전체 주문 가격 조회
public int getTotalPrice(){
int totalPrice = 0;
for(OrderItem orderItem : orderItems){
totalPrice += orderItem.getTotalPrice();
}
// totalPrice += orderItems.stream().mapToInt(OrderItem::getTotalPrice).sum(); 같은 역할
return totalPrice;
}
}
생성 메소드 createOrder() : 주문 엔티티를 생성할 때 사용. 주문 회원, 배송 정보, 주문 상품의 정보를 받아 실제 주문 엔티티를 생성한다.
주문 취소 cancel() : 주문 취소 시 사용. 주문 상태를 취소로 변경하고 주문 상품에 주문 취소를 알린다. 만약 이미 배송을 완료한 상품이면 주문을 취소하지 못하도록 예외 발생
전체 주문 가격 조회 getTotalPrice() : 주문 시 사용한 전체 주문 가격을 조회한다. 전체 주문 가격을 알려면 각각의 주문 상품 가격을 알아야 한다. 로직을 보면 연관된 주문 상품들의 가격을 조회하고 더한 값을 반환. (실무에서는 주로 주문에 전체 주문 가격 필드를 두고 역정규화 한다.)
package jpabook.jpashop.domain;
import jpabook.jpashop.domain.item.Item;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
@Entity
@Getter @Setter
public class OrderItem {
@Id @GeneratedValue
@Column(name = "order_item_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "item_id")
private Item item;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "order_id")
private Order order;
private int orderPrice; //주문 가격
private int count; //주문 수량
// 생성 메소드
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;
}
// 비즈니스 로직
public void cancel(){
getItem().addStock(count); //재고 수량을 다시 엔티티에 원복하기
}
// 조회 로직
// 주문 상품 전체 가격 조회
public int getTotalPrice() {
return getOrderPrice() * getCount();
}
}
생성 메소드 createOrderItem() ****: 주문 상품, 가격, 수량 정보를 사용해 주문 상품 엔티티를 생성한다. 그리고 item.removeStock(count)를 호출해 주문 수량만큼 상품 재고를 줄인다.
주문 취소 cancel() : getItem().addStock(count) 를 호출해서 취소한 주문 수량 만큼 상품의 재고를 증가시킨다.
주문 가격 조회 getTotalPrice() : 주문 가격에 수량을 곱한 값을 반환한다.