구현 기능

순서

주문 엔티티

@Entity
@Table(name = "orders")
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 외부에서 매개변수가 없는 생성자를 생성할 수 없다.
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 = CasecadeType.ALL)
	@Joincolum(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);
	}
	
	// 생성 메서드.  Builder패턴으로 대체 가능 
	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;
	}

	// 비즈니스 로직

	// 주문 취소
	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();
		//}
		//return totalPrice;
		
		// Stream 활용 
		return orderItems.stream()
							.mapToInt(OrderItem::getTotalPrice)
							.sum();
	}

}

주문 아이템 엔티티

// 생성 메서드
public static OrderItem createdOrderItem(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();
}

주문 레퍼지토리

@Repository
@RequiredArgsConstructor
public class OrderRepository {
	
	private final EntityManager em;

	public void save(Order order) {
		em.persist(order);
	}

	public Order findOne(Long id) {
		return em.find(Order.class, id);
	}
}

주문 서비스

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OrderService {
	
	private final OrderRepository orderRepository;
	private final MemberRepository memberRepository;
	private final ItemRepository itemRepository;

	// 주문
	@Transactional	
	public Long order(Long memberId, Long itemId, int count) {

		// 엔티티 조회
		Member member = memberRepository.findOne(memberId);
		Item item = itemRepository.findOne(itemId);

		// 배송정보 생성 
		Delivery delivery = new Delivery();
		delivery.setAddress(member.getAddress());

		// 주문상품 생성
		OrderItem orderItem = OrderItem.createOrderItem(item, item.getPrice(), count);

		// 주문 생성
		Order order = Order.createOrder(member, delivery, orderItem);

		// 주문 저장 
		orderRepository.save(order);

		return order.getId(); // cascadeType.ALL 이므로 연관된 모든 것이 저장된다. (단, 명확하게 종속되는 경우에만 사용해야 한다.)

	}

	// 주문 취소 
	@Transactional
	public void cancelOrder(Long orderId) {
		// 주문 엔티티 조회
		Order order = orderRepository.findOne(orderId);
		// 주문 취소
		order.cancel();
	}

	// 주문 검색 
	
}