Answer the question
In order to leave comments, you need to log in
How to make a payment using Yandex.Money API on Ruby on Rails?
I use RoR and the gem at the link https://github.com/yandex-money/yandex-money-sdk-ruby
I read the doc, section: Payments from bank cards without authorization
There are three steps. After the third one, I have the status ext_auth_required , in the incoming parameter acs_uri I get a link to which I need to send a post (read here ):
You should open the WebView and send the client with a POST request to the acs_uri address with the acs_params parameters. Now I need to somehow redirect to acs_uri using the POST method. How can I do this? The redirect follows a GET request, but you need a POST and a transition to the Yandex.Money page. If you try a simple redirect_to - Yandex gives an error: "Oh, something went wrong." In general, the question is what to do next after the described 3 steps? The instruction ends, but the payment has not yet passed.
require 'yandex_money/api'
require "httparty"
module YandexMoneyHelper
class Payment
include HTTParty
def initialize
end
def account_replenishment(amount, email)
i_id = ym_get_instance_id
r_id = ym_get_request_id(i_id, amount, email)
res = ym_process_payment(i_id, r_id)
end
protected
#Функции для приема платежей с банковских карт
#Получение идентификатора экземпляра приложения на основе
# client_id (выдается при регистрации приложения).
# Получается один раз. Сохраняется в безопасном месте
def ym_get_instance_id
api = YandexMoney::Api.new(client_id: Rails.application.secrets.yandex_money_app_id)
instance_id = api.get_instance_id
end
def ym_get_request_id(inst_id, amount, email)
api = YandexMoney::Api.new(
client_id: Rails.application.secrets.yandex_money_app_id,
instance_id: inst_id
)
response = api.request_external_payment({
pattern_id: "p2p", #Фиксированное значение «p2p».
to: Rails.application.secrets.yandex_money_wallet, #Номер счета для пополнения
#amount: "1.00" Сумма к списанию с банковской карты (на счет поступит эта сумма минус комиссия).
amount_due: amount, #Сумма к зачислению на счет (с карты будет списана эта сумма плюс комиссия).
message: "Пополнение счета от " + email #Комментарий к зачислению, отображается получателю
})
if response.status == "success"
request_id = response.request_id
else
request_id = null
end
end
def ym_process_payment(inst_id, req_id)
api = YandexMoney::Api.new(instance_id: inst_id)
result = api.process_external_payment({
request_id: req_id,
ext_auth_success_uri: "http://example.com/success",
ext_auth_fail_uri: "http://example.com/fail"
})
if result.status == "ext_auth_required"
#Сюда нужно написать редирект методом POST!
end
end
end
end
Answer the question
In order to leave comments, you need to log in
Returned six months later to the problem, finished it, it works, use it, and yes, point out security problems, if any...
gem 'yandex-money-sdk'
gem 'devise' #управление юзерами
get '/кошелек/пополнить', :to=> 'cabinet/balance#replenishment', :as => :replenishment
post '/пополнение/счета', :to=> 'cabinet/balance#payment_process', :as => :payment_process
get '/платеж/не/прошел', :to=> 'cabinet/balance#payment_fail', :as => :payment_fail
get '/платеж/прошел/:secure_code', :to=> 'cabinet/balance#payment_success', :as => :payment_success
require 'yandex_money/api'
module YandexMoneyHelper
class YM
# Класс служит для приема денег на Яндекс кошелек от других пользователей
# Разработчик регистрирует свое приложение в Яндекс.Деньгах,
# получает client_id - идентификатор приложения.
# В течение жизненного цикла приложения client_id не изменяется.
CLIENT_ID = Rails.application.secrets.yandex_money_app_id
# Номер кошелька для приема нлатежей
WALLET_ID = Rails.application.secrets.yandex_money_wallet
attr_reader :successful
attr_reader :error
attr_reader :secure_code
def initialize
puts "=::YANDEX MONEY INITIALIZE::="
puts "CLIENT_ID: #{CLIENT_ID}"
puts "WALLET_ID: #{WALLET_ID}"
#Получение идентификатора экземпляра приложения на основе client_id
@instance_id = YandexMoney::ExternalPayment.get_instance_id(CLIENT_ID)
if @instance_id.status == "success"
@instance_id = @instance_id.instance_id
@ext_pay = YandexMoney::ExternalPayment.new @instance_id
@successful = true
else
@successful = false
@error = @instance_id.error
end
puts "instance_id: #{@instance_id}"
puts "ext_pay: #{@ext_pay}"
end
# Пополнение счета:
def recieve_payment(amount, email)
puts "reciving payment..."
@successful = false
@secure_code = rand 10000000..99999999
puts "secure_code: #{@secure_code}"
response = @ext_pay.request_external_payment({
pattern_id: "p2p", #Фиксированное значение «p2p».
to: WALLET_ID, #Номер счета для пополнения
#amount: "1.00" Сумма к списанию с банковской карты (на счет поступит эта сумма минус комиссия).
amount_due: amount, #Сумма к зачислению на счет (с карты будет списана эта сумма плюс комиссия).
message: "Пополнение счета от #{email}" #Комментарий к зачислению, отображается получателю
})
puts "get request_id: #{response}"
if response.status != "success"
@error = response.error
return
end
@request_id = response.request_id
puts "request_id: #{@request_id}"
puts "process_payment..."
res = @ext_pay.process_external_payment({
request_id: @request_id,
ext_auth_success_uri: Rails.application.routes.url_helpers.payment_success_url(:secure_code => @secure_code),
ext_auth_fail_uri: Rails.application.routes.url_helpers.payment_fail_url
})
@successful = true
puts res
res
rescue => e
@successful = false
@error = e.message
puts "error recieving payment #{e.message}"
{:status => "error", :error => e.message}
end
end
end
class Cabinet::BalanceController < Cabinet::CabinetController
#Пополнение счета
def replenishment
@amount = 100
end
def payment_process
@params[:amount] = {:type => :integer, :in => 1..10000.0}
return if !sanitize_params
@amount = params[:amount]
# Инициализация модуля Яндекс Деньги
ym = YM.new
err = "Ошибка работы с модулем оплаты "
if !ym.successful
err << ym.error if Rails.env.development?
flash[:error] = err
redirect_to replenishment_path
return
end
# Прием платежа на кошелек Яндекс Денег
res = ym.recieve_payment(@amount, "#{current_user.id}: #{current_user.email}")
if !ym.successful
err << ym.error if Rails.env.development?
flash[:error] = err
redirect_to replenishment_path
return
end
# Требуется внешняя аутентификация пользователя
if res.status != "ext_auth_required"
err = "Нет запроса на внешнюю авторизацию"
err << "status: #{res.status} error: #{res.error}" if Rails.env.development?
flash[:error] = err
redirect_to replenishment_path
return
end
# Сохраняем проверочный код платежа в сессии
session[:ym_secure_code] = ym.secure_code
session[:ym_amount] = @amount
# Отсылаем методом POST acs_params:
@acs_params = res.acs_params
@acs_uri = res.acs_uri
render :payment_process
end
def payment_fail
msg = 'Платеж не прошел.'
reason = case params[:reason]
when 'no3ds' then 'Указан неверный код CVV.'
when 'not-enough-funds' then 'Недостаточно средств.'
else
e = Exception.new 'Платеж не прошел.'
ExceptionNotifier.notify_exception(e,
:env => request.env,
:data => {:message => "Ошибка при совершении оплаты: #{params[:reason]}"})
params[:reason]
end
flash[:error] = msg << ' ' << reason
redirect_to replenishment_path
end
def payment_success
#Эти 2 строки измените под свои нужды:
@params[:secure_code] = {:type => :integer, :in => 10000000..99999999}
return if !sanitize_params
secure_code = params[:secure_code]
if !session[:ym_secure_code] || !session[:ym_amount]
flash[:error] = "Платеж не прошел. Ошибка сессии"
redirect_to replenishment_path
return
end
amount = session[:ym_amount].to_i
if session[:ym_secure_code].to_i != secure_code
flash[:error] = "Не верный проверочный код платежа. Платеж не прошел"
else
current_user.with_lock do
@inc = Incoming.create(:user_id => current_user.id, :amount => amount)
current_user.amount += amount
current_user.amount = eval(sprintf("%8.2f",current_user.amount))
current_user.save(validate: false)
end
notify "Баланс пополнен",
"Баланс пополнен на сумму #{amount} #{rub}. Текущий баланс: #{current_user.amount} #{rub}"
UserMailer.new_incoming(@inc.id).deliver if current_user.notify_incomings
flash[:success] = "Платеж прошел"
end
redirect_to replenishment_path
ensure
session[:ym_secure_code] = nil
session[:amount] = nil
end
end
= form_tag(payment_process_path, method: "post") do
= label_tag(:amount, "Сумма без учета комисси банка, #{rub}:")
= number_field_tag :amount, @amount ,in: 1..10000, step: 1
= submit_tag "Пополнить", :class => "button"
%p Подождите, Вы будете перенаправлены на страницу Яндекс Денег
%form#ext_auth_required{:action=>@acs_uri}
%input{:type=>"hidden", :name=>"cps_context_id", :value=> @acs_params["cps_context_id"]}
%input{:type=>"hidden", :name=>"paymentType", :value=> @acs_params["paymentType"]}
:javascript
document.forms["ext_auth_required"].submit();
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question