Project 2 - KREAM 7

Junjii·2023년 9월 4일
0

Project2

목록 보기
7/7

<Project 2 - KREAM >
기간 : 2주
팀원 : 프론트 2명 (PM) / 백엔드 4명
필수 구현 사항 : 로그인, 회원가입, 리스트페이지, 상품 디테일페이지 ,주문, 결제

< 채결에 대한 이해 과정 >
처음에는 채결에 대해 실시간으로 상품을 찾는 api 를 구현해야하나...? 라고 생각했다. 그렇게 검색을 해보고 고민을 해보다가 모식도를 다시 그려보면서 알게 되었다. 먼저 채결이 된다는 것은 조건이 맞는 상품이 있다는 것이다.

그러면 어떠한 조건인가? - bidProductSizeId 와 userId , price 가 맞아야한다.

맞는 조건이 있다면? orders에 주문 완료를 작성한다.

정리를 해보니 길이 보이기 시작했다. 그런데 조건이 맞으면 bid에 있는 내용을 삭제해야하나? 라고 생각이 들었는데 그러면 각각 고객 입장에서 언제 얼마에 거래를 했는지 나중에 알고자 한다면 조회를 못하는 것이다.
또 한번 다시 고민하다가 bid 의 column 중에 status를 활용해야겠다라고 생각이 들었다.

정리해보자면
1) bid에 맞는 조건의 상품을 찾는다.
조건에 맞는 상품이 있다면?
2) bid 의 status를 "입찰완료" 로 수정한다.
3) 해당 정보를 가지고 orders 를 작성한다.

조건에 맞는 상품이 없다면?
2) bid의 status 를 "판매 / 구매 입찰" 로 하여 작성한다.

이렇게 정리한 흐름이다.

고민이 해결되면 또 고민이 생긴다.
이제는 멘토님께서 피드백을 주셨는데 만약에 다른 고객이 해당 상품을 빠르게 구매버튼을 눌러서 재고를 채결할 수도 있을텐데 어떻게 관리할 것인가? 라고 하셨다.

그러면 즉시 구매 계속 버튼을 누르는 순간 해당 상품을 홀딩 시켜놔야 다른 고객이 해당 상품을 구매하지 못하게 만드는 것이였다.
그러면 어떻게 홀딩을 시키는가?
이것 또한 status 를 활용해야겠다고 생각이 들었다.

나의 흐름에는 해당 상품 서칭을 여러번 한다. 그때마다 status 상태를 조건으로 걸어서 서치를 한다면 해결이 되는 것이다.

const insertBidSellWaiting = async (sellerId, productId, size, price) => {
  let status = bidStatusEnum.BUY_CONFIRMED;
  const bidProductSizeId = await searchBidProductSize(productId, size);
  const existingBidBuyInfo = await existingBidBuy(
    status,
    bidProductSizeId,
    price
  );
  status = bidStatusEnum.WAIT_CONFIRMED;
  let bidSellId;
  if (existingBidBuyInfo) {
    const bidBuyId = existingBidBuyInfo.id;
    const modifyAndInsertBidSell = await bidSellDao.modifyAndInsertBidSell(
      bidBuyId,
      sellerId,
      bidProductSizeId,
      status,
      price
    );
    bidSellId = modifyAndInsertBidSell.insertId;
  } else if (!existingBidBuyInfo) {
    const insertOnlyBidSell = await bidSellDao.insertOnlyBidSell(
      sellerId,
      bidProductSizeId,
      status,
      price
    );
    bidSellId = insertOnlyBidSell.insertId;
  }
  return bidSellId;
};

먼저 status를 상황별로 재할당을 유연하게 할 수 있게 dao 단에 status만 저장해놓은 파일을 만들고 api안에 status를 상황별로 바꿔 사용한다.
처음에 bid_sells를 서칭할때 "판매입찰"로 서칭을 한다.
이것은 누군가가 판매입찰을 올려놓은 상태이기 때문에 조건만 맞는다면 바로 구매가 가능한 상태임을 확인하는 것이다. 이렇게 생각하니 실시간으로 api를 검색해야하는 생각을 고치게 되었다.
그리고 if문을 사용하여 2가지의 기능으로 처리한다.
있다면 해당 bid_sells를 "거래중"으로 바꿔서 맨처음 서칭할때 서칭이 안되게 홀딩을 시켜버린다.

그 후 결제 창에서 고객이 결제정보를 입력하게 한다.
해당 부분에서 dao 단에 transaction 을 사용하여 결제 정보 입력 중 중단하게 된다면 다시 롤백 시켜버리게 만들었다.

const modifyAndInsertBidSell = async (
  bidBuyId,
  sellerId,
  bidProductSizeId,
  status,
  price
) => {
  const queryRunner = await AppDataSource.createQueryRunner();
  await queryRunner.connect();
  await queryRunner.startTransaction();
  try {
    await queryRunner.query(
      `update 
      bid_buys 
      set status = ?
      where id = ?`,
      [status, bidBuyId]
    );
    const bidSellId = await queryRunner.query(
      `insert into 
      bid_sells
      (seller_id,bid_product_size_id,status,price) 
      values (?,?,?,?)`,
      [sellerId, bidProductSizeId, status, price]
    );
    await queryRunner.commitTransaction();
    return bidSellId;
  } catch {
    await queryRunner.rollbackTransaction();
    const err = new Error('INVALID_DATA');
    err.statusCode = 401;
    throw err;
  } finally {
    await queryRunner.release();
  }
};

const insertOnlyBidSell = async (sellerId, bidProductSizeId, status, price) => {
  const queryRunner = await AppDataSource.createQueryRunner();
  await queryRunner.connect();
  await queryRunner.startTransaction();
  try {
    const bidSellId = await queryRunner.query(
      `insert into 
      bid_sells
      (seller_id,bid_product_size_id,status,price) 
      values (?,?,?,?)`,
      [sellerId, bidProductSizeId, status, price]
    );
    await queryRunner.commitTransaction();
    return bidSellId;
  } catch {
    await queryRunner.rollbackTransaction();
    const err = new Error('INVALID_DATA');
    err.statusCode = 401;
    throw err;
  } finally {
    await queryRunner.release();
  }
};

그 후 결제정보 입력을 마치고 결제하기 버튼을 누른다면?

다시 해당 bid_sells을 서치하는데 이번에는 status 를 "거래중" 으로 홀딩해 놓은 상품을 찾는다.
있다면?
해당 bid_sells의 status를 "입찰완료" 로 바꾸고
bid_buys를 "입찰완료"로 작성하고 두 정보를 모아 orders 를 작성을 하며 주문완료 시켜버린다.

const insertOrder = async (
  status,
  bidBuyId,
  bidSellId,
  point,
  sellerId,
  bidBuyerId,
  bidProductSizeId,
  shortUuid,
  orderPrice
) => {
  const queryRunner = await AppDataSource.createQueryRunner();
  await queryRunner.connect();
  await queryRunner.startTransaction();
  try {
    const modifyBidBuy = await queryRunner.query(
      `update
        bid_buys
        set status = ?
        where id = ?`,
      [status, bidBuyId]
    );
    const modifyBidSell = await queryRunner.query(
      `update 
        bid_sells 
        set status = ?
        where id = ?`,
      [status, bidSellId]
    );
    const modifyUserPoint = await queryRunner.query(
      `update 
      users 
      set point = ?
      where id = ?`,
      [point, sellerId]
    );
    const insertOrder = await queryRunner.query(
      `insert into 
        orders 
        (seller_id, 
          buyer_id, 
          bid_product_size_id,
          order_number,
          price) 
        values 
        (?,?,?,?,?)`,
      [sellerId, bidBuyerId, bidProductSizeId, shortUuid, orderPrice]
    );
    await queryRunner.commitTransaction();
    return insertOrder.insertId;
  } catch (err) {
    await queryRunner.rollbackTransaction();
  } finally {
    await queryRunner.release();
  }
};

여기까지가 내가 고민하고 완성한 채결의 내용이다.
이것들이 잘 수행이 되고나면 화면 디테일 페이지의 최근 거래 목록에 반영이 되고 목록의 금액이 수정이 된다.

정말 고민의 고민을 수도 없이 했던 과정이였고 그래도 결국에 기능은 돌아가게 한 것이 너무 만족스럽지만 한 편으로는 더 효율적이고 좋은 방법이 분명 있을 것이지만 나의 지식의 한계로 리펙토링을 더 하지 못한게 너무 아쉬웠다.
위코드 수료 후 다시 한번 고민하며 리펙토링을 해봐야겠다!

0개의 댓글