"The token is invalid" when trying to setup Paypal recurring payments with ActiveMerchant - ruby-on-rails

I feel like a lot of the documentation on this is outdated, but this is what I have been trying so far:
I am using the ActiveMerchant::Billing::PaypalExpressGateway gateway.
First I setup the purchase and redirect the user to Paypal:
response = gateway.setup_purchase price,
return_url: <confirm url>,
cancel_return_url: <cancel url>,
items: [
{
name: 'My Item',
quantity: 1,
description: "My Item Description",
amount: price
}
]
redirect_to gateway.redirect_url_for(response.token)
This works, I can sign in as a sandboxed buyer and confirm the payment, which brings me back to <confirm url> from above. In the confirmation, I do:
response = gateway.recurring price, nil,
token: params[:token],
period: 'Year',
frequency: 1,
start_date: Time.now,
description: 'My Item Subscription'
When I do this, I receive an invalid token error from Paypal in the response variable. The token seems to be fine, it is present in the URL when I am brought back to the confirmation URL. I'm then taking it directly (params[:token]) and sending it back to Paypal.
Am I doing something completely wrong? Like I said, it seems like a lot of the documentation for this type of process is outdated (or maybe what I am trying is the stuff that is outdated...)

After looking through the source code for ActiveMerchant's Paypal express checkout gateway, I came to the conclusion that it's simply outdated when dealing with recurring payments. I switched to the paypal-recurring gem instead and everything worked fine.

Related

Stripe success_url format in a rails app not creating correct URL

I have an app that uses Stripe Checkout and creates a Stripe session and then redirects to checkout.
In my controller, this code works fine:
session = Stripe::Checkout::Session.create(
payment_method_types: ['card'],
subscription_data: {
items: [{ plan: stripe_plan }],
},
customer: stripe_customer_id,
customer_email: stripe_customer_email,
client_reference_id: current_user.id,
success_url: "http://localhost:3000/welcome_new_subscriber?session_id={CHECKOUT_SESSION_ID}",
cancel_url: "http://localhost:3000/charges/new?stripe_plan=" + stripe_plan,
)
And correctly redirects to the URL:
http://localhost:3000/welcome_new_subscriber?session_id=cs_test_abcd1234
When I change the success_url line to the following (as advised on a few websites) it does not work:
success_url: welcome_new_subscriber_url(:session_id => '{CHECKOUT_SESSION_ID}'),
The URL resolves to:
http://localhost:3000/welcome_new_subscriber?session_id=%7BCHECKOUT_SESSION_ID%7D
It seems the {CHECKOUT_SESSION_ID} is not resolving correctly.
Any idea what I am doing incorrectly - I've tried every syntax change I can think of?
When you use
welcome_new_subscriber_url(:session_id => '{CHECKOUT_SESSION_ID}')
Rails is trying to be helpful by URI-escaping { and }. However the Stripe gem using these as special characters to know where to replace template variables.
So you could just use
welcome_new_subscriber_url + "?session_id={CHECKOUT_SESSION_ID}"
Not the most elegant thing, but then again Stripe's system here is kinda wierd (why don't they let you just pass CHECKOUT_SESSION_ID yourself?), so we gotta make do

Braintree Error In Production Mode

I have implemented Braintree subscription payment in rails app. Everything works fine in development, however when I switched to production (I have registered with Braintree and got a real account, and I change all the key in environment)
I have tried to submit an invalid card information to test the app, the page keeps showing error.
I look at the application logs and it said
NoMethodError (undefined method `customer' for #<Braintree::ErrorResult:0x007f6ed80f1d80>):
Here's my create method, I follow your tutorial and it works fine in development
def create
if current_user.braintree_id?
customer = Braintree::Customer.find(current_user.braintree_id)
else
result = Braintree::Customer.create(
email: current_user.company_email,
company: current_user.company_name,
payment_method_nonce: params[:payment_method_nonce]
)
customer = result.customer
current_user.update(braintree_id: customer.id)
end
result = Braintree::Subscription.create(
payment_method_token: customer.payment_methods.find{ |pm| pm.default? }.token,
plan_id: params[:plan_id]
)
if result.success?
result.subscription.transactions.each do |transaction|
current_user.transactions.create(braintree_transaction_id: transaction.id,
plan_name: params[:plan_name],
price: transaction.amount.to_f,
start_date: transaction.subscription_details.billing_period_start_date,
end_date: transaction.subscription_details.billing_period_end_date,
subscription_id: result.subscription.id
)
end
current_user.update(braintree_subscription_id: result.subscription.id,
next_billing_date: result.subscription.next_billing_date,
billing_period_start_date: result.subscription.billing_period_start_date,
billing_period_end_date: result.subscription.billing_period_end_date,
status: result.subscription.status,
next_billing_period_amount: result.subscription.next_billing_period_amount,
paid_through_date: result.subscription.paid_through_date,
plan_id: params[:plan_id],
plan_name: params[:plan_name])
flash[:info] = "You've been subscribed successfully"
redirect_to #current_user
else
flash[:warning] = "Invalid card information"
render 'new'
end
end
The weird thing is it doesn't render the flash warning of unsuccessful result and redirect to the original new_subscription_path, instead the website url redirect to this
https://herokuappname.herokuapp.com/subscription.1
and the page error shows
This page isn’t working herokuappname.herokuapp.com is currently unable to handle this request.
HTTP ERROR 500
So, I want to know whether it is the customer method error (which I don't think so because it doesn't have any problem in development mode) or any other problem such as why the page url so weird?
I looked at the Braintree control panel, and the reason that the subscription failed was because the bank declined the transactions due to incorrect card information, which I entered incorrect card in order to test it, if it is invalid card info, why didn't it display the flash notice and redirect back to the new_subscription_path, instead it redirects to the subscription.1 url which I have mentioned above?
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
I'm not sure if you used the same invalid card number for testing in production as in sandbox, but I'll try to answer your questions with the information we have on hand:
NoMethodError (undefined method `customer' for #):
By attempting to create a customer with a payment method with an invalid card, the result of that API call was an ErrorResult object. ErrorResult objects are either a validation error, processor decline, gateway rejection, or other exception messages, and do not contain a customer method. Hence, the undefined method error.
You should add some error handling around all of your Braintree API calls so that you can address any errors throughout the subscription process.

Active model OTP not generating new secret key after 30 seconds sleep

I am trying implement active_model_otp on a sample rails application.
My user model has name and email columns. After following the necessary steps from the documentation I first created a user as follows on rails console:
User.create(name: "Abc", email: "example#email.com")
This created a record as follows:
<User id: 1, name: "Abc", email: "example#email.com", created_at: "2017-04-28 07:12:25", updated_at: "2017-04-28 07:12:25", otp_secret_key: "lol6rrtqppy46xfs">
Then I assigned:
user = User.last and
user.otp_secret_key gave the otp that was generated which is
=>"lol6rrtqppy46xfs"
Then I ran
sleep(2)
According to given documentation it supposed to generate a new otp after 2 seconds. But when I gave: user.otp_secret_key again in the console after 2 seconds it is returning the same old otp.
=>"lol6rrtqppy46xfs"
What am I missing ?
Twilio developer evangelist here.
The otp_secret_key is the string that is used to generate the actual OTP code that you send to the user. It is the secret that is shared to the user (via the QR code) and so it needs to match on both the user's auth app as well as your server.
The generated OTP should change every 30 seconds. As far as I can see it uses the default interval of the ROTP gem, which is 30 seconds.
The method to get the OTP is otp_code. So to check it's working, try:
user = User.last
puts user.otp_code
sleep(30)
puts user.otp_code
Let me know if that helps at all.

'No such token' error upon submitting payment request to Stripe

I'm setting up payments using the Stripe API to allow a user to log into their Stripe account on an iPad and accept payments from anyone. To do this, I'm using Stripe Connect to log them in and save their account id, then I'm using the STPPaymentCardTextField to obtain credit card details, then using the Stripe iOS SDK I'm submitting a card (with the test card info - 4242...) and getting back a token via createTokenWithCard. This successfully returns a token. At this point I need to submit that token along with the destination account id (provided to the app after the user logged in) and other info (currency, amount, etc) to my own server to submit the payment to Stripe. I have verified that information is being submitted and forwarded onto Stripe, but Stripe is returning an error:
{ type: 'invalid_request_error',
app[web.1]: message: 'No such token: tok_13vxes2eZkKYli2C9bHY1YfX',
app[web.1]: param: 'source',
app[web.1]: statusCode: 400,
app[web.1]: requestId: 'req_7AIT8cEasnzEaq' },
app[web.1]: requestId: 'req_7AIT8cEasnzEaq',
app[web.1]: statusCode: 400 }
If we submit the credit card info directly, avoiding the token altogether, the payment succeeds. Something is wrong with this token, and we are not sure why it is failing. What could be going wrong here?
[[STPAPIClient sharedClient] createTokenWithCard:card completion:^(STPToken *token, NSError *error) {
//submit tokenId and other info to 'charge' endpoint below
}
NodeJS:
app.post('/charge', (req, res, next) => {
stripe.charges.create({
amount: req.body.amount,
currency: req.body.currency,
source: req.body.token,
description: req.body.description,
destination: req.body.destination
}, (err, charge) => {
if (err) return next(err)
res.json(charge)
})
})
Are you sure you're using the same API keys on your server and client?
Your server should be using your (live/test) secret key, and your iOS app should be using your (live/ test) publishable key as mentioned here on Stripe Testing.
I had been facing same issue for my test environment and the mistake i had been doing, i was adding the token received by Stripe like this one source: 'tok_18nnwSJ6tVEvTdcVs3dNIhGs' , but for the test environment we have to use source: 'tok_visa'.
Here is the list of test sources provided by Stripe. https://stripe.com/docs/testing#cards
It created customer for me, let me know if it helped anyone else as well.
The accepted answer does not work for me. I am using correct key for client and server, but still the issue is still there. I am sending source from iOS to the server as well, based on stripe example RocketRides, it is sending source ID of the credit card, which is "card_xxx", and that is not gonna work. You will have to add "customer" attribute for the call on your server side.
For example: (python)
stripe.Charge.create(amount=1000, currency='usd', source="card_xxxxx", **customer**='cus_xxxx', application_fee=600,destination={'account': 'acct_xxxx'})
Neither of the answers here worked for me.
I was trying to use Stripe's PHP library to charge a card that I already had on file like this...
$charge = \Stripe\Charge::create([
'amount' => 1000,
'currency' => 'gbp',
'card' => 'card_xxx',
'description' => 'Payment for Sam',
]);
And I was receiving the no such token error above.
To get it to work, I also had to provide the customer id like so...
$charge = \Stripe\Charge::create([
'amount' => 1000,
'currency' => 'gbp',
'customer' => 'cus_xxx',
'card' => 'card_xxx',
'description' => 'Payment for Sam',
]);
First check api keys wheather they are the same at front end and backend.
If you are using testing api keys then you have to pass source: 'tok_visa' instead of your card source token source: 'tok_kb3kb23k2bk32bk3b2'.

Integration tests create test users on Stripe, how to stop or stub out

I'm using stripe on a project. I'm using Railscasts #288 (http://railscasts.com/episodes/288-billing-with-stripe) as a guide. I have it so that once a user registers with a valid username and password I will create their Stripe customer account.
After a few runs of my integration test I can see that I have many users created in my test account for Stripe. How do I structure the integration test so that it goes through my registration process as a typical user would, but without creating the Stripe account with Stripe?
I'm coming a little late to the game, but check out StripeMock. It is made specifically for this purpose.
StripeMock.start
Stripe::Customer.create({
id: '123',
email: 'someone#something.com',
card: 'void_card_token',
subscriptions: {
data: [{
plan: {
name: 'Some Subscription Plan',
currency: 'usd',
amount: 1000
},
start: 1410408211,
status: 'active',
current_period_start: 1410408211,
current_period_end: 1413000211
}]
}
})
test... test... test...
StripeMock.stop
i dealt with that by making all my customers created through the testing have "deletable" in their email address, and adding these lines to my spec_helper.
config.after(:suite) do
custs = Stripe::Customer.all(limit: 100).data
custs.keep_if { |c| c.email.match( /deletable/ ) }
custs.each { |c| c.delete }
end
This is typically done with a tool like WebMock which intercepts the HTTP request and returns a response you provide. The VCR gem makes this process easier by recording and replaying HTTP requests using WebMock (or optionally FakeWeb) under the hood. There is a Railscast on VCR, but it is a bit out of date. Take care not to record any sensitive data (i.e. api keys) by using the filter_sensitive_data configuration option.
It's difficult to really test an integration without making your tests as realistic as possible. Therefore, I suggest that you let stripe create the test customer accounts, but make use of the webhooks to automatically delete them.
Specifically, you would handle the customer.created event. If event->livemode == false, send a request back to the api to delete the customer.
This way, you run through the entire process as you test, while only keeping customers that were created in live mode.

Resources