혼자 고민해보기_ 개발/TIL (Today I Learned)

20230731(월)_ 키오스크 프로젝트 진행

nuri-story 2023. 7. 31. 21:58

금일 달성 항목

1) 키오스크 프로젝트 진행
  : 상품 발주 API 작업 완료, 트랜직션 구현 완료
  : 상품 주문 수정 API 구현 진행


문제 해결 과정 1 - 상품 발주 수정 API

[문제]

상품 발주 수정 API를 구현하는데 트랜직션을 써야하는 상황이었습니다.

 

** 발주 상태 수정 API **
- 발주 상태를 수정(pending, completed)
- Ordered → Pending
   : 조건없이 가능

- Ordered or Pending → Canceled
   : 조건없이 가능
- Pending → Completed
   : 트랜잭션을 적용해 완료됨과 동시에 상품의 amount를 증가
- Completed → Canceled or Pending or Ordered
  : 주문한 수량보다 현재 수량이 적을 경우 현재 수량이 발주 수량보다 적어 발주 취소가 불가능. 에러메세지 반환
  : 가능할경우 트랜잭션을 적용해 상태변경과 동시에 상품의 amount를 감소.

 

 

[시도 및 해결]
1. 새로운 DB를 파고 그 안에 state 상태값을 이전 값과 변경 후의 값으로 담은 다음에 활용하는 용도로 해야하는 줄 알았습니다.
그러나 알고보니 굳이 히스토리 관리를 누군가 알필요가 없는 상황이면 필요가 없었습니다.
또한 이미 상품 수량으로 기록이 있기 때문에 상관이없었습니다 그래서 해당 db를 삭제하고 처음부터 다시 했습니다.

2. 다만들고 res를 받아오지 못하는 오류가 있어서 레포지토리로 res를 끌어오는 대신에 

trow.Error() 를 활용해서 코드를 재 작성하였습니다.

 

order_item.router.js

OrderItemRouter.put(
  '/items/:item_id/order-items/:order_item_id',
  orderItemController.createStateTransaction
);

 


order_item.controller.js

  // 상품 상태 변경
  createStateTransaction = async (req, res) => {
    try {
      const { amount, state } = req.body;
      const { item_id, order_item_id } = req.params;

      const createStateTransaction = await this.orderItemService.createStateTransaction(
        item_id,
        order_item_id,
        amount,
        state
      );
      if (!createStateTransaction)
        return res.status(404).json({ message: '주문 항목을 찾을 수 없습니다' });

      res.status(200).json(createStateTransaction);
    } catch (err) {
      console.error(err.name, ':', err.message);
      return res.status(400).json({ message: `${err.message}` });
    }
  };

 

 

services/order_item.service.js

  // 상품 상태 변경
  createStateTransaction = async (item_id, order_item_id, amount, state) => {
    try {
      const createStateTransaction = await this.orderItemRepository.createStateTransaction(
        item_id,
        order_item_id,
        amount,
        state
      );
      return createStateTransaction;
    } catch (err) {
      console.error(err.message);
      throw new Error(err.message);
    }
  };

 

 

repositories/order_item.repository.js

createStateTransaction = async (item_id, order_item_id, amount, state) => {
    const orderItem = await Order_item.findOne({
      where: { order_item_id },
    });

    const item = await Item.findByPk(orderItem.item_id);

    const currentStock = await Item.findOne({ where: { item_id } });

    if (amount > currentStock.amount && state === 'canceled') {
      throw new Error('현재 수량이 발주 수량보다 적어 발주 취소가 불가능합니다.');
    }

    const t = await sequelize.transaction({
      isolationLevel: Transaction.ISOLATION_LEVELS.READ_COMMITTED,
    });
    try {
      if (orderItem.state === 'ordered' && state === 'pending') {
        await orderItem.update({ state }, { transaction: t });
      } else if (
        (orderItem.state === 'ordered' || orderItem.state === 'pending') &&
        state === 'canceled'
      ) {
        await orderItem.update({ state }, { transaction: t });
      }

      if (orderItem.state === 'pending' && state === 'completed') {
        await item.increment({ amount }, { transaction: t });
        await orderItem.update({ state }, { transaction: t });
      }

      if (
        orderItem.state === 'completed' &&
        (state === 'canceled' || state === 'pending' || state === 'ordered')
      ) {
        await item.increment({ amount: -amount }, { transaction: t });
        await orderItem.update({ state }, { transaction: t });
      }

      await orderItem.save({ transaction: t });

      await t.commit();
      return { message: '상태 변경에 성공하였습니다' };
    } catch (err) {
      console.log(err);
      if (t) await t.rollback();
      throw new Error(err.message);
    }

 

[알게된 점]

해결하는데 2일이 꼬박 걸렸지만 해냈습니다 ㅇㅂㅇ!! 앞으로 트랜직션을 구현할 수 있을 것 같습니다.