Error (Status 402) (Request req_QPLfwLnwBf2OeY) Your card has insufficient funds - ruby-on-rails-5

Using Rails 5.02, Ruby 2.3, with Stripe gem 'stripe'
My code for the deduction of the charge is as:
begin
# Use Stripe's library to make requests...
charge = Stripe::Charge.create(
:customer => 1234,
:amount => 100, ## i.e 1$
:description => "job payment",
:currency => 'usd',
capture: false,
metadata: {'transaction' => transaction_id},
)
if !charge.review
charge.capture
end
if charge.paid?
#job_payment.invoice_id = transaction_id
#job_payment.transaction_date = Time.now
#job_payment.save
#job.update(job_payment_status: 'paid', expiry_date: Time.now + 30.days)
puts 'Job Payment.....'
job_payment_done_email(#job, #job_payment.invoice_id)
end
rescue Stripe::CardError => e
flash[:error] = "Insufficient funds!"
Rails.logger.info '***********Begin Exception*********'
Rails.logger.info e
Rails.logger.info "Amount = " + #amount.to_s
Rails.logger.info '***********End Exception*********'
rescue Stripe::RateLimitError => e
# Too many requests made to the API too quickly
flash[:error] = "Too many requests made to the API too quickly!"
rescue Stripe::InvalidRequestError => e
# Invalid parameters were supplied to Stripe's API
flash[:error] = "Invalid parameters were supplied to payment gateway!"
rescue Stripe::AuthenticationError => e
# Authentication with Stripe's API failed
flash[:error] = "Payment authentication problem!"
rescue Stripe::APIConnectionError => e
# Network communication with Stripe failed
flash[:error] = "Payment can not be completed due to the network problem with payment gateway!"
rescue Stripe::StripeError => e
# Display a very generic error to the user, and maybe send
# yourself an email
flash[:error] = "Something went wrong inside server while payment in stripe!"
rescue => e
# Something else happened, completely unrelated to Stripe
flash[:error] = "Something went wrong inside server while payment!"
end
The transaction get stuck by giving the following error of insuficient balance:
(Status 402) (Request req_QPLfwLnwBf2OeY) Your card has insufficient
funds.
Instead if the amount was less than the desired one, then it should have told that at the js pop up itself, but it is giving this error on the server end, But the card has an amount of Rs 1000 in it already.

Related

how to test rails custom validation

I have a custom validation that checks whether a param is valid JSON or not:
def is_valid_json
begin
!!JSON.parse(preferences)
rescue
errors.add(:preferences, "This is not valid JSON")
end
end
In my controller test, I want to make sure that when I send in a bad value, the status code of the response is 422. Here is the spec from my controller:
it 'should return a 422 when validations fail' do
put :update, {:user_preferences => { :email => #email, :preferences => 'badval' } }
expect(response.status).to eq(422)
res = JSON.parse(response.body)
expect(res['error']).to_not be_blank
end
The test fails due to an error:
Failure/Error: put :update, {:user_preferences => { :email => #email, :preferences => 'badval' } }
ActiveRecord::RecordInvalid:
Validation failed: Preferences This is not valid JSON
Controller code:
def update
#user_preference = UserPreference.where(email: params[:user_preferences][:email]).first
authorize! :update, #user_preference
#user_preference.update_attributes!(params[:user_preferences])
render_api_response(#user_preference)
end
When I make the request from the browser, I get a 422 return status code, so is there a reason that I can't get the same result from the test?
The way I see it, update_attributes raises an exception, and you need to catch that. Perhaps you are doing an XHR call with your browser and you code handles that exception code (422) in the front end. For tests to work you should rescue the exception and respond with the relevant status in your render
rescue ActiveRecord::RecordInvalid do
render json: {
error: "Invalid params",
status: 422
},
status: 422
end

IPN handling with paypal-recurring gem in Rails

I have tried to figure out this response back to PayPal for a while and it drives me nuts. Somewhere I need to send it back to stop PayPal from re-sending the IPN. This is my code for the IPN listener so far, how do I send the IPN response? Just doing ppr.valid? creates a VERIFIED response but the IPN messages keep coming so I guess that doesn't count as an IPN response. The valid? line always fails as well as it can't find the email and seller_id, which I also need to put somewhere (this stuff needs documentation). See gem documentation here: https://github.com/fnando/paypal-recurring
def ipn
subscription = Subscription.where(:email => params[:payer_email], :status => "Active").last
if subscription
ppr = PayPal::Recurring::Notification.new(params)
PaymentsNotification.create!(:params => params.to_json, :status => params[:payment_status], :transaction_id => params[:txn_id])
if ppr.valid? && (ppr.express_checkout? || ppr.recurring_payment?)
#business logic
end
end
I ended up with this code:
def ipn
subscription = Subscription.where(:email => params[:payer_email], :status => "Active").last
if subscription
PaymentsNotification.create!(:params => params.to_json.gsub("\"", "'"), :status => params[:payment_status], :transaction_id => params[:txn_id])
ppr = PayPal::Recurring::Notification.new(params)
ppr.response #send back the response to confirm IPN, stops further IPN notifications from being sent out
if ppr.verified? && ppr.completed?
if ppr.express_checkout? || ppr.recurring_payment?
#do stuff here
end
else
#raise response.errors.inspect
end
end
render :nothing => true
end

Rails3 ActiveMerchant Paypal Express Checkout Money Transfer

I am trying to implement PaypalExpressCheckout in my e-commerce application which is built on Rails3.
There will be two roles in the application - Seller and Buyer
Seller can create products and he can add his valid Paypal Email address to get amount on behalf of his sold products.
Buyer able to purchase items and can checkout through Paypal, amount shall transfer to the seller account once the user transaction is successful.
The issue I'm facing here, when buyer checking out, the amount is successfully transfer to the seller account but not deducting same from the buyer account.
I configured API credentials from Paypal sandbox and here are the methods I'm using from ActiveMerchant gem:
From Controller:
def checkout
values = {:ip => request.remote_ip,
:return_url => confirm_paypal_url(#payment),
:cancel_return_url => root_url, :shipping => 0,
:handling => 0, :tax => 0,
:items => get_items(session[:cart])}
response = #payment.setup_purchase(values)
redirect_to #payment.redirect_url_for(response.token)
end
## CALL BACK
def paypal
# session[:product_users] = [{:amount => '100', :email => 'xx#x.com'}]
session[:product_users].each do |user|
#payment = if user.last.nil?
#payment.purchase(:token => params[:token], :payer_id => params[:PayerID], :ip => request.remote_ip)
else
#payment.transfer(user[:amount], user[:email])
end
#payment.save
end
redirect_to billing_thank_you_url(#payment)
end
From Model:
def setup_purchase(options)
gateway.setup_purchase(amount * 100, options)
end
def transfer(amount, receiver)
response = gateway.transfer(amount * 100, receiver, :subject => "Payment from XXX")
end
I'd be grateful if anyone help me on this.
Thank You

Paypal IPN on Rails app not being called

We are using Paypal Adaptive Chained payments to allow contributions on a crowd funding website. I've got everything working as far as making the payment and being returned to the 'return_url' after a successful payment (in the sandbox).
Paypals documentation on testing IPN in the Sandbox is sparse. Perhaps I missed a setting somewhere to enable IPN callbacks?
I would like to be able to use the IPN callback to verify a successful payment. I would like to see the callback JSON so I know which field to capture and compare with. I have found sample code, but the IPN callback doesn't seem to be called in the Sandbox. I've tried to output the params like so (also the puts statement isn't called):
****backers_controller.rb
class BackersController < ApplicationController
include ActiveMerchant::Billing::Integrations
def callback_ipn
puts "callback: ipn"
notify = PaypalAdaptivePayment::Notification.new(request.raw_post)
puts notify.to_yaml
end
def callback_return
puts "callback: return"
#backer = Backer.find(params[:id])
#reward = #project.rewards.find_by_id(#backer.reward_id)
#backer.callback
respond_to do |format|
format.html { render :layout => 'application_proj_back_blog' }
format.json { render json: #backer }
end
end
(The 'callback_return' action is working)
****backer.rb
class Backer < ActiveRecord::Base
include ActionDispatch::Routing::UrlFor
include Rails.application.routes.url_helpers
def purchase
project = Project.find(self.project_id)
default_url_options[:host] = 'localhost:3000'
proj_owner_email = User.find(project.user_id).email
recipients = [{:email => PRIMARY_EMAIL,
:amount => total_pledge,
:primary => true},
{:email => project.paypal_email,
:amount => project_owner_cut,
:primary => false}
]
response = GATEWAY.setup_purchase(
:action_type => "PAY_PRIMARY",
:return_url => callback_return_project_backer_url(project, self),
:cancel_url => callback_cancel_project_backer_url(project, self),
:ipn_notification_url => callback_ipn_project_backer_url(project, self),
:currency_code =>"USD",
:receiver_list => recipients
)
puts response.to_yaml
pay_key = response["payKey"]
pledge_transactions.create!(:action => "purchase", :amount => total_pledge, :response => response)
return response["payKey"]
end
Back in backers_controller.rb, 'def purchase' calls the purchase:
****backers_controller.rb
class BackersController < ApplicationController
def purchase
#backer = Backer.find(params[:id])
#backer.purchase
redirect_to (GATEWAY.redirect_url_for(#backer.purchase))
end
It turns out my authentication was preventing paypal from calling my ipn listener.

Omniauth not updating OAuth token secret on log in

I'm using Omniauth to authenticate users with Twitter and Facebook, going by the "standard" tutorial on the topic (Ryan Bates' screencast, although I'm using Authlogic, not Devise).
I can log in using Twitter, but can't handle authenticated requests back because my Twitter access token secret has been changed on Twitter's end, but is not being updated on my application's end. I've tried deleting the authentication, but it just saves the old one for some reason.
authentications_controller.rb
def create
omniauth = request.env['omniauth.auth']
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
# User is already registered with application
flash[:notice] = 'Signed in successfully.'
sign_in_and_redirect(authentication.user)
elsif current_user
# User is signed in but has not already authenticated with this social network
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => (omniauth['credentials']['token'] rescue nil), :secret => (omniauth['credentials']['secret'] rescue nil))
current_user.apply_omniauth(omniauth)
current_user.save
flash[:notice] = 'Authentication successful.'
redirect_to root_url
else
# User is new to this application
#user = User.new
#user.apply_omniauth(omniauth)
if #user.save
flash[:notice] = 'User created and signed in successfully.'
sign_in_and_redirect(#user)
else
session[:omniauth] = omniauth.except('extra')
redirect_to new_user_path
end
end
end
user.rb
def apply_omniauth(omniauth)
self.email = "foo#example.com"
self.login = omniauth['user_info']['nickname'] if login.blank?
authentications.build(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => omniauth['credentials']['token'], :secret => omniauth['credentials']['secret'])
end
Any ideas? Rails 3.0.6 and Ruby 1.8.7
Steve, you can try the following:
if authentication
# Make sure we have the latest authentication token for user
if omniauth['credentials']['token'] && omniauth['credentials']['token'] != authentication.token
# puts "Found Invalid token"
authentication.update_attribute(:token, omniauth['credentials']['token'])
end
flash[:notice] = "Signed in successfully"
sign_in_and_redirect(:user, authentication.user)
elsif ...
This should basically update the user's access token every time an already registered user tries to login and when a token mismatch occurs.