最近、友人がRailsのキャッシュデスクとの統合コードを持っているかどうかを尋ねました。 私は他の誰かがこのコードを必要とするかもしれないと共有し、考えたので、ここでこのトピックを作成することにしました。
コントローラー
コントローラーから始めましょう。ここでは4つのメソッドが必要です。
- pay-これは、「pay」ボタンが配置されるページです
- resultは、キャッシュデスクを呼び出して操作の結果を報告するコールバックであり、「OK」+「InvId」を返すことでそれを受け入れるか、トランザクション結果が適切でない場合は「FAIL」を返す必要があります。
- success-支払いが成功した場合に、キャッシュデスクがユーザーをリダイレクトするページ
- fail-何かが間違っている場合にチケットオフィスがユーザーをリダイレクトするページ。
class PaymentsController < ApplicationController def pay # , : @order = Order.find(params[:id]) unless @order.blank? && @order.payment.blank? # @pay_desc = Hash.new @pay_desc['mrh_url'] = Payment::MERCHANT_URL @pay_desc['mrh_login'] = Payment::MERCHANT_LOGIN @pay_desc['mrh_pass1'] = Payment::MERCHANT_PASS_1 @pay_desc['inv_id'] = 0 @pay_desc['inv_desc'] = @order.payment.desc @pay_desc['out_summ'] = @order.payment.price.to_s @pay_desc['shp_item'] = @order.id @pay_desc['in_curr'] = "WMRM" @pay_desc['culture'] = "ru" @pay_desc['encoding'] = "utf-8" # @pay_desc['crc'] = Payment.get_hash(@pay_desc['mrh_login'], @pay_desc['out_summ'], @pay_desc['inv_id'], @pay_desc['mrh_pass1'], "Shp_item=#{@pay_desc['shp_item']}") end end def result crc = Payment.get_hash(params['OutSum'], params['InvId'], Payment::MERCHANT_PASS_2, "Shp_item=#{params['Shp_item']}") @result = "FAIL" begin # , break if params['SignatureValue'].blank? || crc.casecmp(params['SignatureValue']) != 0 @order = Order.where(:id => params['Shp_item']).first # break if @order.blank? || @order.payment.price != params['OutSum'].to_f # @order.payment.invid = params['InvId'].to_i @order.payment.status = Payment::STATUS_OK @order.payment.save # ... # , @result = "OK#{params['InvId']}" end while false end def success # end def fail # , ... end end
視聴回数
支払方法のフォーム:
<form action="<%= @pay_desc['mrh_url'] %>" method="post"> <input type=hidden name=MrchLogin value="<%= @pay_desc['mrh_login'] %>"> <input type=hidden name=OutSum value="<%= @pay_desc['out_summ'] %>"> <input type=hidden name=InvId value="<%= @pay_desc['inv_id'] %>"> <input type=hidden name=Desc value="<%= @pay_desc['inv_desc'] %>"> <input type=hidden name=SignatureValue value="<%= @pay_desc['crc'] %>"> <input type=hidden name=Shp_item value="<%= @pay_desc['shp_item'] %>"> <input type=hidden name=IncCurrLabel value="<%= @pay_desc['in_curr'] %>"> <input type=hidden name=Culture value="<%= @pay_desc['culture'] %>"> <input type=submit value=''> </form>
ここでは、フォームを生成するためにレールメソッドを使用していないという事実に注意を払う価値があります。これは、まだあまり意味がなく、問題があるかもしれないという意図で行われていますが、実際にはこれまでに遭遇していませんが。 通常、RailsはCSRFから保護するための隠しフィールドを生成しますが、キャッシュデスクに送信するため、必要になることはほとんどありません。
キャップ、抵抗できなかったため、ここに結果メソッドのビューを追加することにしました。
<%= @result %>
成功と失敗は任意です。
モデル
このモデルでは、mondoidを使用しますが、他のORMでリメイクするのは問題ではないと思います。
また、このモデルには、robocash deskのXMLインターフェイスを操作するためのメソッドがあります。 コードを書いている時点では、レールの下に適切なSOAPクライアントが見つからなかったので、スコアをつけて、単にNokogiriで書くことにしました。
require 'open-uri' require 'digest/md5' class Payment include Mongoid::Document include Mongoid::Timestamps field :status, :type => Integer field :invid, :type => Integer field :price, :type => Float field :desc # ... MERCHANT_URL = 'https://merchant.roboxchange.com/Index.aspx' # test interface: http://test.robokassa.ru/Index.aspx SERVICES_URL = 'https://merchant.roboxchange.com/WebService/Service.asmx' #test interface: http://test.robokassa.ru/Webservice/Service.asmx MERCHANT_LOGIN = 'login' MERCHANT_PASS_1 = 'your_pass_1' MERCHANT_PASS_2 = 'your_pass_2' def self.get_currencies(lang = "ru") svc_url = "#{SERVICES_URL}/GetCurrencies?MerchantLogin=#{MERCHANT_LOGIN}&Language=#{lang}" doc = Nokogiri::XML(open(svc_url)) doc.xpath("//xmlns:Group").map {|g|{ 'code' => g['Code'], 'desc' => g['Description'], 'items' => g.xpath('.//xmlns:Currency').map {|c| { 'label' => c['Label'], 'name' => c['Name'] }} }} if doc.xpath("//xmlns:Result/xmlns:Code").text.to_i == 0 end def self.get_payment_methods(lang = "ru") svc_url = "#{SERVICES_URL}/GetPaymentMethods?MerchantLogin=#{MERCHANT_LOGIN}&Language=#{lang}" doc = Nokogiri::XML(open(svc_url)) doc.xpath("//xmlns:Method").map {|g| { 'code' => g['Code'], 'desc' => g['Description'] }} if doc.xpath("//xmlns:Result/xmlns:Code").text.to_i == 0 end def self.get_rates(sum = 1, curr = '', lang="ru") svc_url = "#{SERVICES_URL}/GetRates?MerchantLogin=#{MERCHANT_LOGIN}&IncCurrLabel=#{curr}&OutSum=#{sum}&Language=#{lang}" doc = Nokogiri::XML(open(svc_url)) doc.xpath("//xmlns:Group").map {|g| { 'code' => g['Code'], 'desc' => g['Description'], 'items' => g.xpath('.//xmlns:Currency').map {|c| { 'label' => c['Label'], 'name' => c['Name'], 'rate' => c.xpath('./xmlns:Rate')[0]['IncSum'] }} }} if doc.xpath("//xmlns:Result/xmlns:Code").text.to_i == 0 end def self.operation_state(id) crc = get_hash(MERCHANT_LOGIN, id.to_s, MERCHANT_PASS_2) svc_url = "#{SERVICES_URL}/OpState?MerchantLogin=#{MERCHANT_LOGIN}&InvoiceID=#{id}&Signature=#{crc}&StateCode=80" doc = Nokogiri::XML(open(svc_url)) return nil unless doc.xpath("//xmlns:Result/xmlns:Code").text.to_i == 0 state_desc = { 1 => ' InvoiceID ', 5 => ' , ', 10 => ' , ', 50 => ' , ', 60 => ' ', 80 => ' ', 100 => ' ', } s = doc.xpath("//xmlns:State")[0] code = s.xpath('./xmlns:Code').text.to_i state = { 'code' => code, 'desc' => state_desc[code], 'request_date' => s.xpath('./xmlns:RequestDate').text, 'state_date' => s.xpath('./xmlns:StateDate').text } end def self.get_hash(*s) Digest::MD5.hexdigest(s.join(':')) end end
ルーター
最後に、後でキャッシュデスクに通知するために、ルートを登録することを忘れないでください。
match 'payment/result' => "payments#result" match 'payment/success' => "payments#success" match 'payment/fail' => "payments#fail" match 'payment' => "payments#pay"
ソース
提示されたすべてのコードは、hist