IPN handling with paypal-recurring gem in Rails - ruby-on-rails-3

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

Related

Error (Status 402) (Request req_QPLfwLnwBf2OeY) Your card has insufficient funds

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.

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.

Rspec Rails 3.1 Integration test. How to send post request headers for mobile, http basic authentication and JSON?

I have an RSPEC integration test for a Rails 3.1 app that needs to test an api for a mobile client by issuing a POST request with JSON params and a mobile header that needs to use http_basic authentication
As the request object is not available in an integration test I'm kinda stuck
This is the code I have so far
it "successfully posts scores" do
# request.env["HTTP_ACCEPT"] = "application/json" #This causes an error as request is nly available in controller tests
post "scores", :score => {:mobile_user_id => #mobile_user.id, :points => 50, :time_taken => 7275}.to_json,
:format => :json, :user_agent => 'Mobile', 'HTTP_AUTHORIZATION' => get_basic_auth
end
The post request does not recognise that I am using http basic authentication but unsure if the format for json is correct. Any help appreciated
get_basic_auth is a helper me4thod that looks like this
def get_basic_auth
user = 'user'
pw = 'secret'
ActionController::HttpAuthentication::Basic.encode_credentials user, pw
end
I use a before_filter in my controllers that checks for mobile and http_basic_authentication that looks like this
def authorize
logger.debug("#### Authorizing request #{request.inspect}")
if mobile_device?
authenticate_or_request_with_http_basic do |username, password|
username == Mobile::Application.config.mobile_login_name && Mobile::Application.config.mobile_password
end
else
unless current_user
redirect_to login_url, :notice => "Please log in"
end
end
end
I get a redirect to login so obviously the mobile header is not being accepted so I have no idea really if any of the other headers are working
UPDATE
Figured it out
post("scores", {:score => {:mobile_user_id => #mobile_user.id, :points => 50, :time_taken => 7275}}.to_json,
{"HTTP_USER_AGENT" => "Mobile", 'HTTP_AUTHORIZATION' => get_basic_auth, 'HTTP_CONTENT_TYPE' => "application/json"})
Does the trick nicely
I figured out what I needed to do
post("scores", {:score => {:mobile_user_id => #mobile_user.id, :points => 50, :time_taken => 7275}}.to_json,
{"HTTP_USER_AGENT" => "Mobile", 'HTTP_AUTHORIZATION' => get_basic_auth, 'HTTP_CONTENT_TYPE' => "application/json"}
Obviously the "mobile" user agent is not needed to test normal json requests.
Hope that helps someone

Toggling working in the controller but not in the Spec: Rails 3 + Rspec

Given this confirm method:
if (#bucket.confirmation_code == #code)
puts "OLAAA"
#bucket.toggle!(:confirmation)
#bucket.save
flash[:success] = "Successfully confirmed bucket."
redirect_to bucket_url(#bucket)
else
flash[:fail] = "Error confirming bucket."
redirect_to bucket_url(#bucket)
end
I have a spec testing if it toggles the confirmation attribute but even though in the controller, everything seems to be working (confirmation == true), the test is failing (confirmation == false instead of true).
The test is as:
it "should have a confirmation URL" do
#attr3 = {:email => "test#testing.com", :confirmation_code => "ola123"}
post :create, :bucket => #attr3
#bucket = Bucket.last
post :confirm, :id => #bucket.id, :code => "ola123"
#bucket.save
#bucket.confirmation.should == true
end
Instead of #bucket.save, which is unnecessary since your controller method will already do this, do #bucket.reload, which will re-query the database for the current values (which changed since you first assigned #bucket = Bucket.last). Then your confirmation value should return true.