[23.11.16] TIL

yy·2023년 11월 15일

개발일지

목록 보기
35/122

오늘 할 일

(완료)1. 시험보기
(X_안하는 날이었다.) 2. 코드카타
(완료) 3. lv5 코드에 추가하기 (추가 요구 사항)
(완료) 4. 챌린지팀 회의 (주제, 앞으로의 방향성)


lv5 코드

https://github.com/jeongyy123/third_week_lv5.git

1. **메뉴 주문 API**를 여러개의 메뉴가 주문 가능하도록 수정해주세요.
2. **주문 내역 조회 API**가 특정 주문 상태만 필터링 가능하도록 개선해주세요.
3. 등록된 메뉴가 **판매 가능한 갯수**를 가질 수 있도록 수정해주세요. 
만약, 판매 가능한 갯수가 존재하지 않는다면, 메뉴 상태를 **매진(`SOLD_OUT`)**으로 변경해주세요.
4. 프로젝트의 아키텍처 패턴을 **Layered Architecture Pattern**으로 수정해주세요.

위의 요구 사항 중 1-3번만 우선 적용했다.
메뉴 주문 api에서 추가한 기능은 1. 트랜잭션기능 2.재고관리 3. 재고가 없으면 status 업데이트.

우선 재고관리 기능을 먼저 만들었다. 재고가 있는지 없는지를 확인해야지 트랜잭션 기능이 잘 굴러가는지 확인할 수 있을 것 같았다.

menu테이블에 stock이라는 필드명을 추가해서 처음 메뉴 등록했을 때 stock 갯수를 받도록 했다.업로드중..

menu의 stock 재고보다 작거나 같을때만 주문을 받아 menus의 테이블의 stock을 업데이트를 했다.
await에서 prisma대신 tx를 쓴건 트랜잭션때문에 그렇게 적은 것이다.

//재고관리: 입력받은 quantity보다 재고량이 같거나 많으면 업데이트
        if (quantity <= menu.stock) {
          await tx.menus.update({
            where: { menuId },
            data: { stock: menu.stock - quantity },
          });
        } else {
          throw new Error(
            `menuId ${menu.menuId} 번의 재고 수량을 확인하십시오.`,
          );
          // return res.status(400).json({ message: '재고 수량을 확인하세요.' });
        }

그리고 주문을 하면서 재고가 0이 된 메뉴는 menus의 status가 sold_out을 표시해야해서 주문등록하는 트랜잭션 안에 포함시켰다.

		if (menu.stock - quantity === 0) {
          await tx.menus.update({
            where: { menuId },
            data: { status: 'SOLD_OUT' },
          });
        }

그리고 트랜잭션을 만들었다. 우선 오류를 잡는 try catch문 전에 transaction을 초기화시켜준다. 그 이유는 아래에 catch문에서 transaction을 사용해야하기때문이다. 트랜잭션을 아래와 같이 사용하면 transaction 안에 트랜잭션을 실행한 결과가 담기게 된다.
그럼 try문 안에서 로직을 타면서 만약 오류가 나게되면 catch으로 가게되는데 그 안에 transaction이 만약 (잘못된)내용물이 있다면 롤백하도록 구성하였다. 없다면 트랜잭션의 원자성을 해치지않기때문에 그냥 에러메시지를 띄운다.

/** 여러개 메뉴 주문 **/
router.post('/orders', authMiddleware, async (req, res, next) => {
  let transaction;
  try {
    const orders = req.body;

    const { userId, type } = req.user;

    if (type !== checkType.CUSTOMER) {
      return res
        .status(400)
        .json({ message: '소비자만 사용할 수 있는 API입니다.' });
    }

    //여러개 중 하나라도 오류 뜨면 뒤로 돌려야한다.
    transaction = await prisma.$transaction(async (tx) => {
      for (const order of orders) {
        const validation = await createOrders.validateAsync(order);
        const { menuId, quantity } = validation;

        const menu = await tx.menus.findFirst({
          where: { menuId },
        });

        //재고관리: 입력받은 quantity보다 재고량이 같거나 많으면 업데이트
        if (quantity <= menu.stock) {
          await tx.menus.update({
            where: { menuId },
            data: { stock: menu.stock - quantity },
          });
        } else {
          throw new Error(
            `menuId ${menu.menuId} 번의 재고 수량을 확인하십시오.`,
          );
          // return res.status(400).json({ message: '재고 수량을 확인하세요.' });
        }

        if (menu.stock - quantity === 0) {
          await tx.menus.update({
            where: { menuId },
            data: { status: 'SOLD_OUT' },
          });
        }

        const totalPrice =
          await tx.$queryRaw`SELECT SUM(price * ${quantity}) AS totalPrice FROM Menus WHERE menuId = ${menuId}`;

        await tx.orders.create({
          data: {
            User: {
              connect: {
                userId: Number(userId),
              },
            },
            Menu: {
              connect: {
                menuId: Number(menuId),
              },
            },
            quantity,
            orderedAt: new Date(),
            totalPrice: totalPrice[0].totalPrice,
          },
        });
      }
    });
    return res.status(200).json({ message: '메뉴 주문이 완료되었습니다.' });
  } catch (error) {
    console.log(error);

    if (transaction) {
      await prisma.$executeRaw`ROLLBACK`;
    }
    next(error);
  }
});

사장님 주문 내역 전체 조회와 별도로 주문 상태에 따라 볼 수 있는 페이지를 만들었다.
기존 사장님 주문 내역 전체 조회 페이지에서 params를 추가해서 구현했다.

const orderStatus = ['PENDING', 'ACCEPTED', 'CANCEL'];
/** (특정상태) 사장님 주문 내역 조회 **/
router.get('/orders/owner/:status', authMiddleware, async (req, res, next) => {
  try {
    const { status } = req.params;
    const { type } = req.user;

    if (type !== checkType.OWNER) {
      return res
        .status(400)
        .json({ message: '사장님만 사용할 수 있는 API입니다.' });
    }

    if (!orderStatus.includes(status.toUpperCase())) {
      return res.status(400).json({
        message: 'PENDING, ACCEPTED, CANCEL 중 상태를 잘 입력해주세요.',
      });
    }

    const orders = await prisma.orders.findMany({
      orderBy: { orderedAt: 'desc' },
      where: { status },
      select: {
        UserId: true,
        User: { select: { nickname: true } },
        Menu: { select: { name: true, price: true } },
        orderId: true,
        quantity: true,
        orderedAt: true,
        totalPrice: true,
        status: true,
      },
    });

    if (!orders) {
      return res.status(400).json({ message: '주문이 존재하지않습니다.' });
    }
    return res.status(200).json({ data: orders });
  } catch (error) {
    next(error);
  }
});

profile
시간이 걸릴 뿐 내가 못할 건 없다.

0개의 댓글