결제 또한 프론트엔드의 구현기능이고 굉장히 도움이 되는 기능이다.
꼭 알아두긔

결제 프로세스 구조

결제에는 일반결제, 정기결제가 있다

일반 결제 : 그냥 한번 내기
-> 카드 결제, 계좌이체, 무통장 입금, 모바일페이

정기 결제 : 구독서비스 같은거 (넷플릭스)
-> 역시 다양한 결제과정이있음

--> 결제라는 기능을 붙인다고 모든 기능이 넣어지는 것이 아니다. 하나씩 넣어줘야하고 자동으로 되는것이 아님. X팡에서 쓸 때 모든 결제방법이 있지만 그것도 알고보면 하나씩 다 해야되는것임

결제 프로세스의 상세과정

  1. 브라우저에서 결제하기 버튼을 누름

  2. 계약한 PG사(NHN, 나이스페이, KG 이니시스)가 제공한 라이브러리를 사용해야함 한줄의 import가 아니고 굉장히 뭐가 많음, 또 다른 곳으로 쓰고 싶으면 또 다른 곳에 맞춰서 다시 계약해야함 + 보안까지 신경써야함,

-> 이렇게 복잡하니까 대신 PG사와 연결하는 기능을 구현한 API가 생겨남, Rest API요청하듯이 간단하게 이뤄짐 !!!
이런 API를 결제 솔루션이라고 함. 대표적으로는 아임포트가 있다.

물론 이런 솔루션을 사용하면서 월 결제액이 50억을 넘었을때는 솔루션보다는 다이렉트로 PG사와 연결하는 것이 좋지만, 그 이하면 솔루션을 쓰는 것이 훨씬 좋음(유지, 서버, 보안 등등 다양한 문제가 있음)

  1. 그럼 이런 API에 요청하면 됨. 그러면 API에서는 아이디 값을 넘겨줌(예시 : imp_uid), 그럼 이 값을 우리 백엔드에 넘기면 됨(구매, 취소, mutaiton, 결제내역 조회 query) 이런아이디만 있으면 결제정보를 알 수 있음, 무려 부분취소도 가능함, 영수증도 있음

이런 구조고 아임포트에서 이걸 이뤄지기 위해서 몇 가지가 필요하다.

  1. 아임포트에서 PG사와 연동을 위한 가입, 계약서 작성, 1주일정도 걸림

  2. PPT, 테스트용 로그인계정을 만들어서 어디서 어떤 버튼을 눌러서 결제하는지 설명하는걸 PG사에 보내요 PG사에서는 카드사에 보냄

  3. 그럼 카드사들은 하나씩 결제해보고 이걸 통과시켜줄지 안시켜줄지 봄(1,2주정도걸림)
    -> 경매나 도박결제같은 경우는 거절당함
    -> 직접입력방식의 결제(input창에 결제액 입력)
    -> 도메인이 없는 테스트 서비스에서의 결제, 정식오픈이 되어야함

(이미 우리쪽 백엔드는 다 구현했어도 API를 사용하는데도 약 한달정도가 소요된다, 다른 결제기능도 추가하려면 더더더더더 걸리겠지. 그냥 결제 API라고 생각하면 절대금물)

아임포트 해보기

회원가입을 해야한다.

우측 상단 관리자 콘솔로 들어간다

REST API 가 제공되는 것을 볼 수 있다 (결제내역 조회 및 결제취소도 보인다)

(이래서 GRAPHQL 만 하면 안되고 REST API도 알아야한다)

정기결제에 관한 부분도 있다.


무통장 입금에 관한 부분이 있다

쭉 보면 POST는 등록이나 결제, GET의 경우 조회인 것 같다.

시스템 설정으로 가보자

결제설정, 결제 알림(웹훅,notification)설정, 본인인증 서비스, IP보안 설정이 있다.

  • 본인인증 같은 경우는 이렇게 새로운 창에서 다 구성이 되어있는 익숙한 화면을 보여준다.
    (우리가 만드는 것이 아님)

  • 웹훅(Notification)은 중요한 부분임

    무통장입금이라고 생각해보자 무통장 입금을 누르면 가상계좌로 얼마를 언제까지 입금하라고 뜰 것이다.
    이용자는 이걸 적어서 ATM이나 온라인 송금을 할 것이다.
    이런 카드사와 결제해서 아임포트 아이디를 가져오고 그걸 백엔드로 저장하는 것과는 과정이 다르다.

이건 아임포트 아이디를 같은 방식으로 가져올 수가 없음
대신 백엔드에 API를 만듬 - 이것이 웹훅노티피케이션인것

밖에서 결제나 취소가 이루어질경우 백엔드로 rest-api를 통해서 아임포트 아이디를 보내는 것
이렇게 디비에 저장할 수 있게 된다.
웹훅(Notification)발송 공통 URL이라고 써있는 부분에 restAPI를 넣으면 된다.

-사용 메뉴얼

사용메뉴얼을 보면 여기도 docs를 가지고있다. github도 가지고있다.

PC/모바일 웹에서 연동하기 부분을 보면

이렇게 .request_pay 부분은 결제,function 부분은 결제성공시 작성하는 내용, mutation으로 백엔드로 imp_uid로 보내는 내용이다.

모바일은 근데 경험해봤듯이 다른 사이트로 넘어가게 된다.
그럼 함수가 다 사라지는거 아닌가? 어차피 페이지가 바뀌면서 function이 날아가니까
-> 결제 성공시 이동할 페이지를 먼저 작성해서 (m_redirect_url)결제가 끝나고 다시 이동될 url주소를 입력하면 결제 성공됐을 때 다시 이동하게 된다.

관리자콘솔 - 사용메뉴얼, 일반결제 연동하기

그냥 단순히 yarn add 보다는 jquery를 통해서 가져오는듯 하다.

직접 해보자

import Head from "next/head";
export default function PaymentPage() {
  const onClickPayment = () => {
    const IMP = window.IMP; // 생략 가능
    IMP.init("imp75660508"); // Example: imp00000000
    IMP.request_pay(
      {
        // param
        pg: "html5_inicis",
        pay_method: "card",
        // merchant_uid: "ORD20180131-0000011",
        name: "노르웨이 회전 의자",
        amount: 64900,
        buyer_email: "gildong@gmail.com",
        buyer_name: "홍길동",
        buyer_tel: "010-4242-4242",
        buyer_addr: "서울특별시 강남구 신사동",
        buyer_postcode: "01181",
      },
      (rsp) => {
        // callback
        if (rsp.success) {
          // 결제 성공시
          console.log(rsp);
        } else {
          // 결제 실패 시
        }
      }
    );
  };

  return (
    <>
      <Head>
        <script
          type="text/javascript"
          src="https://code.jquery.com/jquery-1.12.4.min.js"
        ></script>
        <script
          type="text/javascript"
          src="https://cdn.iamport.kr/js/iamport.payment-1.2.0.js"
        ></script>
      </Head>
      결제금액: <input type="text" />
      <button onClick={onClickPayment}> 결제하기</button>
    </>
  );
}

최신버전은 아임포트 페이지에 링크가 걸려있다(1.2.0) 스크립트 같은 경우 head에 넣으면되는데 next의 head기능을 사용해보자

결제 준비, 요청하기

결제 준비하기와 결제 요청하기 부분을 아까 만들었던 결제 버튼 안에다가 넣으면 된다.

Merchant ID 는 관리자 콘솔 - 가맹점 식별코드를 넣으면 된다.
reqeust_pay 부분의 merchant_uid는 삭제하거나 자신만의 상품 아이디를 넣는데 사용된다.

근데 이런 reading 'init'을 읽는 과정에서 문제가 생긴다면
(아직 pg사 설정이 안되어서 그렇다 )

이렇게 64,900원이 결제된 모습을 볼 수 있다. (테스트모드기 때문에 12시 지나면 자동환불되나 임의로 취소해도된다)
실제로 핸드폰에 결제, 취소문자까지 온다.

여기서 궁금한점 :
앱에서 결제 한다고 할 때는 어떻게 할까??
마켓에서 다이렉트로 결제하는 것을 본 적이 있을것이다. 이렇게 마켓으로 다이렉트로 연결해도되고
아니면 react의 iframe을 이용해서 앱 내에서 웹페이지를 여는 방식을 응용해도된다. 웹페이지는 결제 창을 의미함
이렇게 하면 웹에서 만든 결제시스템을 앱 내에서 다시 사용 할 수 있고 수수료가 높은 마켓보다 더 저렴할 수 있다.

관리자 도구로 보면 아임포트에 이런 결제 정보가 넘어갔다는 것을 알 수 있다.
우리는 이것을 다시 우리 백엔드로 넘겨줘야 이 정보를 이용할 수 있다.

playground docs를 보면 구매하기, 충전하기에 관한 부분이 있다.

이로써 포인트로 물건을 구매하면 백엔드를 통해서 포인트가 조정된다.
충전부분이 아임포트를 이용해서 충전하고 그 아이디 값을 받아서 백엔드에 저장하고 그걸 통해서 포인트를 조정한다.

즉 백엔드에서도 이걸 활용하고 이런 방식으로는 물건 구매는 아임포트를 활용하지 않는다.

마켓을 만들 때 충전하기를 만들고
아임포트를 통해 충전이 완료되면
createPointTransactionOfLoading 뮤테이션 실행하기 , 인자는 ImpUid이다.

이걸 통해서 백엔드를 통해서 포인트를 충전시킨다.

이후 구매하기를 만들고 구매api를 넣고 버튼을 누르면

createPointTransactionOfBuyingAndSelling 이 실행되면서 useritemID에 맞는 아이템으로 사게되고

fetchUserLoggedIn을 통해서 포인트가 변화된 것 또한 확인할 수 있다.

모바일결제 주의사항

(앱 아니고 모바일 웹)

(개발자도구에서 모바일 버전을 실행시켜볼 수 있음)
아예 새로운 페이지에서 열리는데 이러면 결제가 되고도 실행이 안된다 왜냐하면 새로운 페이지기 때문에 아까 작성한 기능이 있는 곳이 아니기 때문

아까 언급했던 리다이렉트 기능을 이용해서 결제가 끝나면 다시 전 페이지로
(m_redirect_url)
돌아가서 기능이 구현되게 하고 웹훕 노티피케이션을 활용해서 백엔드에도 알림을 줘야한다.

+ 시간이벤트 주의사항

결제된 날짜나 취소된 시간을 넣고 싶을 수 있다
방법은 프론트엔드에서 new Date()를 사용해서 mutation으로 보내거나
백엔드에서 mutation을 받았을 때 newDate()를 만들 수 있다.

하지만 프론트엔드에서는 이런 방식을 가급적 사용하지 않는게 좋은데
왜냐면 프런트엔드의 날짜같은건 변조가 되었을 수도 있기 때문인데 변조가 되어도 백엔드에서는 구별할 수 없기때문

해외서비스에 문제가 있을 수 있음
(국내만 서비스할일은 별로 없을것임)

시간대가 다른 문제가 생김

그럼 백엔드에서는 세계 표준 시간 UTC로 저장한뒤에

한국에서 열때는 UTC를 가져오고, 한국에서 맞는 시간으로 바꿔서 보여줌
미국에서 열때도 UTC를 가져오고, 미국에서 맞는 시간으로 바꿔서 보여줌
일본에서 열때도 UTC를 가져오고, 한국에서 맞는 시간으로 바꿔서 보여줌

결론적으로 시간은 세계 표준시간에 맞게 저장 후 해당하는 환경(12시, 24)시, 장소(미국,한국, 일본 등등)에 맞게 변경해서 보여줌

이건 또 어떻게 실현하느냐?
관련 라이브러리가 있음.

moment.js


13,483,802이 넘는 이용자 수를 보여주기 때문에 이곳에서만 쓰기보다는 사실 많은 곳에서 공통적으로 쓰기 때문에 이런 자주쓰이는 라이브러리들은 사용법을 공부해두는 것이 좋다.

+++ 보너스
특정시간에 버튼을 누르지 않고 함수를 실행시키고 싶다면?
-> 크론탭(리눅스에 자동으로 설치된 프로그램이다)을 활용하면 된다.

요약
결제 프로세스 및 구현에 있어서의 과정, 결제 실제로 실현해보기, 그 과정에서의 주의사항, 모바일 주의사항

profile
개발자 새싹🌱 The only constant is change.

0개의 댓글