在Rails上串接歐付寶,在github上有兩個gem可以用,一個是active_merchant_allpay,另外一個是ez_allpay,兩個我都試過,而且兩個說明的文件都很少,我一開始試用active_merchant_allpay,但是有一些問題解決不了,所以就改用ez_allpay,ez_allpay也確實如他的名字一樣easy,一下子就可以付款了,不過我還卡在其他問題,後面再說。
前置工作
- 當然你要先申請你的歐付寶帳號,要去驗證件還有一堆東西。
- 申請完後看一下他的介接規格說明,程式範例就免了,因為沒有Rails的範例
安裝gem
就如果一般的安裝方式,但是gem install找不到這個gem,所以在gemfile要寫成下面這個樣子,從git去下載。
# Gemfile gem 'ez_allpay', git: 'https://github.com/madeinfree/ez_allpay.git'
設定
# config/initializers/ez_allpay.rb EzAllpay.setup do |allpay| if Rails.env.development? allpay.merchant_id = '2000132' allpay.hash_key = '5294y06JbISpM5x9' allpay.hash_iv = 'v77hoKGq4kWxNNIS' allpay.choose_payment = 'Credit' allpay.return_url = 'http://114.34.97.162/notify' else allpay.merchant_id = ENV['MERCHANT_ID'] allpay.hash_key = ENV['HASH_KEY'] allpay.hash_iv = ENV['HASH_IV'] allpay.choose_payment = 'Credit' allpay.return_url = 'http://www.meetme.cc/notify' end end
這裡要注意的是choose_payment和之後寫在html.erb的ez_allpay_for的ChoosePayment要一樣,不然會有錯誤訊息,還有return_url,用localhost是收不到的,雖然我用了http://www.meetme.cc/notify還是一樣收不到。
# config/routes.rb post 'notify', to: 'bills#notify', as: 'notify'
指定了http://www.meetme.cc/notify這個路徑當然也要在routes.rb把他打開,歐付寶server會用post的方式將付款結果傳過來,接著就是收到之後要怎麼處埋了。
# app/controllers/bills_controller.rb def notify mail(to: 'game0519@gmail.com', subject: "您的付款成功") end
依照在Rails新手村得到的建議是收到一筆就先存一筆,確定有收到了,params再去處埋,不過我把他改成收到之後就發email給我。
新增付款按鈕
# app/views/bills/show.html.erb <%= ez_allpay_for @bill, :setting => { :value => "付款", :css => "btn btn-danger" } do %> <% attr_instead :MerchantTradeNo => :"#{@bill.merchant_trade_no}" %> <% attr_instead :MerchantTradeDate => :"#{@bill.merchant_trade_date}" %> <% attr_instead :PaymentType => "aio" %> <% attr_instead :ChoosePayment => "Credit" %> <% attr_instead :TotalAmount => :"#{@bill.total_amount}" %> <% attr_instead :TradeDesc => :"#{@bill.trade_desc}" %> <% attr_instead :ItemName => :"#{@bill.item_name}" %> <% end %>
這裡重要的是去參考介接文件上所要求的資料格式,將你的資料改成那個格式,才能傳送給歐付寶,還有如果傳送過去之後,在付款完成之前,有任何中斷,原來的訂單號碼就不能再用了,我是重新取號來解決這個問題。
Authenticity Token
接著我靈機一動去看了一下heroku的log檔,發現其實有收到但是因為歐付寶傳來的訊息中沒有authenticity token的關係被擋下來了,所以我在bills controller加了這一行,這樣在notify action 就不會檢查authenticity token。
之後的log記錄大概是像下面這樣。
但是來路不明的東西不能收,所以還是要檢查CheckMacValue,這個mac_value_ok?回傳true,才會對傳過來的東西進行處理
# app/controllers/bills_controller.rb skip_before_action :verify_authenticity_token, only: [:notify]
之後的log記錄大概是像下面這樣。
2014-11-05T08:38:52.291385+00:00 app[web.1]: Started POST "/notify" for 60.199.179.37 at 2014-11-05 08:38:52 +0000
但是來路不明的東西不能收,所以還是要檢查CheckMacValue,這個mac_value_ok?回傳true,才會對傳過來的東西進行處理
# app/controllers/bills_controller.rb def mac_value_ok? #整個的做法是先複製一份params,一份有checkMacValue,一鉁沒有,再把沒有的那一份做檢查碼的加密 #再和他傳回來的checkMacValue比較,如果OK就沒錯了 params_copy = params.dup #Rails.logger.info "PARAMS_COPY #{params_copy}" params_to_go = params_copy.except(:CheckMacValue, :action, :controller) #Rails.logger.info "PARAMS_TO_GO #{params_to_go}" # 把 params 轉成 query string 前必須先依照 hash key 做 sort raw_data = params_to_go.sort.map do |x, y| "#{x}=#{y}" end.join('&') #Rails.logger.info "RAW_DATA #{raw_data}" #加上自己的hash_key與hash_iv hash_raw_data = "HashKey=#{EzAllpay.hash_key}&#{raw_data}&HashIV=#{EzAllpay.hash_iv}" #Rails.logger.info "HASH_RAW_DATA #{hash_raw_data}" #做成url encode並轉成小寫 url_encode_data = (CGI::escape(hash_raw_data)).downcase #Rails.logger.info "URL_ENCODE_DATA #{url_encode_data}" #做MD5加密 my_mac = Digest::MD5.hexdigest(url_encode_data) #Rails.logger.info "MY_MAC #{my_mac}" #他傳來的CheckMacValue值 params_no_mac = params[:CheckMacValue] #Rails.logger.info "PARAMS_NO_MAC #{params_no_mac}" if my_mac == params_no_mac.to_s.downcase return true else return false end end
這樣就搞定了
感謝非常實用
回覆刪除真開心~
回覆刪除Thanks, it saves my time.
回覆刪除I'm so glad it's helpful
刪除非常感謝 Authenticity Token的部分!
回覆刪除謝謝你喔~
刪除