How to create plans if they don't exist - ruby-on-rails

I want to create subscription plans in stripe programatically, and I want to be able to run this many times so if the plans exist it should just ignore it.
I noticed if I try and retrieve a plan it throws an exception if it doesn't exist:
plan1 = Strie::Plan.retrieve("abcd123")
>>Stripe::InvalidRequestError: No such plan: abcd123
I create a plan using:
Stripe::Plan.create(.....)
I have a plans model that has all my plans, so I ideally want to do this:
Plan.all.each do |plan|
# create stripe plan here if it doesn't exist
end
What is the best way to handle this exception if the plan exists in stripe already?

Take a look at https://stripe.com/docs/api#error_handling
If you attempt to create a plan with an id that already exists, the request will fail and Stripe will throw an invalid request error. You should be able to wrap your plan creation call to account for errors. A barebones example:
require "stripe"
Stripe.api_key = "sk_test_xxxyyyzzz"
MyPlans.each do |plan|
# try to create a plan
begin
my_plan = Stripe::Plan.create(
:amount => plan.amount,
:interval => "month",
:name => plan.name,
:currency => "usd",
:id => plan.id
)
puts my_plan
# catch any invalid request errors
rescue Stripe::InvalidRequestError => e
puts e.json_body[:error]
end
end

Related

Rails - Stripe::InvalidRequestError (Must provide source or customer.)

I'm building an application (based in online resource). You can sign up or login with devise. Then, you can buy a product. Or make your own list and sell your products.
I'm integrating Stripe. When I create the Charge, I get this error in the console: Stripe::InvalidRequestError (Must provide source or customer.).
Here is the code of the orders_controller.rb for the charge action:
Stripe.api_key = ENV["STRIPE_API_KEY"]
token = params[:stripeToken]
begin
charge = Stripe::Charge.create(
:amount => (#listing.price * 100).floor,
:currency => "usd",
:card => token
)
flash[:notice] = "Thanks for ordering!"
rescue Stripe::CardError => e
flash[:danger] = e.message
end
Of course I'm taking a look in the Stripe API Documentation here: Charge documentation example and here: Charge full API Reference
I'm not sure how to handle the :resource or customer. I saw in other materials in the web that some people create a customer. In other sites it says that the :card is deprecated, so I'm a little confused.
I will leave the github repository of my project, and feel free to take a look. I'm trying to deal with Transfers and Recipients too. Project Repository
Thanks.
As mentioned in the docs, stripe expects either customer or source to be mentioned while creating a charge. So, you either need to
Create a customer on stripe(if you want to charge that customer in future too) from the token you received, and mention that customer while creating a charge,
customer = Stripe::Customer.create(source: params[:stripeToken])
charge = Stripe::Charge.create({
:amount => 400,
:currency => "usd",
:customer => customer.id,
:description => "Charge for test#example.com"
})
Or, if you don't want to create a customer, then directly mention received token as a source,
Stripe::Charge.create({
:amount => 400,
:currency => "usd",
:source => params[:stripeToken],
:description => "Charge for test#example.com"
})
For anyone going through the Stripe docs, you may have something like this (using an existing account)
account_links = Stripe::AccountLink.create({
account: 'acct_1032D82eZvKYlo2C',
refresh_url: 'https://example.com/reauth',
return_url: 'https://example.com/return',
type: 'account_onboarding',
})
if so, just change it to look like this (i.e. include the actual account.id you created in the previous step):
account_links = Stripe::AccountLink.create({
account: account.id,
refresh_url: 'https://example.com/reauth',
return_url: 'https://example.com/return',
type: 'account_onboarding',
})

Stripe charge and Subscription

I have a rails 4 app that I'm using Stripe checkout. I've followed their tutorial, and my controller looks like:
def create
s = Subscription.new
s.user_id = current_user.id
s.plan_id = params[:plan_id]
s.stripe_token = params[:stripeToken]
s.save
# Amount in cents
#amount = 699
customer = Stripe::Customer.create(
:email => current_user.email,
:card => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => #amount,
:description => 'Sitekite Pro',
:currency => 'usd'
)
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to charges_path
end
I looked at a couple other tutorials, looking for help with creating a subscription with Stripe checkout. Some of them dont have the Stripe::Charge part. Is the Stripe::Charge part only for single charges? How do I sign the user up for a monthly subscription with the same #amount?
The Stripe::Charge is indeed for single charges. The Customer create is what you need, but when you create the customer you specify a plan (plans are defined in your Stripe dashboard). The plan will specify the amount to charge and how often to charge it.
When the charge is actually made, which might be the same day or might be several days later depending on whether your plan provides, say, some free access time... the Stripe service can send the charge to a webhook... which is to say a route in your project for the dedicated use of the Stripe service.
Stripe will post charges (and failures) to your webhook, and you can handle them appropriately (logging the payments and maybe restricting the user if his card becomes expired or a regular payment fails for some other reason)

stripe payment issue ruby on rails

So I have made a stripe payment option in my app. When I click the button pay now, it shows me that the payment is successful. and when I go to my stripe account and go to stripe-test and check logs, I can see my test payment with the code 200 OK. But this payment doesn't show in stripe-test events, or in stripe-test payments. Are the payments from logs processed the next day or am I doing something wrong?
def charge
Stripe.api_key = "some_test_api_key"
customer = Stripe::Customer.retrieve(stripe_customer_id)
if stripe_customer_id.nil?
Stripe::Charge.create(
:amount => 2500,
:currency => "cad",
:customer => stripe_customer_id,
:description => "Usage charges for #{name}"
)
end
rescue Stripe::StripeError => e
logger.error "Stripe Error: " + e.message
errors.add :base, "Unable to process charge. #{e.message}."
false
end
You are only executing if the stripe_customer_id is nil. What you want is the opposite, !stripe_customer_id.nil
I don't have points to leave comments, so I have to post it like an answer ..
Payments should be processed instantly, so there must be a problem in your request.
Webhooks have no any effect on payments, its just for tracking events on your site.
Please, can you show your request's body and stripe's response? You can check it in logs.

Active Record without Rails: How to pass an Arbitrary hash to Active Record

I'm trying to pass the following Hash to Active Record to save:
[{
"id"=>"WSECOUT",
"realtime_start"=>"2013-02-10",
"realtime_end"=>"2013-02-10",
"title"=>"Reserve Bank Credit - Securities Held Outright",
"observation_start"=>"1989-03-22",
"observation_end"=>"2013-02-06",
"frequency"=>"Weekly, Ending Wednesday",
"frequency_short"=>"W",
"units"=>"Billions of Dollars",
"units_short"=>"Bil. of $",
"seasonal_adjustment"=>"Not Seasonally Adjusted",
"seasonal_adjustment_short"=>"NSA",
"last_updated"=>"2013-02-08 08:32:33-06",
"popularity"=>"42",
"notes"=>"The amount of securities held by Federal Reserve Banks. This quantity is the cumulative result of permanent open market operations: outright purchases or sales of securities, conducted by the Federal Reserve. Section 14 of the Federal Reserve Act defines the securities that the Federal Reserve is authorized to buy and sell."
}]
My ruby class looks like this:
require 'rubygems'
require 'active_record'
require 'logger'
ActiveRecord::Base.establish_connection(
:adapter => "mysql2",
:host => "localhost",
:username => "root",
:password => "*********",
:database => "fred"
)
class Series < ActiveRecord::Base
attr_accessible :id, :realtime_start, :realtime_end, :title, :observation_start,
:observation_end, :frequency, :frequency_short, :units, :units_short,
:seasonal_adjustment, :seasonal_adjustment_short, :last_updated,
:popularity, :notes
end
require_relative 'wsecout'
#series = Wsecout.new.getSeries "wsecout"
#series = #series['series']
test = Series.create(#series)
The #series variable contains the Hash. When I run this code, the object is created as is the row in mysql, however, there is no data in the fields. I know I'm missing a step here, but I am unable to figure out which step. Also, is there going to be a problem with my Hash containing an id, because Active Record creates it's own id?
Answer to your second question "map that "id" to a new field called :series_id":
#series['series'][0]['series_id'] = #series['series'][0]['id']
#series['series'][0].delete('id')
Or if you want to change multiple keys based on some criteria, then use it in the if condition as below:
#series['series'][0].keys.each do |k|
if(k == 'id')
#series['series'][0]['series_id'] = #series['series'][0][k]
#series['series'][0].delete(k)
end
end
This will iterate through each key of the hash and if the key matches to id then it add another key series_id with the same value and delete the id.

Testing association methods with Mocha

I have a Rails app with an Order and a Refund model. Order has_many :refunds. All well and good. I'm trying to write a functional test for refund logic in a controller. Here's what I have right now:
test "should not process partial paypal refund for partially refunded order when refund total plus refund amount is greater than order total" do
set_super_admin_login_credentials
o = Order.new
o.stubs({:id => 1234567, :source => "PayPal", :total => 39.95, :user => users(:dave)})
Order.stubs(:find).with(1234567).returns(o)
get :refund, {:order_id => 1234567}
assert_equal o, assigns(:order)
o.refunds.build.stubs({:amount => 1.0})
o.refunds.build.stubs({:amount => 30.00})
assert_raise do
post :refund, {:order_id => 1234567, :refund_amount => 10.00}
end
end
And in the controller, the refund method looks like this:
def refund
#order = Order.find(params[:order_id])
return if request.get?
amount = params[:refund_amount].to_f
raise "Cannot refund order for more than total" if (#order.refunds.sum(&:amount) + amount)
# Do refund stuff
end
Some notes:
I'm basing the o.refunds.build bit on Ryan Bates' Railscast. If this is not right or no longer relevant, that's helpful information.
I've seen a lot of conflicting information about how to actually do the sum method, some with the & and some without. In script/console, the & blows up but without it, I get an actual sum. In my controller, however, if I switch from &:amount to :amount, I get this message: NoMethodError: undefined method+' for :amount:Symbol`
I feel like there's some conceptual information missing rather than a bug somewhere, so I'll appreciate some pointers.
Finally figured out the issue. I was stubbing an empty association as [] rather than leaving it nil for Rails to handle on some other methods. So, when I would change one, the other would fail. Word to the wise: Enumerable#sum and ActiveRecord::Associations::AssociationCollection#sum take entirely different parameters. :)
So, by changing the stubs to leave off :refunds => [] and using a string for the field name in sum I got things back to normal. So, here's the functional version of the above code:
test "should not process partial paypal refund for partially refunded order when refund total plus refund amount is greater than order total" do
set_super_admin_login_credentials
o = Order.new
o.stubs({:id => 1234567, :source => "PayPal", :total => 39.95, :user => users(:dave)})
Order.stubs(:find).with(1234567).returns(o)
get :refund, {:order_id => 1234567}
assert_equal o, assigns(:order)
o.refunds.build.stubs({:amount => 1.0})
o.refunds.build.stubs({:amount => 30.00})
assert_raise do
post :refund, {:order_id => 1234567, :refund_amount => 10.00}
end
end
def refund
#order = Order.find(params[:order_id])
return if request.get?
amount = params[:refund_amount].to_f
raise "Cannot refund order for more than total" if (#order.refunds.sum('amount') + amount)
# Do refund stuff
end

Resources