What is standard practice for Rail's PayPal integration with auto return and dynamic URL data? - ruby-on-rails

I'm finding conflicting information on the standard way to integrate PayPal for what I'm trying to do. This is a somewhat higher level question.
My task: After a non-authenticated user of my app (a 'guest') pays for a booking on PayPal, I need them auto redirected back, where I create a record of this, send appropriate emails, and begin my account creation flow.
I'm leaning towards setting it up as described in this SO answer
It uses the 'paypal-sdk-rest' gem and sends a hash of data to a paypal endpoint like:
values = {
:business => business,
:cmd => '_cart',
:upload => 1,
:return => return_url
}
values.merge!({
"amount_1" => amount,
"item_name_1" => name,
"item_number_1" => id,
"quantity_1" => '1'
})
"https://www.sandbox.paypal.com/cgi-bin/webscr?" + values.to_query
But this appears based on a Railscast implementation from way back in 2008! I have doubts this is still an ideal way of doing it.
Auto return:
1) In the implementation above, I cannot get auto return to work, despite setting it up on my business profile.
2) A static URL is required for the auto return setup on the profile page, but I want to pass dynamic data to the auto return for triggering subsequent actions. Will the return_url specified above override the static URL set on the profile page, is it supposed to (since I can't get it to work I can't test and see)?
3) I've read that auto return won't work if users pay with a CC on PayPal?? If that's true, auto return isn't something I should depend on so I need to find a better implementation.
So maybe I should be using:
1) Instant Payment Notifications (IPNs)
or
2) Payment Data Transfer (PDTs).
Should I be using these, if so, which one? Do they accomplish the same goals?
I really just want the simplest, quickest implementation. PayPal is not the main payment method on my app, and I'm questioning whether I should bother supporting it now, given how dead straightforward other solutions (like Stripe) have been for me by comparison plus a growing task list that needs attention.
Thanks in advance for any guidance offered.

I will recommend you use this gem paypal sdk rest, you can follow all the steps like installing the gem, you run the bundle install command and also the rails g paypal:sdk:install also need to login to developer.paypal.com and create a REST API, because you will need the client_id and client_secret in this section:
PayPal::SDK::REST.set_config(
:mode => "sandbox", # "sandbox" or "live"
:client_id => "EBWKjlELKMYqRNQ6sYvFo64FtaRLRR5BdHEESmha49TM",
:client_secret => "EO422dn3gQLgDbuwqTjzrFgFtaRLRR5BdHEESmha49TM")
Also recommend you to go to the Execute Payment section of the link that i have show you above and click in
Only for Payment with payment_method as "paypal"
then you will see another code so copy and paste it in your app, at the end of that code you will see this
# Create Payment and return status
if #payment.create
# Redirect the user to given approval url
#redirect_url = #payment.links.find{|v| v.method == "REDIRECT" }.href
logger.info "Payment[#{#payment.id}]"
logger.info "Redirect: #{#redirect_url}"
else
logger.error #payment.error.inspect
end
There you cant add this line befose the else statement redirect_to #redirect_url
That line of code will redirect you to Paypal, and when user accept the payment it will redirect you to the return_url you out in this part of the code
# ###Redirect URLs
:redirect_urls => {
:return_url => "http://localhost:3000/payment/execute",
:cancel_url => "http://localhost:3000/" },

You definitely want to use IPN for this. Even with Auto-Return enabled there is no guarantee that the user will make it back to that page, so if you're attempting to handle post-payment processing tasks there you'll run into problems where sometimes the user doesn't make it there so the updates don't occur.
IPN will trigger regardless of whether the user makes it back to your site, so you can be sure it will always run the code as expected. Also, IPN will allow you to correctly handle things like e-checks, where the original IPN would show the payment as pending, and when it clears (or fails) you'd get another IPN with the same transaction ID but an updated status.
IPN also allows you to handle things like refunds, disputes, subscription payments, etc. where a checkout may not have happened, but a transaction of some sort did.

Related

Spree Confirmation Emails

So, I want to set up my Spree store such that confirmation emails are not sent when we create orders in the back-end, since we get customers who place orders outside of our store website, which we would like entered into our Spree database nonetheless. The best way we can think of to do this (if you have another way, by all means chime in) is to disrupt this bit of code in the orders model (you can find it at /core/app/models/spree/order.rb):
def finalize!
# lock all adjustments (coupon promotions, etc.)
all_adjustments.each{|a| a.close}
# update payment and shipment(s) states, and save
updater.update_payment_state
shipments.each do |shipment|
shipment.update!(self)
shipment.finalize!
end
updater.update_shipment_state
save!
updater.run_hooks
touch :completed_at
if paid? #THIS CONDITIONAL IS THE BIT WE ADDED
deliver_order_confirmation_email unless confirmation_delivered?
end
consider_risk
end
Now it's just a matter of testing this. The only kind of payment that can be tested through the GUI is check, and I need to see if this trips with a credit card payment that's been authorized/not authorized/captured/not captured (since Spree's documentation on what qualifies as a payment_state of 'balance_due', 'pending' or 'paid' is pretttty bad). So I've been trying to use factory girl's stuff to make an order like that, and see whether or not a confirmation email has been sent. The only thing I can find for testing confirmation emails, however, involves sending one out, and also I can't find anything that would help me build a factory for an order that specific. Am I missing something?

Refresh page on Heroku with Pusher

I've got an App on Heroku with multiple users, who can bet each other. When a user post a new Bet the Bet should ppear on all other users Home page, so they can take action on it if they want to.
The problem is that I need the Home page to auto refresh when a new Bet is created. I don't want to use the simple HTTP refresh thing, sp I'm thinking on using Pusher, since the App is hosted on Heroku.
But i'm not sure on how to implement this. Could anyone direct me in the right direction - preferably with some code examples.
It seems that all the examples I can find refers to a chat application :)
Checkout Pusher's getting started page. This should be very straight forward.
I assume you have a Bet model. In that case
class Bet < ActiveRecord::Base
after_commit :push_notification, :on => :create, :if => :persisted?
def push_notification
Pusher["bets"].trigger("created", {:id => id, :message => "New bet created"}.to_json)
end
end
On your views you should be doing,
var pusher = new Pusher('abc243231a132b21c321'); // Replace with your app key
var channel = pusher.subscribe('bets');
channel.bind('created', function(data) {
alert('A new bet was created: ' + data.message);
});
Hope you get the idea.
Watch this railscasts, it can be adapted to your application.
http://railscasts.com/episodes/316-private-pub

How to get PayPal's user data and transaction details using paypal_permissions gem?

I need to get Transaction data(date, valued) and user adata.Can I use this gem with some modifications as in this question?
Also, from documentation:
For example, if you plan to query PayPal using getBasicPersonalData and getAdvancedPersonalData, you might generate a merchant model like:
rails generate paypal_permissions merchant email:string first_name:string last_name:string full_name:string country:string payer_id:string street1:string street2:string city:string state:string postal_code_string phone:string birth_date:string
bundle exec
rake db:migrate
I should use Payment Data Transfer (PDT) or TRANSACTION_DETAILS?
It is place,where I will write data, but how I can get data from PayPal ?
Can anyone give me example of code ?
Paypal Adaptive seems to be the way to go on this, here are some documentation I found, hope it helps.
PayPal Adaptive with Rails 3
As usual the PayPal documentation is quite messy and disorganised and thus I thought I’d document how I managed to get PayPal Adaptive working on a marketplace style website.
Warning!
Please use this post as a guide as to how the paypal API connects with your rails app. As Jamesw in the comments below points out, I have not created an adequate way of recording all details of each transaction; something that is no doubt required by law. So perhaps take a look at his comment after reading this. Hopefully you can work out a way to do this
Setup
After some searching I found that the best gem to use right now is paypal_adaptive. ActiveMerchant currently does not support PayPal Adaptive (there is a gem that add’s it in but it does not seem to be maintained.)
# Gemfile
gem 'paypal_adaptive'
How it works
PayPal Adaptive is relatively simple, yet the messy documentation can make it appear daunting. Put simply, this is how I did it:
create paypal_adaptive.yml in your config folder and add your details
create a resource to handle payments – I created a “Purchases” resource (model: Purchase)
when the user clicks a buy button it invokes an action I called “buy” in my PurchasesController
in the “buy” action I firstly create a new Purchase item (Purchase.new) and then add in some details like user_id, product_id, amount etc.
I then invoke a model method called “pay” on my newly created Purchase object (purchase.pay)
in my Purchase model I define the “pay” method and inside it I finally make use of the paypal_adaptive gem by creating its Request class (PaypalAdaptive::Request.new)
I add all the necessary data I want to ship off to PayPal into a hash, and then invoke the Request.pay method, passing in that hash of data. This makes an API call to PayPal, who then replies with a confirmation that this request is successful
If the API call is successful I redirect the user off to PayPal to sign in and confirm the payment
Once the user makes the payment, PayPal sends an IPN (instant payment notification) to your specified IPN address – which I routed to a method in my PurchasesController
In this method, I find the the Purchase object and mark it as paid (purchase.paid = true) and then it’s done!
paypal_adaptive.yml
Go here to create a sandbox account (you will need it). Once logged in go to “Create a preconfigured account”. Create two accounts – one buyer and one seller. If you are using chained or parallel payments (payments that are split amongst more than one person) then create some more accounts.
Click on Api Credentials in the left hand side panel.
Now fill out your paypal_adaptive.yml using those credentials (also use the application_id I provide below – this is the testing application_id provided by www.x.com
development:
environment: "sandbox"
username: "platts_xxxxxxxx_biz_api1.gmail.com"
password: "xxxxxxxxxxxx"
signature: "xxxxxxx"
application_id: "APP-80W284485P519543T"
test:
environment: "sandbox"
username: "platts_xxxxxxxx_biz_api1.gmail.com"
password: "xxxxxxxx"
signature: "xxxxxxxx"
application_id: "APP-80W284485P519543T"
production:
environment: "production"
username: "my_production_username"
password: "my_production_password"
signature: "my_production_signature"
application_id: "my_production_app_id"
Create controller action to handle a buy request
Here you only really need the amount of money to be paid and a list of the emails you want that money to go to. So write your logic to work that out and then make a call to PayPal to setup the purchase.
pay_request = PaypalAdaptive::Request.new
data = {
"returnUrl" => return_url,
"requestEnvelope" => {"errorLanguage" => "en_US"},
"currencyCode" => "USD",
"receiverList" =>
{ "receiver" => [
{"email" => "platts_xxxxxxxx_biz#gmail.com", "amount"=> amount}
]},
"cancelUrl" => cancel_url,
"actionType" => "PAY",
"ipnNotificationUrl" => ipn_url
}
#To do chained payments, just add a primary boolean flag:{“receiver”=> [{"email"=>"PRIMARY", "amount"=>"100.00", "primary" => true}, {"email"=>"OTHER", "amount"=>"75.00", "primary" => false}]}
pay_response = pay_request.pay(data)
if pay_response.success?
# Send user to paypal
redirect_to pay_response.approve_paypal_payment_url
else
puts pay_response.errors.first['message']
redirect_to "/", notice: "Something went wrong. Please contact support."
end
Handling the IPN call
I route my IPN call from PayPal to this method:
def ipn_notification
ipn = PaypalAdaptive::IpnNotification.new
ipn.send_back(request.raw_post)
if ipn.verified?
logger.info "IT WORKED"
else
logger.info "IT DIDNT WORK"
end
render nothing: true
end
Unfortunately if you are on localhost, PayPal can’t send you the IPN, and hence there is a problem with testing this whole process. Ryan Bates’ solution is to use curl to mimic an IPN request. However as you can see in the code above, we make another request to PayPal confirming that the IPN is real. So even with curl sending a fake IPN, we run into problems. I’m going to go hunt for solutions now, but please comment if you have any ideas.

Security concerns with paypal_adaptive gem

I'm using the paypal_adaptive gem with Rails 3.1 to make chained payments. However, after watching http://railscasts.com/episodes/143-paypal-security I've become concerned that I should perhaps add security measures to my payment request. Specifically, I don't want someone to be able to manipulate the prices of the items which I send in my request. Of course, I'm using the standard paypal_adaptive gem request:
pay_request = PaypalAdaptive::Request.new
data = {
"returnUrl" => "http://testserver.com/payments/completed_payment_request",
"requestEnvelope" => {"errorLanguage" => "en_US"},
"currencyCode"=>"USD",
"receiverList"=>{"receiver"=>[{"email"=>"testpp_1261697850_per#nextsprocket.com", "amount"=>"10.00"}]},
"cancelUrl"=>"http://testserver.com/payments/canceled_payment_request",
"actionType"=>"PAY",
"ipnNotificationUrl"=>"http://testserver.com/payments/ipn_notification"
}
pay_response = pay_request.pay(data)
if pay_response.success?
redirect_to pay_response.approve_paypal_payment_url
else
puts pay_response.errors.first['message']
redirect_to failed_payment_url
end
My question is: do I need to encrypt this request to prevent people from changing prices like Ryan does in his rails cast? If so, how can I manipulate this code in order to do so?
IPN validation is definitely good practice. But with regards to encrypting the variables sent across; no, that's not necessary.
The example listed on http://railscasts.com/episodes/143-paypal-security uses Website Payments Standard, in which case it is good to encrypt it.
But Adaptive Payments is a series of server-to-server API calls (the 'Pay' API), from your server to PayPal's. The only part exposed to the buyer is the payKey, a temporary token which the buyer can't manipulate.

Braintree "shopping cart"-like implementation in rails app / finding previous params[:id]?

I'm trying to integrate Braintree into my rails app which already has a deposits controller, model, and view. Right now basically you can specify an amount but I have its status set to "Pending". I would like it so that the user can make such a deposit but then pay for it at any time using Braintree (ala shopping cart). Would I have to create another controller and/or model to do this? (For example all the Braintree examples I've seen want the payment immediately).
Specifically, I've been trying to just work with the 'deposits' I already have. I put the form for the user's name, credit card info, etc. on the deposits "show" page and a confirm button. This seems to work fine if all fields satisfy validation, however it doesn't when there is an error and renders the show page again.
In DepositsController.rb:
def confirm
#deposit = Deposit.find(params[:id])
#result = Braintree::TransparentRedirect.confirm(request.query_string)
if #result.success?
render :action => "confirm"
else
render :action => "show"
end
end
The problem is that :id now is the Braintree transaction ID, rather than the deposits id (primary key). So of course Deposit.find(params[:id]) can't be found.
What is the best way to implement this? Should I store the previous id somehow or get it another way? Should I be using another controller? Thanks!
Short answer is you should be using a Cart model, connected to this Deposit model from what i can gather here. Based on other questions, however, that feeling could change.
So, solely based on what you wrote above:
If we follow a RESTful approach, you should be creating a Deposit#new for all new deposits.
In your Deposit#create, you would then put all of your logic into the deposit.rb model file. this logic includes, going to Braintree and such.
You say you are working with the deposits you already have, in that case, they should be handled in the Deposit#edit method.
Further questions I would ask of you in this regard, are you using ActiveMerchant? If not, why not?

Resources