본문으로 건너뛰기

기술 글

아임포트 결제 연동하기

투데이크 프로젝트를 진행하며 구현했던 결제 방법입니다. 아임포트 가이드...

표시 날짜
읽는 시간
1 min read
Tags

투데이크 프로젝트를 진행하며 구현했던 결제 방법입니다.

아임포트 가이드 문서 를 참고해 구현했습니다.

모바일 웹 환경(framework7)에서 PG사로 KG이니시스, LG U+, NHN KCP, 나이스정보통신, JTNet, KICC를 사용하는 경우에만 동작합니다. 다른 환경에서는 결제 호출 시 callback 함수로 처리해야합니다

결제 순서는 아래와 같습니다.

  1. 주문 정보 입력 폼(remote: true)에서 주문 정보 제출
  2. order#create에서 주문 정보 생성 및 업데이트
  3. orders/create.js.erb에서 결제창 호출
  4. 결제 후 order#complete 액션에서 결제 정보 검증 및 데이터 동기화

routes.rb

resources :orders do
  collection do
    get :complete
    ...
  end
end

아임포트 라이브러리 추가하기

application.html.erb

<!-- jQuery 1.0이상이 이미 추가되어 있어야 합니다. -->
<script type="text/javascript" src="https://cdn.iamport.kr/js/iamport.payment-1.1.5.js"></script>

orders/new.html.erb

<script>
  var IMP = window.IMP;
  IMP.init("imp00000000");
</script>

init()함수 인자로 아임포트 관리자 대시보드에서 확인한 가맹점 식별번호를 넘겨줍니다.

결제하기

orders/new.html.erb

<%= form_for @order, url: orders_path, remote: true do |f| %>
...
...
<% end %>

order_controller.rb

def create
  # 주문을 생성합니다.
  @order = current_user.orders.find_or_create_by(state: :wait)
  @order.update!(order_params)
end

create.js.erb

// 결제창을 띄우는 코드입니다.
IMP.request_pay({
    pg: 'inicis',
    pay_method: 'card',
    merchant_uid: '주문_고유_번호',
    name: '주문명:<%= @order.id %>_<%= @order.user.email %>_<%= @order.item.title %>',
    amount: <%= @order.price %>,
    buyer_email: '<%= @order.user.email %>',
    buyer_name: '<%= @order.user.name %>',
    buyer_tel: '<%= @order.user.phone %>',
    m_redirect_url: '<%= Rails.env.development? ? "<개발환경IP주소>" : "<배포URL>" %><%= complete_orders_path %>'
});

자세한 파라미터 정보 확인

PC환경과 달리 모바일 웹 환경에서는 각 PG사의 웹사이트로 리다이렉트되고 callback이 메모리에서 해제되기 때문에 callback을 이용해 결제 완료 처리하던 방식과는 다르게 구현해야 했습니다.

결제 완료 후 m_redirect_url에 지정된 url로 리다이렉트 됩니다. 이때 imp_uid와 merchant_uid가 쿼리스트링으로 넘어오며 이를 이용해 결제 검증을 구현합니다.

imp_uid는 결제 고유 정보로 아임포트 서버에서 imp_uid로 결제 정보를 조회할 수 있습니다.

저는 iamport 젬을 이용해 결제 검증에 사용했습니다. 직접 아임포트 REST API를 사용해 결제정보를 요청해도 상관없습니다.

Gem

아임포트 REST API

Gemfile

gem 'httparty'
gem 'iamport'

config/initialize/iamport.rb

Iamport.configure do |config|
  # iamport api_key로 변경, 아임포트 대시보드에서 확인 가능합니다.
  config.api_key = "REST_API_KEY"
  config.api_secret = "REST_API_SECRET"
end

order_controller.rb

def complete
  imp_uid = params[:imp_uid]
  merchant_uid =  params[:merchant_uid]

  # Iamport 젬을 이용해 아임포트 서버에 저장된 결제 정보 요청
  res = Iamport.payment(imp_uid)

  if res['code'] == -1
    # 결제 실패 시 처리할 로직
    redirect_to root_path, notice: "결제에 실패했습니다"
    return
  end

  price = res['response']['amount']
  status = res['response']['status']

  # 저는 사용자 주문에서 wait인 경우가 한개 뿐이라 이렇게 주문을 찾았지만
  # 주문 생성시 데이터베이스에 merchant_uid를 저장한다면
  # params[:merchant_uid]를 통해 주문을 찾을 수 있습니다
  order = current_user.orders.find_by(state: :wait)

  # 아임포트 서버에 저장된 가격과 데이터베이스에 저장된 가격이 일치하면 결제 성공
  # 아임포트서버에는 결제완료로 되어있지만 가격 정보 불일치 -> 결제정보 위조일 경우
  # 결제 검증 실패 시 주문 취소 처리 및 아임포트 서버에 결제 취소 요청
  if status == 'paid' && price == order.price
    order.complete!
    msg = '결제에 성공했습니다'
  else
    order.cancel! if order.present?
    body = {
      imp_uid: imp_uid,
      merchant_uid: "MERCHANT_UID",
    }

    Iamport.cancel(body)
    msg = '결제에 실패했습니다'
  end

  redirect_to root_path, notice: msg
end

이상입니다...