iamport API로 결제 구현하기

김은호·2023년 4월 7일
0

세팅하기

iamport 공식 홈페이지에 가서 가맹점 식별코드를 발급받는다. 그 후 useEffect로 사용하기 위한 라이브러리를 추가한다.

  useEffect(() => {
    const jquery = document.createElement('script');
    jquery.src = 'https://code.jquery.com/jquery-1.12.4.min.js';

    const iamport = document.createElement('script');
    iamport.src = 'https://cdn.iamport.kr/v1/iamport.js';

    document.head.appendChild(jquery);
    document.head.appendChild(iamport);

    return () => {
      document.head.removeChild(jquery);
      document.head.removeChild(iamport);
    };
  }, []);

그 후 TS를 위해 타입을 선언한다.

// /types
// payment type
export interface RequestPayAdditionalParams {
  digital?: boolean;
  vbank_due?: string;
  m_redirect_url?: string;
  app_scheme?: string;
  biz_num?: string;
}

export interface Display {
  card_quota?: number[];
}

export interface RequestPayParams extends RequestPayAdditionalParams {
  pg?: string;
  pay_method: string;
  escrow?: boolean;
  merchant_uid: string;
  name?: string;
  amount: number;
  custom_data?: any;
  tax_free?: number;
  currency?: string;
  language?: string;
  buyer_name?: string;
  buyer_tel: string;
  buyer_email?: string;
  buyer_addr?: string;
  buyer_postcode?: string;
  notice_url?: string | string[];
  display?: Display;
}

// payment callback func type
export interface RequestPayAdditionalResponse {
  apply_num?: string;
  vbank_num?: string;
  vbank_name?: string;
  vbank_holder?: string | null;
  vbank_date?: number;
}

export interface RequestPayResponse extends RequestPayAdditionalResponse {
  success: boolean;
  error_code: string;
  error_msg: string;
  imp_uid: string | null;
  merchant_uid: string;
  pay_method?: string;
  paid_amount?: number;
  status?: string;
  name?: string;
  pg_provider?: string;
  pg_tid?: string;
  buyer_name?: string;
  buyer_email?: string;
  buyer_tel?: string;
  buyer_addr?: string;
  buyer_postcode?: string;
  custom_data?: any;
  paid_at?: number;
  receipt_url?: string;
}

// 컴포넌트
export type RequestPayResponseCallback = (response: RequestPayResponse) => void;

export interface Iamport {
  init: (accountID: string) => void;
  request_pay: (
    params: RequestPayParams,
    callback?: RequestPayResponseCallback,
  ) => void;
}

declare global {
  interface Window {
    IMP?: Iamport;
  }
}

사용하기

import { RequestPayParams, RequestPayResponse } from '@/lib/type';
import {
  Button,
  Modal,
  ModalBody,
  ModalCloseButton,
  ModalContent,
  ModalFooter,
  ModalHeader,
  ModalOverlay,
} from '@chakra-ui/react';
import { useRouter } from 'next/router';
import React, { useEffect } from 'react';

export type RequestPayResponseCallback = (response: RequestPayResponse) => void;

export interface Iamport {
  init: (accountID: string) => void;
  request_pay: (
    params: RequestPayParams,
    callback?: RequestPayResponseCallback,
  ) => void;
}

declare global {
  interface Window {
    IMP?: Iamport;
  }
}

interface IProps {
  isOpen: boolean;
  price: number
}

function PurchaseModal({ isOpen, price }: IProps) {
  const router = useRouter();
  const { IMP } = window;

  useEffect(() => {
    const jquery = document.createElement('script');
    jquery.src = 'https://code.jquery.com/jquery-1.12.4.min.js';

    const iamport = document.createElement('script');
    iamport.src = 'https://cdn.iamport.kr/v1/iamport.js';

    document.head.appendChild(jquery);
    document.head.appendChild(iamport);

    return () => {
      document.head.removeChild(jquery);
      document.head.removeChild(iamport);
    };
  }, []);
  
  const handlePayment = (pgType: 'tosspay' | 'kakaopay' | 'html5_inicis') => {
    IMP?.init('impxxxxxxx'); // 발급받은 가맹점 식별코드 넣기
    IMP?.request_pay(
      {
        pg: pgType, // PG사
        pay_method: 'card', // 결제수단 
        merchant_uid: 'merchant_' + new Date().getTime(), // 주문번호
        name: '결제테스트', // 주문명
        amount: price, // 가격
        buyer_email: user.email, // 구매자 이메일
        buyer_name: user.name, // 구매자 이름
        buyer_tel: '010-1234-5678', // 구매자 전화번호
        buyer_addr: '서울특별시 강남구 삼성동', // 구매자 주소
        buyer_postcode: '123-456', // 구매자 우편번호
      },
      // 결제 완료 후 실행될 콜백함수
      (res: RequestPayResponse) => {
        const { success, error_msg } = res;
        if (success) {
          if (confirm('결제 성공')) {
            router.push('/');
          }
        } else {
          alert(`결제 실패, ${error_msg}`);
        }
      },
    );
  };

  return (
    <>
      <Modal isOpen={isOpen} onClose={onClose}>
        <ModalOverlay />
        <form>
          <ModalContent>
            <ModalHeader>결제 페이지</ModalHeader>
            <ModalCloseButton />
            <ModalFooter justifyContent="space-evenly">
              <Button
                colorScheme="red"
                onClick={() => {
                  handlePayment('html5_inicis');
                }}
              >
                결제하기
              </Button>
              <Button
                backgroundColor="#fae100"
                _hover={{
                  bgColor: 'yellow.400',
                }}
                onClick={() => {
                  handlePayment('kakaopay');
                }}
              >
                카카오페이
              </Button>
              <Button
                bgColor="#0c61eb"
                color="white"
                _hover={{
                  bgColor: '#063a8f',
                }}
                onClick={() => {
                  handlePayment('tosspay');
                }}
              >
                토스페이
              </Button>
            </ModalFooter>
          </ModalContent>
        </form>
      </Modal>
    </>
  );
}

export default PurchaseModal;


실제 결제를 해도 다음날 취소가 되니까 걱정할 필요는 없다.
카카오페이는 test 결제 기능을 제공해서 가상의 돈으로 결제를 테스트할 수 있다!

-끗-

0개의 댓글