기술 글
아임포트 결제 연동하기
투데이크 프로젝트를 진행하며 구현했던 결제 방법입니다. 아임포트 가이드...
- 표시 날짜
- 읽는 시간
- 1 min read
- Tags
투데이크 프로젝트를 진행하며 구현했던 결제 방법입니다.
아임포트 가이드 문서 를 참고해 구현했습니다.
모바일 웹 환경(framework7)에서 PG사로 KG이니시스, LG U+, NHN KCP, 나이스정보통신, JTNet, KICC를 사용하는 경우에만 동작합니다. 다른 환경에서는 결제 호출 시 callback 함수로 처리해야합니다
결제 순서는 아래와 같습니다.
- 주문 정보 입력 폼(remote: true)에서 주문 정보 제출
- order#create에서 주문 정보 생성 및 업데이트
- orders/create.js.erb에서 결제창 호출
- 결제 후 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를 사용해 결제정보를 요청해도 상관없습니다.
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
이상입니다...