Robokassa Integration in ActiveMerchant

Original author: Vasiliy Ermolovich
  • Transfer
Note translator - there was already a post about integrating Robokassa and Rails , but I believe that the method provided there will not suit many.

When you have an application written in Ruby on Rails and you plan to add some kind of payment system (for example, PayPal, Moneybookers or Robokassa, as in our case), then the first gem you should think about is Shopify's active_merchant .

ActiveMerchant is a simple abstract payment library used and sponsored by Shopify.

Therefore, when I needed to add payments via Robokassa to our project, I opened the list of supported payment systems and was a little disappointed because Robokassa was not included there. A little later, I found a fork that added its support, but it is already deprecated, so some tests crashed ec801d3d4f8 . So I decided to look at this code and fix it, and not write everything from scratch.

In fact, to fix the tests, I just had to fix a small typo 07fb5494134 ( zbs - approx.) Yes, that was easy. Then I decided to add different urls to the test environment and production to the previous solution (Robokassa recommends that you first test your code in the sandbox, and then, when everything works, use it in live mode). You can look at this code here - c2ec85d53cb .

Now it's time to add active_merchant to the project. Add it to the gemfile:

gem 'activemerchant', :require => 'active_merchant'

To use ActionView helpers (such as payment_service_for), you need to put the activemerchant.rb file in the initializers folder:

require 'active_merchant'
require 'active_merchant/billing/integrations/action_view_helper'
ActionView::Base.send(:include, ActiveMerchant::Billing::Integrations::ActionViewHelper)

To use production mode in the initializer, you need to add another line:

ActiveMerchant::Billing::Base.integration_mode = :production # :test for sandbox

The next step is the routes. Robokassa makes a push request to the application when the transaction is completed, so you need to add the following lines to routes.rb:

scope 'robokassa' do
  match 'paid'    => 'robokassa#paid',    :as => :robokassa_paid # to handle Robokassa push request
  match 'success' => 'robokassa#success', :as => :robokassa_success # to handle Robokassa success redirect
  match 'fail'    => 'robokassa#fail',    :as => :robokassa_fail # to handle Robokassa fail redirect
end

Now create a controller to make it work:

class RobokassaController < ApplicationController
  include ActiveMerchant::Billing::Integrations
  skip_before_filter :verify_authenticity_token # skip before filter if you chosen POST request for callbacks
  before_filter :create_notification
  before_filter :find_payment
  # Robokassa call this action after transaction
  def paid
    if @notification.acknowledge # check if it’s genuine Robokassa request
      @payment.approve! # project-specific code
      render :text => @notification.success_response
    else
      head :bad_request
    end
  end
  # Robokassa redirect user to this action if it’s all ok
  def success
    if !@payment.approved? && @notification.acknowledge
      @payment.approve!
    end
    redirect_to @payment, :notice => I18n.t("notice.robokassa.success")
  end
  # Robokassa redirect user to this action if it’s not
  def fail
    redirect_to @payment, :notice => I18n.t("notice.robokassa.fail")
  end
  private
  def create_notification
    @notification = Robokassa::Notification.new(request.raw_post, :secret => AppConfig.robokassa_secret)
  end
  def find_payment
    @payment = Payment.find(@notification.item_id)
  end
end

Finally, add the form to the page:

<%= payment_service_for @payment.id, AppConfig.robokassa_login,
                        :amount =>  @payment.amount,
                        :service => :robokassa,
                        :secret => AppConfig.robokassa_secret do |s| %>
  <%= submit_tag "Submit" %>
<% end %>

That's all! Now, if an object exists @payment, then after submitting the form, a redirect to the Robokassa website will occur, where it will be possible to make a payment for the amount indicated in @payment.amount.

Also popular now: