🙄주문, 주문상품 엔티티 개발
@Entity
@Table(name = "orders")
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
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<>();
private LocalDateTime orderDate;
@Enumerated(value = EnumType.STRING)
private OrderStatus status;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "delivery_id")
private Delivery delivery;
public void setMember(Member member) {
this.member = member;
member.getOrders().add(this);
}
public void addOrderItem(OrderItem orderItem) {
orderItem.setOrder(this);
orderItems.add(orderItem);
}
public void setDelivery(Delivery delivery) {
this.delivery = delivery;
delivery.setOrder(this);
}
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.getOrderPrice() * orderItem.getCount();
}
return totalPrice;
}
}
@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class OrderItem {
@Id
@GeneratedValue
@Column(name = "orderItem_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 void cancel() {
getItem().addStock(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 int getTotalPrice() {
return getOrderPrice() * getCount();
}
}
🙄주문 리포지토리 개발
@Repository
@RequiredArgsConstructor
public class OrderRepository {
private final EntityManager em;
private final OrderRepository orderRepository;
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();
}
@Transactional
public void cancelOrder(Long orderId) {
Order findOrder = orderRepository.findOne(orderId);
findOrder.cancel();
}
}
🙄주문 기능 테스트
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
class OrderServiceTest {
@Autowired private EntityManager em;
@Autowired private OrderService orderService;
@Autowired
private OrderRepository orderRepository;
@Test
public void 상품주문() throws Exception {
Member member = new Member();
member.setName("회원");
member.setAddress(new Address("서울", "강가", "123-123"));
em.persist(member);
Book book = new Book();
book.setName("JPA");
book.setPrice(10000);
book.setStockQuantity(10);
em.persist(book);
int orderCount = 2;
Long orderId = orderService.order(member.getId(), book.getId(), orderCount);
Order getOrder = orderRepository.findOne(orderId);
assertEquals("상품 주문시 상태는 ORDER", OrderStatus.ORDER, getOrder.getStatus());
assertEquals("주문한 상품 종류 수가 정확해야 한다.", getOrder.getOrderItems().size(), 1);
assertEquals("주문 가격은 가격 X 수량이다.", getOrder.getTotalPrice(), book.getPrice() * orderCount);
assertEquals("주문 수량만큼 재고가 줄어야 한다.", book.getStockQuantity(), 8);
}
@Test
public void 주문취소() throws Exception {
Member member = new Member();
member.setName("회원");
member.setAddress(new Address("서울", "강가", "123-123"));
em.persist(member);
Book book = new Book();
book.setName("JPA");
book.setPrice(10000);
book.setStockQuantity(10);
em.persist(book);
int orderCount = 2;
Long orderId = orderService.order(member.getId(), book.getId(), orderCount);
orderService.cancelOrder(orderId);
Order order = orderRepository.findOne(orderId);
assertEquals("주문 취소시 상태는 CANCEL", OrderStatus.CANCEL, order.getStatus());
assertEquals("주문이 취소된 상품은 그만큼 재고가 증가해야 한다.", 10, book.getStockQuantity());
}
@Test
public void 상품주문_재고수량초과() throws Exception {
Member member = new Member();
member.setName("회원");
member.setAddress(new Address("서울", "강가", "123-123"));
em.persist(member);
Book book = new Book();
book.setName("JPA");
book.setPrice(10000);
book.setStockQuantity(10);
em.persist(book);
int orderCount = 11;
Assertions.assertThrows(NotEnoughStockException.class, () -> orderService.order(member.getId(), book.getId(), orderCount));
}
}
🙄주문 검색 기능 개발
@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);
}
public List<Order> findAll(OrderSearch orderSearch) {
String jpql = "select o from Order as o join o.member as m";
boolean isFirstCondition = true;
if (orderSearch.getOrderStatus() != null) {
if (isFirstCondition) {
jpql += " where";
isFirstCondition = false;
} else {
jpql += " and";
}
jpql += " o.status = :status";
}
if (StringUtils.hasText(orderSearch.getMemberName())) {
if (isFirstCondition) {
jpql += " where";
isFirstCondition = false;
} else {
jpql += "and";
}
jpql += " m.name like :name";
}
TypedQuery<Order> query = em.createQuery(jpql, Order.class)
.setMaxResults(1000);
if (orderSearch.getOrderStatus() != null) {
query = query.setParameter("status", orderSearch.getOrderStatus());
}
if (orderSearch.getMemberName() != null) {
query = query.setParameter("name", orderSearch.getMemberName());
}
return query.getResultList();
}
}