package jpabook.jpashop.domain;
import lombok.Getter;
import lombok.Setter;
import org.aspectj.weaver.ast.Or;
import javax.persistence.*;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import static javax.persistence.FetchType.*;
@Entity
@Table(name = "orders")
@Getter @Setter
public class Order {
@Id @GeneratedValue
@Column(name = "order_id")
private Long id;
@ManyToOne (fetch = LAZY)
@JoinColumn(name = "member_id")
private Member member;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();
@OneToOne(fetch = LAZY, cascade = CascadeType.ALL)
@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);
}
//생성 메서드 ...1
public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems) { //...2
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() { //...3
if (delivery.getStatus() == DeliveryStatus.COMP) {
throw new IllegalStateException("이미 배송완료된 상품은 취소가 불가능합니다.");
}
this.setStatus(Orderstatus.CANCEL);
for (OrderItem orderItem : orderItems) {
orderItem.cancel();
}
}
//조회 로직
/**
* 전체 주문 가격 조회
*/
public int getTotalPrice() { //...4
int totalPrice = 0;
for (OrderItem orderItem : orderItems) {
totalPrice += orderItem.getTotalPrice();
}
return totalPrice;
}
}
주문이기 때문에 중요한게 있습니다. 생성 메서드를 만들어야합니다.
주문 생성은 복잡합니다. Order만 생성해서 되는게 아니라 OrderItem, Delivery 등등 여러개 연관관계가 들어가고 복잡합니다. 그래서 이런 복잡한 생성은 별도의 생성 메서드가 있으면 좋습니다.
→ 정적 팩토리 메서드 (static factory method)
이렇게 하면 Order가 연관관계를 쫙 걸면서 세팅이 되서 한 번에 생성이 됩니다.
이게 중요한 이유는 앞으로 생성해야하는 지점을 변경해야한다면 생성 메서드만 변경하면 됩니다. 여기저기 찾아다닐 필요가 없습니다. 이게 정말 중요한 포인트입니다.
<aside> 📖 [정리]
밖에서 new해서 Order를 set, set, set 하는게 아니라 생성을 할 때부터 createOrder를 무조건 호출해야합니다. 그래서 관계가 있는 모든 값(member, delivery, status, orderDate)을 넣어서 생성 메서드에서 완결을 합니다.
주문 생성에 대한 복잡한 비즈니스 로직을 다 응집해 놓는 것입니다.
그래서 주문 생성에 관련된 로직은 createOrder에서만 고치면 됩니다.
</aside>
주문 취소
취소 버튼을 누르면 수량이 올라가야 합니다.
this 생략
for (OrderItem orderItem : this.orderItems) {
}
this를 잘 안씁니다. 어차피 IDE가 색칠을 해줍니다. 그래서 굳이 쓸 의미가 없습니다.
그래서 로직을 보면서 자기거라고 강조해야할 때나 이름이 똑같을 때 외에는 잘 안씁니다.
OrderItem에도 다 cancel을 해줘야합니다.
한 번 주문할 때 상품을 2번 주문할 수 있습니다. 그럼 OrderItem이 2개 생기니까 2개 각각 cancel을 날려줘야합니다.
<aside> 📖 이미 배송된 상품은 주문하지 못한다는 비즈니스 로직에 대한 체크 로직이 엔티티 안에 있습니다.
그 다음에 상태를 바꿔주고, 루프를 돌면서 OrderItem에 대해서 cancel을 치면 Item의 재고를 원복시켜줍니다.
</aside>