Пользователь
0,0
рейтинг
9 июля 2012 в 18:48

Разработка → Интеграция Robokassa в ActiveMerchant перевод

Прим. переводчика — пост про интеграцию Robokassa и Rails уже был, но способ, предоставленый там, полагаю, многих не устроит.

Когда у вас есть приложение, написанное на Ruby on Rails и вы планируете добавить какую-нибудь платежную систему (например PayPal, Moneybookers или Robokassa, как в нашем случае), то первый гем о котором вы должны подумать — это active_merchant от Shopify.

ActiveMerchant — простая абстрактная платежная библиотека используемая и спонсируемая компанией Shopify.

Поэтому когда мне понадобилось добавить платежи через Robokassa в наш проект, я открыл список поддержеваемых платежных систем и был немного разачарован, потому что Robokassa туда не входила. Чуть позже я нашел форк, который добавлял её поддержку, но он уже устарел, поэтому некоторые тесты падали ec801d3d4f8. Таким образом я решил глянуть на этот код и исправить его, а не писать всё с чистого листа.

На самом деле, чтобы починить тесты мне пришлось всего лишь исправить небольшую опечатку 07fb5494134 (збс — прим. пер.). Да, это было несложно. Затем я решил добавить к предыдущему решению различные url для тестового окружения и продакшена (Robokassa рекомендует сначала все-таки потестировать свой код в песочнице, а уже потом, когда все заработает, использовать в живом режиме). Посмотреть на этот код можно тут — c2ec85d53cb.

Теперь настало время добавить active_merchant в проект. Добавьте его в Gemfile:

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

Чтобы использовать хелперы ActionView (типа payment_service_for) необходимо положить файлик activemerchant.rb в папку initializers:

require 'active_merchant'
require 'active_merchant/billing/integrations/action_view_helper'

ActionView::Base.send(:include, ActiveMerchant::Billing::Integrations::ActionViewHelper)

Чтобы использовать режим production в инишиалайзер нужно добавить еще строчку:

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

Следующий шаг — роуты. Robokassa делает push-запрос к приложению, когда транзакция завершена, поэтому необходимо добавить следующие строчки в 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

Теперь создадим контроллер, чтобы всё это заработало::

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

Ну и наконец добавим форму на страницу:

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

Вот и всё! Теперь если существует объект @payment, то после сабмита формы произойдет редирект на сайт Робокассы, где можно будет совершить платеж на сумму, указанную в @payment.amount.
Перевод: Vasiliy Ermolovich
Vasili Kachalko @dreamfall
карма
22,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (8)

  • 0
    Спасибо, отлично:) Как раз собирался отрефакторить интеграцию с робокассой:)
    • 0
      Вот только не очень понял, где происходит проверка контрольных сумм, которые отправляет робокасса во время result/success редиректов? Насколько я понимаю @notification.acknowledge не сможет этого сделать, т.к. у него для этого просто не хватит информации (нужен @payment).
      • 0
        Сможет, так как @payment подгружается через before_filter :find_payment (хм, зачем в примере наплодили два фильтра и, хм, действительно ли нужно ещё раз проверять платёж на завершённость и ещё раз его отмечать его выполненным в методе success)
        • 0
          То, что payment подгружается это да, но кто и где проверяет контрольные суммы? @notification про @payment ведь ничего не знает(насколько я могу судить по коду).

          Насчет @payment.approve! два раза да, вызывает вопросы, но там есть комментарий про project specific code, возможно автору это было для чего-то нужно:) По-идее в paid нужно просто сказать робокассе что все хорошо, а в success перевести платеж в категорию оплаченных.
  • 0
    Х-м… а почему на страничке active_merchant в разделе «Supported Offsite Payment Gateways» есть Робокасса? Или это уже Ваша заслуга? (-:
    • +1
      Я тоже задался вопросом и увидел, что pull request от автора был принят ещё 4 месяца назад. Так что да, их заслуга :-)
      • 0
        Ну это правильнее, чем сделать форк и затихарить его :)
  • 0
    По этой инструкции невозможно без дополнительного изучения робокассы и active_merchant настоить интеграцию.

    1. Непонятно, как и куда передать url'ы: robokassa_paid, robokassa_success, robokassa_fail
    2. Для инструкции, стоило бы убрать этот несчастный @payment или объяснить, что это за объект, что он на самом деле ваш внутренний и никакого отношения к active_merchant не имеет
    3. Ну и не совсем понятно, можно ли сделать amount не параметром к payment_service_for, а формочкой?

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.