📜 ⬆️ ⬇️

An example of integrating Robokassa with Rails

image
A friend recently asked if I had an integration code with a robocash for Rails, and it so happened that I had one. I shared it and thought that maybe this code might need someone else, so I decided to create this topic here.

Controller


Let's start with the controller, here we need 4 methods:


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 


Views


The form for the pay method:
 <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> 

Here it is worth paying attention to the fact that I do not use rails methods for generating forms, it was done with the intention that there is still not much use from them, and there may be problems, although I haven’t encountered it in general yet. Rails, as a rule, still generates hidden fields to protect against CSRF, but since we send them to the robocassa, it is unlikely that they will need them.
Cap, could not resist and decided to add a view here for the result method:
  <%= @result %> 

success and fail can be any.
')

Model


In this model, I use mondoid, but I think that it’s not a big deal to remake it under any other ORM.
Also in this model are presented methods for working with XML-interfaces of the robocash box. At the time of writing, I did not find adequate SOAP clients for rails, so I scored and decided to write just 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 


Router



And finally, you need to remember to register the routes, then to tell them to the robot box:
  match 'payment/result' => "payments#result" match 'payment/success' => "payments#success" match 'payment/fail' => "payments#fail" match 'payment' => "payments#pay" 


Sources


All the codes presented can be picked up here

Source: https://habr.com/ru/post/128922/


All Articles